]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/window.cpp
wxX11:
[wxWidgets.git] / src / gtk1 / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #ifdef __GNUG__
12 #pragma implementation "window.h"
13 #endif
14
15 #ifdef __VMS
16 #define XWarpPointer XWARPPOINTER
17 #endif
18
19 #include "wx/defs.h"
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
22 #include "wx/frame.h"
23 #include "wx/app.h"
24 #include "wx/layout.h"
25 #include "wx/utils.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28
29 #if wxUSE_DRAG_AND_DROP
30 #include "wx/dnd.h"
31 #endif
32
33 #if wxUSE_TOOLTIPS
34 #include "wx/tooltip.h"
35 #endif
36
37 #if wxUSE_CARET
38 #include "wx/caret.h"
39 #endif // wxUSE_CARET
40
41 #if wxUSE_TEXTCTRL
42 #include "wx/textctrl.h"
43 #endif
44
45 #include "wx/menu.h"
46 #include "wx/statusbr.h"
47 #include "wx/intl.h"
48 #include "wx/settings.h"
49 #include "wx/log.h"
50
51 #ifdef __WXDEBUG__
52 #include "wx/thread.h"
53 #endif
54
55 #include <math.h>
56
57 #include <gdk/gdk.h>
58 #include <gtk/gtk.h>
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
61 #include <gdk/gdkx.h>
62
63 #include <gtk/gtk.h>
64 #include <gtk/gtkprivate.h>
65
66 #include "wx/gtk/win_gtk.h"
67
68 //-----------------------------------------------------------------------------
69 // documentation on internals
70 //-----------------------------------------------------------------------------
71
72 /*
73 I have been asked several times about writing some documentation about
74 the GTK port of wxWindows, especially its internal structures. Obviously,
75 you cannot understand wxGTK without knowing a little about the GTK, but
76 some more information about what the wxWindow, which is the base class
77 for all other window classes, does seems required as well.
78
79 I)
80
81 What does wxWindow do? It contains the common interface for the following
82 jobs of its descendants:
83
84 1) Define the rudimentary behaviour common to all window classes, such as
85 resizing, intercepting user input (so as to make it possible to use these
86 events for special purposes in a derived class), window names etc.
87
88 2) Provide the possibility to contain and manage children, if the derived
89 class is allowed to contain children, which holds true for those window
90 classes which do not display a native GTK widget. To name them, these
91 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
92 work classes are a special case and are handled a bit differently from
93 the rest. The same holds true for the wxNotebook class.
94
95 3) Provide the possibility to draw into a client area of a window. This,
96 too, only holds true for classes that do not display a native GTK widget
97 as above.
98
99 4) Provide the entire mechanism for scrolling widgets. This actual inter-
100 face for this is usually in wxScrolledWindow, but the GTK implementation
101 is in this class.
102
103 5) A multitude of helper or extra methods for special purposes, such as
104 Drag'n'Drop, managing validators etc.
105
106 6) Display a border (sunken, raised, simple or none).
107
108 Normally one might expect, that one wxWindows window would always correspond
109 to one GTK widget. Under GTK, there is no such allround widget that has all
110 the functionality. Moreover, the GTK defines a client area as a different
111 widget from the actual widget you are handling. Last but not least some
112 special classes (e.g. wxFrame) handle different categories of widgets and
113 still have the possibility to draw something in the client area.
114 It was therefore required to write a special purpose GTK widget, that would
115 represent a client area in the sense of wxWindows capable to do the jobs
116 2), 3) and 4). I have written this class and it resides in win_gtk.c of
117 this directory.
118
119 All windows must have a widget, with which they interact with other under-
120 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
121 thw wxWindow class has a member variable called m_widget which holds a
122 pointer to this widget. When the window class represents a GTK native widget,
123 this is (in most cases) the only GTK widget the class manages. E.g. the
124 wxStatitText class handles only a GtkLabel widget a pointer to which you
125 can find in m_widget (defined in wxWindow)
126
127 When the class has a client area for drawing into and for containing children
128 it has to handle the client area widget (of the type GtkPizza, defined in
129 win_gtk.c), but there could be any number of widgets, handled by a class
130 The common rule for all windows is only, that the widget that interacts with
131 the rest of GTK must be referenced in m_widget and all other widgets must be
132 children of this widget on the GTK level. The top-most widget, which also
133 represents the client area, must be in the m_wxwindow field and must be of
134 the type GtkPizza.
135
136 As I said, the window classes that display a GTK native widget only have
137 one widget, so in the case of e.g. the wxButton class m_widget holds a
138 pointer to a GtkButton widget. But windows with client areas (for drawing
139 and children) have a m_widget field that is a pointer to a GtkScrolled-
140 Window and a m_wxwindow field that is pointer to a GtkPizza and this
141 one is (in the GTK sense) a child of the GtkScrolledWindow.
142
143 If the m_wxwindow field is set, then all input to this widget is inter-
144 cepted and sent to the wxWindows class. If not, all input to the widget
145 that gets pointed to by m_widget gets intercepted and sent to the class.
146
147 II)
148
149 The design of scrolling in wxWindows is markedly different from that offered
150 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
151 clicking on a scrollbar belonging to scrolled window will inevitably move
152 the window. In wxWindows, the scrollbar will only emit an event, send this
153 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
154 which actually moves the window and its subchildren. Note that GtkPizza
155 memorizes how much it has been scrolled but that wxWindows forgets this
156 so that the two coordinates systems have to be kept in synch. This is done
157 in various places using the pizza->xoffset and pizza->yoffset values.
158
159 III)
160
161 Singularily the most broken code in GTK is the code that is supposes to
162 inform subwindows (child windows) about new positions. Very often, duplicate
163 events are sent without changes in size or position, equally often no
164 events are sent at all (All this is due to a bug in the GtkContainer code
165 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
166 GTK's own system and it simply waits for size events for toplevel windows
167 and then iterates down the respective size events to all window. This has
168 the disadvantage, that windows might get size events before the GTK widget
169 actually has the reported size. This doesn't normally pose any problem, but
170 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
171 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
172 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
173 window that is used for OpenGl output really has that size (as reported by
174 GTK).
175
176 IV)
177
178 If someone at some point of time feels the immense desire to have a look at,
179 change or attempt to optimse the Refresh() logic, this person will need an
180 intimate understanding of what a "draw" and what an "expose" events are and
181 what there are used for, in particular when used in connection with GTK's
182 own windowless widgets. Beware.
183
184 V)
185
186 Cursors, too, have been a constant source of pleasure. The main difficulty
187 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
188 for the parent. To prevent this from doing too much harm, I use idle time
189 to set the cursor over and over again, starting from the toplevel windows
190 and ending with the youngest generation (speaking of parent and child windows).
191 Also don't forget that cursors (like much else) are connected to GdkWindows,
192 not GtkWidgets and that the "window" field of a GtkWidget might very well
193 point to the GdkWindow of the parent widget (-> "window less widget") and
194 that the two obviously have very different meanings.
195
196 */
197
198 //-----------------------------------------------------------------------------
199 // data
200 //-----------------------------------------------------------------------------
201
202 extern wxList wxPendingDelete;
203 extern bool g_blockEventsOnDrag;
204 extern bool g_blockEventsOnScroll;
205 extern wxCursor g_globalCursor;
206
207 // mouse capture state: the window which has it and if the mouse is currently
208 // inside it
209 static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
210 static bool g_captureWindowHasMouse = FALSE;
211
212 /* extern */ wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL;
213
214 // the last window which had the focus - this is normally never NULL (except
215 // if we never had focus at all) as even when g_focusWindow is NULL it still
216 // keeps its previous value
217 static wxWindowGTK *g_focusWindowLast = (wxWindowGTK *)NULL;
218
219 // the frame that is currently active (i.e. its child has focus). It is
220 // used to generate wxActivateEvents
221 static wxWindowGTK *g_activeFrame = (wxWindowGTK *)NULL;
222 static bool g_activeFrameLostFocus = FALSE;
223
224 // if we detect that the app has got/lost the focus, we set this variable to
225 // either TRUE or FALSE and an activate event will be sent during the next
226 // OnIdle() call and it is reset to -1: this value means that we shouldn't
227 // send any activate events at all
228 static int g_sendActivateEvent = -1;
229
230 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
231 the last click here */
232 static guint32 gs_timeLastClick = 0;
233
234 extern bool g_mainThreadLocked;
235
236 //-----------------------------------------------------------------------------
237 // debug
238 //-----------------------------------------------------------------------------
239
240 #ifndef __WXGTK20__
241 #define DISABLE_STYLE_IF_BROKEN_THEME 1
242 #endif
243
244 #ifdef __WXDEBUG__
245
246 #if wxUSE_THREADS
247 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
248 #else
249 # define DEBUG_MAIN_THREAD
250 #endif
251
252 static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
253 GdkEvent *WXUNUSED(event),
254 const wxChar *WXUNUSED(name) )
255 {
256 /*
257 static bool s_done = FALSE;
258 if ( !s_done )
259 {
260 wxLog::AddTraceMask("focus");
261 s_done = TRUE;
262 }
263 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
264 */
265
266 return FALSE;
267 }
268
269 void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
270 {
271 // suppress warnings about gtk_debug_focus_in_callback being unused with
272 // this "if ( 0 )"
273 if ( 0 )
274 {
275 wxString tmp = name;
276 tmp += wxT(" FROM ");
277 tmp += window;
278
279 wxChar *s = new wxChar[tmp.Length()+1];
280
281 wxStrcpy( s, tmp );
282
283 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
284 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
285 }
286 }
287
288 #else
289 #define DEBUG_MAIN_THREAD
290 #endif // Debug
291
292 //-----------------------------------------------------------------------------
293 // missing gdk functions
294 //-----------------------------------------------------------------------------
295
296 void
297 gdk_window_warp_pointer (GdkWindow *window,
298 gint x,
299 gint y)
300 {
301 #ifndef __WXGTK20__
302 GdkWindowPrivate *priv;
303 #endif
304
305 if (!window)
306 window = GDK_ROOT_PARENT();
307
308 #ifdef __WXGTK20__
309 if (!GDK_WINDOW_DESTROYED(window))
310 {
311 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
312 None, /* not source window -> move from anywhere */
313 GDK_WINDOW_XID(window), /* dest window */
314 0, 0, 0, 0, /* not source window -> move from anywhere */
315 x, y );
316 }
317 #else
318 priv = (GdkWindowPrivate*) window;
319
320 if (!priv->destroyed)
321 {
322 XWarpPointer (priv->xdisplay,
323 None, /* not source window -> move from anywhere */
324 priv->xwindow, /* dest window */
325 0, 0, 0, 0, /* not source window -> move from anywhere */
326 x, y );
327 }
328 #endif
329 }
330
331 //-----------------------------------------------------------------------------
332 // idle system
333 //-----------------------------------------------------------------------------
334
335 extern void wxapp_install_idle_handler();
336 extern bool g_isIdle;
337
338 //-----------------------------------------------------------------------------
339 // local code (see below)
340 //-----------------------------------------------------------------------------
341
342 // returns the child of win which currently has focus or NULL if not found
343 //
344 // Note: can't be static, needed by textctrl.cpp.
345 wxWindow *wxFindFocusedChild(wxWindowGTK *win)
346 {
347 wxWindow *winFocus = wxWindowGTK::FindFocus();
348 if ( !winFocus )
349 return (wxWindow *)NULL;
350
351 if ( winFocus == win )
352 return (wxWindow *)win;
353
354 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
355 node;
356 node = node->GetNext() )
357 {
358 wxWindow *child = wxFindFocusedChild(node->GetData());
359 if ( child )
360 return child;
361 }
362
363 return (wxWindow *)NULL;
364 }
365
366 // Returns toplevel grandparent of given window:
367 static wxWindowGTK* wxGetTopLevelParent(wxWindowGTK *win)
368 {
369 wxWindowGTK *p = win;
370 while (p && !p->IsTopLevel())
371 p = p->GetParent();
372 return p;
373 }
374
375
376 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
377 {
378 // wxUniversal widgets draw the borders and scrollbars themselves
379 #ifndef __WXUNIVERSAL__
380 if (!win->m_hasVMT)
381 return;
382
383 int dw = 0;
384 int dh = 0;
385
386 if (win->m_hasScrolling)
387 {
388 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
389
390 GtkRequisition vscroll_req;
391 vscroll_req.width = 2;
392 vscroll_req.height = 2;
393 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
394 (scroll_window->vscrollbar, &vscroll_req );
395
396 GtkRequisition hscroll_req;
397 hscroll_req.width = 2;
398 hscroll_req.height = 2;
399 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
400 (scroll_window->hscrollbar, &hscroll_req );
401
402 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
403
404 if (scroll_window->vscrollbar_visible)
405 {
406 dw += vscroll_req.width;
407 dw += scroll_class->scrollbar_spacing;
408 }
409
410 if (scroll_window->hscrollbar_visible)
411 {
412 dh += hscroll_req.height;
413 dh += scroll_class->scrollbar_spacing;
414 }
415 }
416
417 int dx = 0;
418 int dy = 0;
419 if (GTK_WIDGET_NO_WINDOW (widget))
420 {
421 dx += widget->allocation.x;
422 dy += widget->allocation.y;
423 }
424
425 if (win->HasFlag(wxRAISED_BORDER))
426 {
427 gtk_draw_shadow( widget->style,
428 widget->window,
429 GTK_STATE_NORMAL,
430 GTK_SHADOW_OUT,
431 dx, dy,
432 widget->allocation.width-dw, widget->allocation.height-dh );
433 return;
434 }
435
436 if (win->HasFlag(wxSUNKEN_BORDER))
437 {
438 gtk_draw_shadow( widget->style,
439 widget->window,
440 GTK_STATE_NORMAL,
441 GTK_SHADOW_IN,
442 dx, dy,
443 widget->allocation.width-dw, widget->allocation.height-dh );
444 return;
445 }
446
447 if (win->HasFlag(wxSIMPLE_BORDER))
448 {
449 GdkGC *gc;
450 gc = gdk_gc_new( widget->window );
451 gdk_gc_set_foreground( gc, &widget->style->black );
452 gdk_draw_rectangle( widget->window, gc, FALSE,
453 dx, dy,
454 widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
455 gdk_gc_unref( gc );
456 return;
457 }
458 #endif // __WXUNIVERSAL__
459 }
460
461 //-----------------------------------------------------------------------------
462 // "expose_event" of m_widget
463 //-----------------------------------------------------------------------------
464
465 gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
466 {
467 if (gdk_event->count > 0) return FALSE;
468
469 draw_frame( widget, win );
470
471 return TRUE;
472 }
473
474 //-----------------------------------------------------------------------------
475 // "draw" of m_widget
476 //-----------------------------------------------------------------------------
477
478 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
479 {
480 draw_frame( widget, win );
481 }
482
483 //-----------------------------------------------------------------------------
484 // key code mapping routines
485 //-----------------------------------------------------------------------------
486
487 static long map_to_unmodified_wx_keysym( GdkEventKey *event )
488 {
489 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
490 // but only event->keyval which is quite useless to us, so remember
491 // the last character from GDK_KEY_PRESS and resue it as last resort
492 //
493 // NB: should be MT-neutral as always called from main thread only
494 static struct
495 {
496 KeySym keysym;
497 long keycode;
498 } s_lastKeyPress = { 0, 0 };
499
500 KeySym keysym = event->keyval;
501 long key_code;
502
503 switch ( keysym )
504 {
505 case GDK_Shift_L:
506 case GDK_Shift_R: key_code = WXK_SHIFT; break;
507 case GDK_Control_L:
508 case GDK_Control_R: key_code = WXK_CONTROL; break;
509 case GDK_Meta_L:
510 case GDK_Meta_R:
511 case GDK_Alt_L:
512 case GDK_Alt_R:
513 case GDK_Super_L:
514 case GDK_Super_R: key_code = WXK_ALT; break;
515 case GDK_Menu: key_code = WXK_MENU; break;
516 case GDK_Help: key_code = WXK_HELP; break;
517 case GDK_BackSpace: key_code = WXK_BACK; break;
518 case GDK_ISO_Left_Tab:
519 case GDK_Tab: key_code = WXK_TAB; break;
520 case GDK_Linefeed: key_code = WXK_RETURN; break;
521 case GDK_Clear: key_code = WXK_CLEAR; break;
522 case GDK_Return: key_code = WXK_RETURN; break;
523 case GDK_Pause: key_code = WXK_PAUSE; break;
524 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
525 case GDK_Escape: key_code = WXK_ESCAPE; break;
526 case GDK_Delete: key_code = WXK_DELETE; break;
527 case GDK_Home: key_code = WXK_HOME; break;
528 case GDK_Left: key_code = WXK_LEFT; break;
529 case GDK_Up: key_code = WXK_UP; break;
530 case GDK_Right: key_code = WXK_RIGHT; break;
531 case GDK_Down: key_code = WXK_DOWN; break;
532 case GDK_Prior: key_code = WXK_PRIOR; break;
533 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
534 case GDK_Next: key_code = WXK_NEXT; break;
535 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
536 case GDK_End: key_code = WXK_END; break;
537 case GDK_Begin: key_code = WXK_HOME; break;
538 case GDK_Select: key_code = WXK_SELECT; break;
539 case GDK_Print: key_code = WXK_PRINT; break;
540 case GDK_Execute: key_code = WXK_EXECUTE; break;
541 case GDK_Insert: key_code = WXK_INSERT; break;
542 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
543
544 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
545 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
546 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
547 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
548 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
549 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
550 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
551 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
552 case GDK_KP_8: key_code = WXK_NUMPAD8; break;
553 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
554 case GDK_KP_Space: key_code = WXK_NUMPAD_SPACE; break;
555 case GDK_KP_Tab: key_code = WXK_NUMPAD_TAB; break;
556 case GDK_KP_Enter: key_code = WXK_NUMPAD_ENTER; break;
557 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
558 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
559 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
560 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
561 case GDK_KP_Home: key_code = WXK_NUMPAD_HOME; break;
562 case GDK_KP_Left: key_code = WXK_NUMPAD_LEFT; break;
563 case GDK_KP_Up: key_code = WXK_NUMPAD_UP; break;
564 case GDK_KP_Right: key_code = WXK_NUMPAD_RIGHT; break;
565 case GDK_KP_Down: key_code = WXK_NUMPAD_DOWN; break;
566 case GDK_KP_Prior: key_code = WXK_NUMPAD_PRIOR; break;
567 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
568 case GDK_KP_Next: key_code = WXK_NUMPAD_NEXT; break;
569 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
570 case GDK_KP_End: key_code = WXK_NUMPAD_END; break;
571 case GDK_KP_Begin: key_code = WXK_NUMPAD_BEGIN; break;
572 case GDK_KP_Insert: key_code = WXK_NUMPAD_INSERT; break;
573 case GDK_KP_Delete: key_code = WXK_NUMPAD_DELETE; break;
574 case GDK_KP_Equal: key_code = WXK_NUMPAD_EQUAL; break;
575 case GDK_KP_Multiply: key_code = WXK_NUMPAD_MULTIPLY; break;
576 case GDK_KP_Add: key_code = WXK_NUMPAD_ADD; break;
577 case GDK_KP_Separator: key_code = WXK_NUMPAD_SEPARATOR; break;
578 case GDK_KP_Subtract: key_code = WXK_NUMPAD_SUBTRACT; break;
579 case GDK_KP_Decimal: key_code = WXK_NUMPAD_DECIMAL; break;
580 case GDK_KP_Divide: key_code = WXK_NUMPAD_DIVIDE; break;
581
582 case GDK_F1: key_code = WXK_F1; break;
583 case GDK_F2: key_code = WXK_F2; break;
584 case GDK_F3: key_code = WXK_F3; break;
585 case GDK_F4: key_code = WXK_F4; break;
586 case GDK_F5: key_code = WXK_F5; break;
587 case GDK_F6: key_code = WXK_F6; break;
588 case GDK_F7: key_code = WXK_F7; break;
589 case GDK_F8: key_code = WXK_F8; break;
590 case GDK_F9: key_code = WXK_F9; break;
591 case GDK_F10: key_code = WXK_F10; break;
592 case GDK_F11: key_code = WXK_F11; break;
593 case GDK_F12: key_code = WXK_F12; break;
594 default:
595 {
596 // do we have the translation?
597 if ( event->length == 1 )
598 {
599 keysym = (KeySym)event->string[0];
600 }
601 else if ( (keysym & 0xFF) != keysym )
602 {
603 // non ASCII key, what to do?
604
605 if ( event->type == GDK_KEY_RELEASE )
606 {
607 // reuse the one from the last keypress if any
608 if ( keysym == s_lastKeyPress.keysym )
609 {
610 key_code = s_lastKeyPress.keycode;
611
612 // skip "return 0"
613 break;
614 }
615 }
616
617 // ignore this one, we don't know it
618 return 0;
619 }
620 //else: ASCII key, ok
621
622 guint upper = gdk_keyval_to_upper( (guint)keysym );
623 key_code = upper ? upper : keysym;
624
625 if ( event->type == GDK_KEY_PRESS )
626 {
627 // remember it to be reused below later
628 s_lastKeyPress.keysym = keysym;
629 s_lastKeyPress.keycode = key_code;
630 }
631 }
632 }
633
634 return key_code;
635 }
636
637 static long map_to_wx_keysym( GdkEventKey *event )
638 {
639 KeySym keysym = event->keyval;
640 guint key_code = 0;
641
642 switch (keysym)
643 {
644 case GDK_Menu: key_code = WXK_MENU; break;
645 case GDK_Help: key_code = WXK_HELP; break;
646 case GDK_BackSpace: key_code = WXK_BACK; break;
647 case GDK_ISO_Left_Tab:
648 case GDK_Tab: key_code = WXK_TAB; break;
649 case GDK_Linefeed: key_code = WXK_RETURN; break;
650 case GDK_Clear: key_code = WXK_CLEAR; break;
651 case GDK_Return: key_code = WXK_RETURN; break;
652 case GDK_Pause: key_code = WXK_PAUSE; break;
653 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
654 case GDK_Escape: key_code = WXK_ESCAPE; break;
655 case GDK_Delete: key_code = WXK_DELETE; break;
656 case GDK_Home: key_code = WXK_HOME; break;
657 case GDK_Left: key_code = WXK_LEFT; break;
658 case GDK_Up: key_code = WXK_UP; break;
659 case GDK_Right: key_code = WXK_RIGHT; break;
660 case GDK_Down: key_code = WXK_DOWN; break;
661 case GDK_Prior: key_code = WXK_PRIOR; break;
662 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
663 case GDK_Next: key_code = WXK_NEXT; break;
664 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
665 case GDK_End: key_code = WXK_END; break;
666 case GDK_Begin: key_code = WXK_HOME; break;
667 case GDK_Select: key_code = WXK_SELECT; break;
668 case GDK_Print: key_code = WXK_PRINT; break;
669 case GDK_Execute: key_code = WXK_EXECUTE; break;
670 case GDK_Insert: key_code = WXK_INSERT; break;
671 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
672
673 case GDK_KP_0: key_code = '0'; break;
674 case GDK_KP_1: key_code = '1'; break;
675 case GDK_KP_2: key_code = '2'; break;
676 case GDK_KP_3: key_code = '3'; break;
677 case GDK_KP_4: key_code = '4'; break;
678 case GDK_KP_5: key_code = '5'; break;
679 case GDK_KP_6: key_code = '6'; break;
680 case GDK_KP_7: key_code = '7'; break;
681 case GDK_KP_8: key_code = '8'; break;
682 case GDK_KP_9: key_code = '9'; break;
683 case GDK_KP_Space: key_code = ' '; break;
684 case GDK_KP_Tab: key_code = WXK_TAB; break; /* or '\t' ??? */
685 case GDK_KP_Enter: key_code = WXK_RETURN; break; /* or '\r' ??? */
686 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
687 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
688 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
689 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
690 case GDK_KP_Home: key_code = WXK_HOME; break;
691 case GDK_KP_Left: key_code = WXK_LEFT; break;
692 case GDK_KP_Up: key_code = WXK_UP; break;
693 case GDK_KP_Right: key_code = WXK_RIGHT; break;
694 case GDK_KP_Down: key_code = WXK_DOWN; break;
695 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
696 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
697 case GDK_KP_Next: key_code = WXK_NEXT; break;
698 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
699 case GDK_KP_End: key_code = WXK_END; break;
700 case GDK_KP_Begin: key_code = WXK_HOME; break;
701 case GDK_KP_Insert: key_code = WXK_INSERT; break;
702 case GDK_KP_Delete: key_code = WXK_DELETE; break;
703 case GDK_KP_Equal: key_code = '='; break;
704 case GDK_KP_Multiply: key_code = '*'; break;
705 case GDK_KP_Add: key_code = '+'; break;
706 case GDK_KP_Separator: key_code = ','; break;
707 case GDK_KP_Subtract: key_code = '-'; break;
708 case GDK_KP_Decimal: key_code = '.'; break;
709 case GDK_KP_Divide: key_code = '/'; break;
710
711 case GDK_F1: key_code = WXK_F1; break;
712 case GDK_F2: key_code = WXK_F2; break;
713 case GDK_F3: key_code = WXK_F3; break;
714 case GDK_F4: key_code = WXK_F4; break;
715 case GDK_F5: key_code = WXK_F5; break;
716 case GDK_F6: key_code = WXK_F6; break;
717 case GDK_F7: key_code = WXK_F7; break;
718 case GDK_F8: key_code = WXK_F8; break;
719 case GDK_F9: key_code = WXK_F9; break;
720 case GDK_F10: key_code = WXK_F10; break;
721 case GDK_F11: key_code = WXK_F11; break;
722 case GDK_F12: key_code = WXK_F12; break;
723 default:
724 if (event->length == 1)
725 {
726 key_code = (unsigned char)*event->string;
727 }
728 else if ((keysym & 0xFF) == keysym)
729 {
730 key_code = (guint)keysym;
731 }
732 }
733
734 return key_code;
735 }
736
737 //-----------------------------------------------------------------------------
738 // "size_request" of m_widget
739 //-----------------------------------------------------------------------------
740
741 static void gtk_window_size_request_callback( GtkWidget *widget, GtkRequisition *requisition, wxWindow *win )
742 {
743 int w,h;
744 win->GetSize( &w, &h );
745 if (w < 2) w = 2;
746 if (h < 2) h = 2;
747
748 requisition->height = h;
749 requisition->width = w;
750 }
751
752 //-----------------------------------------------------------------------------
753 // "expose_event" of m_wxwindow
754 //-----------------------------------------------------------------------------
755
756 static int gtk_window_expose_callback( GtkWidget *widget,
757 GdkEventExpose *gdk_event,
758 wxWindow *win )
759 {
760 DEBUG_MAIN_THREAD
761
762 if (g_isIdle)
763 wxapp_install_idle_handler();
764
765 /*
766 if (win->GetName() == wxT("panel"))
767 {
768 wxPrintf( wxT("OnExpose from ") );
769 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
770 wxPrintf( win->GetClassInfo()->GetClassName() );
771 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
772 (int)gdk_event->area.y,
773 (int)gdk_event->area.width,
774 (int)gdk_event->area.height );
775 }
776 */
777
778 GtkPizza *pizza = GTK_PIZZA (widget);
779
780 if (win->GetThemeEnabled())
781 {
782 wxWindow *parent = win->GetParent();
783 while (parent && !parent->IsTopLevel())
784 parent = parent->GetParent();
785 if (!parent)
786 parent = win;
787
788 gtk_paint_flat_box (parent->m_widget->style,
789 pizza->bin_window,
790 GTK_STATE_NORMAL,
791 GTK_SHADOW_NONE,
792 &gdk_event->area,
793 parent->m_widget,
794 (char *)"base",
795 0, 0, -1, -1);
796 }
797
798 win->GetUpdateRegion().Union( gdk_event->area.x,
799 gdk_event->area.y,
800 gdk_event->area.width,
801 gdk_event->area.height );
802
803 // Actual redrawing takes place in idle time.
804
805 return TRUE;
806 }
807
808 //-----------------------------------------------------------------------------
809 // "event" of m_wxwindow
810 //-----------------------------------------------------------------------------
811
812 // GTK thinks it is clever and filters out a certain amount of "unneeded"
813 // expose events. We need them, of course, so we override the main event
814 // procedure in GtkWidget by giving our own handler for all system events.
815 // There, we look for expose events ourselves whereas all other events are
816 // handled normally.
817
818 gint gtk_window_event_event_callback( GtkWidget *widget,
819 GdkEventExpose *event,
820 wxWindow *win )
821 {
822 if (event->type == GDK_EXPOSE)
823 {
824 gint ret = gtk_window_expose_callback( widget, event, win );
825 return ret;
826 }
827
828 return FALSE;
829 }
830
831 //-----------------------------------------------------------------------------
832 // "draw" of m_wxwindow
833 //-----------------------------------------------------------------------------
834
835 // This callback is a complete replacement of the gtk_pizza_draw() function,
836 // which disabled.
837
838 static void gtk_window_draw_callback( GtkWidget *widget,
839 GdkRectangle *rect,
840 wxWindow *win )
841 {
842 DEBUG_MAIN_THREAD
843
844 if (g_isIdle)
845 wxapp_install_idle_handler();
846
847 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
848 // there are no child windows.
849 if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) &&
850 (win->GetChildren().GetCount() == 0))
851 {
852 return;
853 }
854
855 /*
856 if (win->GetName() == wxT("panel"))
857 {
858 wxPrintf( wxT("OnDraw from ") );
859 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
860 wxPrintf( win->GetClassInfo()->GetClassName() );
861 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
862 (int)rect->y,
863 (int)rect->width,
864 (int)rect->height );
865 }
866 */
867
868 GtkPizza *pizza = GTK_PIZZA (widget);
869
870 if (win->GetThemeEnabled())
871 {
872 wxWindow *parent = win->GetParent();
873 while (parent && !parent->IsTopLevel())
874 parent = parent->GetParent();
875 if (!parent)
876 parent = win;
877
878 gtk_paint_flat_box (parent->m_widget->style,
879 pizza->bin_window,
880 GTK_STATE_NORMAL,
881 GTK_SHADOW_NONE,
882 rect,
883 parent->m_widget,
884 (char *)"base",
885 0, 0, -1, -1);
886 }
887
888
889 if (!(GTK_WIDGET_APP_PAINTABLE (widget)) &&
890 (pizza->clear_on_draw))
891 {
892 gdk_window_clear_area( pizza->bin_window,
893 rect->x, rect->y, rect->width, rect->height);
894 }
895
896 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
897
898 // Actual redrawing takes place in idle time.
899
900 #ifndef __WXUNIVERSAL__
901 // Redraw child widgets
902 GList *children = pizza->children;
903 while (children)
904 {
905 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
906 children = children->next;
907
908 GdkRectangle child_area;
909 if (gtk_widget_intersect (child->widget, rect, &child_area))
910 {
911 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
912 }
913 }
914 #endif
915 }
916
917 //-----------------------------------------------------------------------------
918 // "key_press_event" from any window
919 //-----------------------------------------------------------------------------
920
921 // turn on to see the key event codes on the console
922 #undef DEBUG_KEY_EVENTS
923
924 static gint gtk_window_key_press_callback( GtkWidget *widget,
925 GdkEventKey *gdk_event,
926 wxWindow *win )
927 {
928 DEBUG_MAIN_THREAD
929
930 if (g_isIdle)
931 wxapp_install_idle_handler();
932
933 if (!win->m_hasVMT) return FALSE;
934 if (g_blockEventsOnDrag) return FALSE;
935
936
937 int x = 0;
938 int y = 0;
939 GdkModifierType state;
940 if (gdk_event->window)
941 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
942
943 bool ret = FALSE;
944
945 long key_code = map_to_unmodified_wx_keysym( gdk_event );
946
947 #ifdef DEBUG_KEY_EVENTS
948 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event->keyval, key_code);
949 #endif // DEBUG_KEY_EVENTS
950
951 /* sending unknown key events doesn't really make sense */
952 if (key_code == 0)
953 return FALSE;
954
955 wxKeyEvent event( wxEVT_KEY_DOWN );
956 event.SetTimestamp( gdk_event->time );
957 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
958 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
959 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
960 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
961 event.m_keyCode = key_code;
962 event.m_scanCode = gdk_event->keyval;
963 event.m_x = x;
964 event.m_y = y;
965 event.SetEventObject( win );
966 ret = win->GetEventHandler()->ProcessEvent( event );
967
968 #if wxUSE_ACCEL
969 if (!ret)
970 {
971 wxWindowGTK *ancestor = win;
972 while (ancestor)
973 {
974 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
975 if (command != -1)
976 {
977 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
978 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
979 break;
980 }
981 if (ancestor->IsTopLevel())
982 break;
983 ancestor = ancestor->GetParent();
984 }
985 }
986 #endif // wxUSE_ACCEL
987
988 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
989 will only be sent if it is not in an accelerator table. */
990 if ( !ret )
991 {
992 key_code = map_to_wx_keysym( gdk_event );
993
994 if ( key_code )
995 {
996 #ifdef DEBUG_KEY_EVENTS
997 wxPrintf(_T("Char event: %ld\n"), key_code);
998 #endif // DEBUG_KEY_EVENTS
999
1000 // reuse the ame event object, just change its type and use the
1001 // translated keycode instead of the raw one
1002 event.SetEventType(wxEVT_CHAR);
1003 event.m_keyCode = key_code;
1004
1005 ret = win->GetEventHandler()->ProcessEvent( event );
1006 }
1007 }
1008
1009 /* win is a control: tab can be propagated up */
1010 if ( !ret &&
1011 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
1012 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1013 // have this style, yet choose not to process this particular TAB in which
1014 // case TAB must still work as a navigational character
1015 #if 0
1016 !win->HasFlag(wxTE_PROCESS_TAB) &&
1017 #endif // 0
1018 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
1019 {
1020 wxNavigationKeyEvent new_event;
1021 new_event.SetEventObject( win->GetParent() );
1022 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1023 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
1024 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1025 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
1026 new_event.SetCurrentFocus( win );
1027 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
1028 }
1029
1030 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1031 if ( !ret &&
1032 (gdk_event->keyval == GDK_Escape) )
1033 {
1034 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
1035 new_event.SetEventObject( win );
1036 ret = win->GetEventHandler()->ProcessEvent( new_event );
1037 }
1038
1039 /* Doesn't work. */
1040 #if 0 // (GTK_MINOR_VERSION > 0)
1041 /* Pressing F10 will activate the menu bar of the top frame. */
1042 if ( (!ret) &&
1043 (gdk_event->keyval == GDK_F10) )
1044 {
1045 wxWindowGTK *ancestor = win;
1046 while (ancestor)
1047 {
1048 if (wxIsKindOf(ancestor,wxFrame))
1049 {
1050 wxFrame *frame = (wxFrame*) ancestor;
1051 wxMenuBar *menubar = frame->GetMenuBar();
1052 if (menubar)
1053 {
1054 wxNode *node = menubar->GetMenus().First();
1055 if (node)
1056 {
1057 wxMenu *firstMenu = (wxMenu*) node->Data();
1058 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
1059 ret = TRUE;
1060 break;
1061 }
1062 }
1063 }
1064 ancestor = ancestor->GetParent();
1065 }
1066 }
1067 #endif // 0
1068
1069 if (ret)
1070 {
1071 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1072 return TRUE;
1073 }
1074
1075 return FALSE;
1076 }
1077
1078 //-----------------------------------------------------------------------------
1079 // "key_release_event" from any window
1080 //-----------------------------------------------------------------------------
1081
1082 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindowGTK *win )
1083 {
1084 DEBUG_MAIN_THREAD
1085
1086 if (g_isIdle)
1087 wxapp_install_idle_handler();
1088
1089 if (!win->m_hasVMT) return FALSE;
1090 if (g_blockEventsOnDrag) return FALSE;
1091
1092 long key_code = map_to_unmodified_wx_keysym( gdk_event );
1093
1094 #ifdef DEBUG_KEY_EVENTS
1095 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event->keyval, key_code);
1096 #endif // DEBUG_KEY_EVENTS
1097
1098 /* sending unknown key events doesn't really make sense */
1099 if (key_code == 0) return FALSE;
1100
1101 int x = 0;
1102 int y = 0;
1103 GdkModifierType state;
1104 if (gdk_event->window)
1105 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1106
1107 wxKeyEvent event( wxEVT_KEY_UP );
1108 event.SetTimestamp( gdk_event->time );
1109 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1110 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1111 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1112 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1113 event.m_keyCode = key_code;
1114 event.m_scanCode = gdk_event->keyval;
1115 event.m_x = x;
1116 event.m_y = y;
1117 event.SetEventObject( win );
1118
1119 if (win->GetEventHandler()->ProcessEvent( event ))
1120 {
1121 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1122 return TRUE;
1123 }
1124
1125 return FALSE;
1126 }
1127
1128 // ============================================================================
1129 // the mouse events
1130 // ============================================================================
1131
1132 // init wxMouseEvent with the info from gdk_event
1133 #define InitMouseEvent(win, event, gdk_event) \
1134 { \
1135 event.SetTimestamp( gdk_event->time ); \
1136 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1137 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1138 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1139 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1140 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1141 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1142 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1143 \
1144 wxPoint pt = win->GetClientAreaOrigin(); \
1145 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1146 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1147 }
1148
1149 // ----------------------------------------------------------------------------
1150 // mouse event processing helper
1151 // ----------------------------------------------------------------------------
1152
1153 static void AdjustEventButtonState(wxMouseEvent& event)
1154 {
1155 // GDK reports the old state of the button for a button press event, but
1156 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1157 // for a LEFT_DOWN event, not FALSE, so we will invert
1158 // left/right/middleDown for the corresponding click events
1159
1160 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1161 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1162 (event.GetEventType() == wxEVT_LEFT_UP))
1163 {
1164 event.m_leftDown = !event.m_leftDown;
1165 return;
1166 }
1167
1168 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1169 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1170 (event.GetEventType() == wxEVT_MIDDLE_UP))
1171 {
1172 event.m_middleDown = !event.m_middleDown;
1173 return;
1174 }
1175
1176 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1177 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1178 (event.GetEventType() == wxEVT_RIGHT_UP))
1179 {
1180 event.m_rightDown = !event.m_rightDown;
1181 return;
1182 }
1183 }
1184
1185 //-----------------------------------------------------------------------------
1186 // "button_press_event"
1187 //-----------------------------------------------------------------------------
1188
1189 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
1190 {
1191 DEBUG_MAIN_THREAD
1192
1193 if (g_isIdle)
1194 wxapp_install_idle_handler();
1195
1196 /*
1197 wxPrintf( wxT("1) OnButtonPress from ") );
1198 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1199 wxPrintf( win->GetClassInfo()->GetClassName() );
1200 wxPrintf( wxT(".\n") );
1201 */
1202 if (!win->m_hasVMT) return FALSE;
1203 if (g_blockEventsOnDrag) return TRUE;
1204 if (g_blockEventsOnScroll) return TRUE;
1205
1206 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1207
1208 if (win->m_wxwindow)
1209 {
1210 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
1211 {
1212 gtk_widget_grab_focus (win->m_wxwindow);
1213
1214 /*
1215 wxPrintf( wxT("GrabFocus from ") );
1216 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1217 wxPrintf( win->GetClassInfo()->GetClassName() );
1218 wxPrintf( wxT(".\n") );
1219 */
1220
1221 }
1222 }
1223
1224 wxEventType event_type = wxEVT_NULL;
1225
1226 if (gdk_event->button == 1)
1227 {
1228 switch (gdk_event->type)
1229 {
1230 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1231 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1232 default: break;
1233 }
1234 }
1235 else if (gdk_event->button == 2)
1236 {
1237 switch (gdk_event->type)
1238 {
1239 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1240 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1241 default: break;
1242 }
1243 }
1244 else if (gdk_event->button == 3)
1245 {
1246 switch (gdk_event->type)
1247 {
1248 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1249 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1250 default: break;
1251 }
1252 }
1253
1254 if ( event_type == wxEVT_NULL )
1255 {
1256 // unknown mouse button or click type
1257 return FALSE;
1258 }
1259
1260 wxMouseEvent event( event_type );
1261 InitMouseEvent( win, event, gdk_event );
1262
1263 AdjustEventButtonState(event);
1264
1265 // wxListBox actually get mouse events from the item
1266
1267 if (win->m_isListBox)
1268 {
1269 event.m_x += widget->allocation.x;
1270 event.m_y += widget->allocation.y;
1271 }
1272
1273 // Some control don't have their own X window and thus cannot get
1274 // any events.
1275
1276 if (!g_captureWindow)
1277 {
1278 wxCoord x = event.m_x;
1279 wxCoord y = event.m_y;
1280 if (win->m_wxwindow)
1281 {
1282 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1283 x += pizza->xoffset;
1284 y += pizza->yoffset;
1285 }
1286
1287 wxNode *node = win->GetChildren().First();
1288 while (node)
1289 {
1290 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1291
1292 node = node->Next();
1293 if (!child->IsShown())
1294 continue;
1295
1296 if (child->m_isStaticBox)
1297 {
1298 // wxStaticBox is transparent in the box itself
1299 int xx1 = child->m_x;
1300 int yy1 = child->m_y;
1301 int xx2 = child->m_x + child->m_width;
1302 int yy2 = child->m_x + child->m_height;
1303
1304 // left
1305 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1306 // right
1307 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1308 // top
1309 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1310 // bottom
1311 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1312 {
1313 win = child;
1314 event.m_x -= child->m_x;
1315 event.m_y -= child->m_y;
1316 break;
1317 }
1318
1319 }
1320 else
1321 {
1322 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1323 (child->m_x <= x) &&
1324 (child->m_y <= y) &&
1325 (child->m_x+child->m_width >= x) &&
1326 (child->m_y+child->m_height >= y))
1327 {
1328 win = child;
1329 event.m_x -= child->m_x;
1330 event.m_y -= child->m_y;
1331 break;
1332 }
1333 }
1334 }
1335 }
1336
1337 event.SetEventObject( win );
1338
1339 gs_timeLastClick = gdk_event->time;
1340
1341 /*
1342 wxPrintf( wxT("2) OnButtonPress from ") );
1343 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1344 wxPrintf( win->GetClassInfo()->GetClassName() );
1345 wxPrintf( wxT(".\n") );
1346 */
1347
1348 if (win->GetEventHandler()->ProcessEvent( event ))
1349 {
1350 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1351 return TRUE;
1352 }
1353
1354 return FALSE;
1355 }
1356
1357 //-----------------------------------------------------------------------------
1358 // "button_release_event"
1359 //-----------------------------------------------------------------------------
1360
1361 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
1362 {
1363 DEBUG_MAIN_THREAD
1364
1365 if (g_isIdle)
1366 wxapp_install_idle_handler();
1367
1368 if (!win->m_hasVMT) return FALSE;
1369 if (g_blockEventsOnDrag) return FALSE;
1370 if (g_blockEventsOnScroll) return FALSE;
1371
1372 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1373
1374 /*
1375 printf( "OnButtonRelease from " );
1376 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1377 printf( win->GetClassInfo()->GetClassName() );
1378 printf( ".\n" );
1379 */
1380
1381 wxEventType event_type = wxEVT_NULL;
1382
1383 switch (gdk_event->button)
1384 {
1385 case 1: event_type = wxEVT_LEFT_UP; break;
1386 case 2: event_type = wxEVT_MIDDLE_UP; break;
1387 case 3: event_type = wxEVT_RIGHT_UP; break;
1388 default: return FALSE;
1389 }
1390
1391 wxMouseEvent event( event_type );
1392 InitMouseEvent( win, event, gdk_event );
1393
1394 AdjustEventButtonState(event);
1395
1396 // wxListBox actually get mouse events from the item
1397
1398 if (win->m_isListBox)
1399 {
1400 event.m_x += widget->allocation.x;
1401 event.m_y += widget->allocation.y;
1402 }
1403
1404 // Some control don't have their own X window and thus cannot get
1405 // any events.
1406
1407 if (!g_captureWindow)
1408 {
1409 wxCoord x = event.m_x;
1410 wxCoord y = event.m_y;
1411 if (win->m_wxwindow)
1412 {
1413 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1414 x += pizza->xoffset;
1415 y += pizza->yoffset;
1416 }
1417
1418 wxNode *node = win->GetChildren().First();
1419 while (node)
1420 {
1421 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1422
1423 node = node->Next();
1424 if (!child->IsShown())
1425 continue;
1426
1427 if (child->m_isStaticBox)
1428 {
1429 // wxStaticBox is transparent in the box itself
1430 int xx1 = child->m_x;
1431 int yy1 = child->m_y;
1432 int xx2 = child->m_x + child->m_width;
1433 int yy2 = child->m_x + child->m_height;
1434
1435 // left
1436 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1437 // right
1438 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1439 // top
1440 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1441 // bottom
1442 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1443 {
1444 win = child;
1445 event.m_x -= child->m_x;
1446 event.m_y -= child->m_y;
1447 break;
1448 }
1449
1450 }
1451 else
1452 {
1453 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1454 (child->m_x <= x) &&
1455 (child->m_y <= y) &&
1456 (child->m_x+child->m_width >= x) &&
1457 (child->m_y+child->m_height >= y))
1458 {
1459 win = child;
1460 event.m_x -= child->m_x;
1461 event.m_y -= child->m_y;
1462 break;
1463 }
1464 }
1465 }
1466 }
1467
1468 event.SetEventObject( win );
1469
1470 if (win->GetEventHandler()->ProcessEvent( event ))
1471 {
1472 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1473 return TRUE;
1474 }
1475
1476 return FALSE;
1477 }
1478
1479 //-----------------------------------------------------------------------------
1480 // "motion_notify_event"
1481 //-----------------------------------------------------------------------------
1482
1483 static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1484 GdkEventMotion *gdk_event,
1485 wxWindowGTK *win )
1486 {
1487 DEBUG_MAIN_THREAD
1488
1489 if (g_isIdle)
1490 wxapp_install_idle_handler();
1491
1492 if (!win->m_hasVMT) return FALSE;
1493 if (g_blockEventsOnDrag) return FALSE;
1494 if (g_blockEventsOnScroll) return FALSE;
1495
1496 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1497
1498 if (gdk_event->is_hint)
1499 {
1500 int x = 0;
1501 int y = 0;
1502 GdkModifierType state;
1503 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1504 gdk_event->x = x;
1505 gdk_event->y = y;
1506 }
1507
1508 /*
1509 printf( "OnMotion from " );
1510 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1511 printf( win->GetClassInfo()->GetClassName() );
1512 printf( ".\n" );
1513 */
1514
1515 wxMouseEvent event( wxEVT_MOTION );
1516 InitMouseEvent(win, event, gdk_event);
1517
1518 if ( g_captureWindow )
1519 {
1520 // synthetize a mouse enter or leave event if needed
1521 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
1522 bool hasMouse = winUnderMouse == gdk_event->window;
1523 if ( hasMouse != g_captureWindowHasMouse )
1524 {
1525 // the mouse changed window
1526 g_captureWindowHasMouse = hasMouse;
1527
1528 wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1529 : wxEVT_LEAVE_WINDOW);
1530 InitMouseEvent(win, event, gdk_event);
1531 event.SetEventObject(win);
1532 win->GetEventHandler()->ProcessEvent(event);
1533 }
1534 }
1535 else // no capture
1536 {
1537 // Some control don't have their own X window and thus cannot get
1538 // any events.
1539
1540 wxCoord x = event.m_x;
1541 wxCoord y = event.m_y;
1542 if (win->m_wxwindow)
1543 {
1544 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1545 x += pizza->xoffset;
1546 y += pizza->yoffset;
1547 }
1548
1549 wxNode *node = win->GetChildren().First();
1550 while (node)
1551 {
1552 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1553
1554 node = node->Next();
1555 if (!child->IsShown())
1556 continue;
1557
1558 if (child->m_isStaticBox)
1559 {
1560 // wxStaticBox is transparent in the box itself
1561 int xx1 = child->m_x;
1562 int yy1 = child->m_y;
1563 int xx2 = child->m_x + child->m_width;
1564 int yy2 = child->m_x + child->m_height;
1565
1566 // left
1567 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1568 // right
1569 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1570 // top
1571 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1572 // bottom
1573 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1574 {
1575 win = child;
1576 event.m_x -= child->m_x;
1577 event.m_y -= child->m_y;
1578 break;
1579 }
1580
1581 }
1582 else
1583 {
1584 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1585 (child->m_x <= x) &&
1586 (child->m_y <= y) &&
1587 (child->m_x+child->m_width >= x) &&
1588 (child->m_y+child->m_height >= y))
1589 {
1590 win = child;
1591 event.m_x -= child->m_x;
1592 event.m_y -= child->m_y;
1593 break;
1594 }
1595 }
1596 }
1597 }
1598
1599 event.SetEventObject( win );
1600
1601 if (win->GetEventHandler()->ProcessEvent( event ))
1602 {
1603 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1604 return TRUE;
1605 }
1606
1607 return FALSE;
1608 }
1609
1610 //-----------------------------------------------------------------------------
1611 // "focus_in_event"
1612 //-----------------------------------------------------------------------------
1613
1614 static gint gtk_window_focus_in_callback( GtkWidget *widget,
1615 GdkEvent *WXUNUSED(event),
1616 wxWindow *win )
1617 {
1618 DEBUG_MAIN_THREAD
1619
1620 if (g_isIdle)
1621 wxapp_install_idle_handler();
1622
1623 if (!win->m_hasVMT) return FALSE;
1624 if (g_blockEventsOnDrag) return FALSE;
1625
1626 switch ( g_sendActivateEvent )
1627 {
1628 case -1:
1629 // we've got focus from outside, synthetize wxActivateEvent
1630 g_sendActivateEvent = 1;
1631 break;
1632
1633 case 0:
1634 // another our window just lost focus, it was already ours before
1635 // - don't send any wxActivateEvent
1636 g_sendActivateEvent = -1;
1637 break;
1638 }
1639
1640 g_focusWindowLast =
1641 g_focusWindow = win;
1642
1643 #if 0
1644 wxPrintf( "OnSetFocus from " );
1645 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1646 wxPrintf( win->GetClassInfo()->GetClassName() );
1647 wxPrintf( ".\n" );
1648 #endif
1649
1650 // notify the parent keeping track of focus for the kbd navigation
1651 // purposes that we got it
1652 wxChildFocusEvent eventFocus(win);
1653 (void)win->GetEventHandler()->ProcessEvent(eventFocus);
1654
1655 #ifdef HAVE_XIM
1656 if (win->m_ic)
1657 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1658 #endif
1659
1660 #if wxUSE_CARET
1661 // caret needs to be informed about focus change
1662 wxCaret *caret = win->GetCaret();
1663 if ( caret )
1664 {
1665 caret->OnSetFocus();
1666 }
1667 #endif // wxUSE_CARET
1668
1669 wxWindowGTK *active = wxGetTopLevelParent(win);
1670 if ( active != g_activeFrame )
1671 {
1672 if ( g_activeFrame )
1673 {
1674 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame);
1675 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
1676 event.SetEventObject(g_activeFrame);
1677 g_activeFrame->GetEventHandler()->ProcessEvent(event);
1678 }
1679
1680 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active);
1681 g_activeFrame = active;
1682 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
1683 event.SetEventObject(g_activeFrame);
1684 g_activeFrame->GetEventHandler()->ProcessEvent(event);
1685 }
1686 g_activeFrameLostFocus = FALSE;
1687
1688
1689 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1690 event.SetEventObject( win );
1691
1692 if (win->GetEventHandler()->ProcessEvent( event ))
1693 {
1694 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1695 return TRUE;
1696 }
1697
1698
1699 return FALSE;
1700 }
1701
1702 //-----------------------------------------------------------------------------
1703 // "focus_out_event"
1704 //-----------------------------------------------------------------------------
1705
1706 static GtkWidget *gs_widgetLastFocus = NULL;
1707
1708 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win )
1709 {
1710 DEBUG_MAIN_THREAD
1711
1712 if (g_isIdle)
1713 wxapp_install_idle_handler();
1714
1715 if (!win->m_hasVMT) return FALSE;
1716 if (g_blockEventsOnDrag) return FALSE;
1717
1718 // VZ: this is really weird but GTK+ seems to call us from inside
1719 // gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
1720 // this widget and then "focus_in". This is totally unexpected and
1721 // completely breaks wxUniv code so ignore this dummy event (we can't
1722 // be losing focus if we're about to acquire it!)
1723 if ( widget == gs_widgetLastFocus )
1724 {
1725 gs_widgetLastFocus = NULL;
1726
1727 return FALSE;
1728 }
1729
1730 if ( !g_activeFrameLostFocus && g_activeFrame )
1731 {
1732 // VZ: commenting this out because it does happen (although not easy
1733 // to reproduce, I only see it when using wxMiniFrame and not
1734 // always) and makes using Mahogany quite annoying
1735 #if 0
1736 wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame,
1737 wxT("unfocusing window that hasn't gained focus properly") )
1738 #endif // 0
1739
1740 g_activeFrameLostFocus = TRUE;
1741 }
1742
1743 // if the focus goes out of our app alltogether, OnIdle() will send
1744 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1745 // g_sendActivateEvent to -1
1746 g_sendActivateEvent = 0;
1747
1748 wxWindowGTK *winFocus = wxFindFocusedChild(win);
1749 if ( winFocus )
1750 win = winFocus;
1751
1752 g_focusWindow = (wxWindowGTK *)NULL;
1753
1754 #if 0
1755 wxPrintf( "OnKillFocus from " );
1756 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1757 wxPrintf( win->GetClassInfo()->GetClassName() );
1758 wxPrintf( ".\n" );
1759 #endif
1760
1761 #ifdef HAVE_XIM
1762 if (win->m_ic)
1763 gdk_im_end();
1764 #endif
1765
1766 #if wxUSE_CARET
1767 // caret needs to be informed about focus change
1768 wxCaret *caret = win->GetCaret();
1769 if ( caret )
1770 {
1771 caret->OnKillFocus();
1772 }
1773 #endif // wxUSE_CARET
1774
1775 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1776 event.SetEventObject( win );
1777
1778 if (win->GetEventHandler()->ProcessEvent( event ))
1779 {
1780 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1781 return TRUE;
1782 }
1783
1784 return FALSE;
1785 }
1786
1787 //-----------------------------------------------------------------------------
1788 // "enter_notify_event"
1789 //-----------------------------------------------------------------------------
1790
1791 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
1792 {
1793 DEBUG_MAIN_THREAD
1794
1795 if (g_isIdle)
1796 wxapp_install_idle_handler();
1797
1798 if (!win->m_hasVMT) return FALSE;
1799 if (g_blockEventsOnDrag) return FALSE;
1800
1801 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1802
1803 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1804 event.SetTimestamp( gdk_event->time );
1805 event.SetEventObject( win );
1806
1807 int x = 0;
1808 int y = 0;
1809 GdkModifierType state = (GdkModifierType)0;
1810
1811 gdk_window_get_pointer( widget->window, &x, &y, &state );
1812
1813 InitMouseEvent(win, event, gdk_event);
1814 wxPoint pt = win->GetClientAreaOrigin();
1815 event.m_x = x + pt.x;
1816 event.m_y = y + pt.y;
1817
1818 if (win->GetEventHandler()->ProcessEvent( event ))
1819 {
1820 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1821 return TRUE;
1822 }
1823
1824 return FALSE;
1825 }
1826
1827 //-----------------------------------------------------------------------------
1828 // "leave_notify_event"
1829 //-----------------------------------------------------------------------------
1830
1831 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
1832 {
1833 DEBUG_MAIN_THREAD
1834
1835 if (g_isIdle)
1836 wxapp_install_idle_handler();
1837
1838 if (!win->m_hasVMT) return FALSE;
1839 if (g_blockEventsOnDrag) return FALSE;
1840
1841 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1842
1843 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1844 event.SetTimestamp( gdk_event->time );
1845 event.SetEventObject( win );
1846
1847 int x = 0;
1848 int y = 0;
1849 GdkModifierType state = (GdkModifierType)0;
1850
1851 gdk_window_get_pointer( widget->window, &x, &y, &state );
1852
1853 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1854 event.m_controlDown = (state & GDK_CONTROL_MASK);
1855 event.m_altDown = (state & GDK_MOD1_MASK);
1856 event.m_metaDown = (state & GDK_MOD2_MASK);
1857 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1858 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1859 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1860
1861 wxPoint pt = win->GetClientAreaOrigin();
1862 event.m_x = x + pt.x;
1863 event.m_y = y + pt.y;
1864
1865 if (win->GetEventHandler()->ProcessEvent( event ))
1866 {
1867 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1868 return TRUE;
1869 }
1870
1871 return FALSE;
1872 }
1873
1874 //-----------------------------------------------------------------------------
1875 // "value_changed" from m_vAdjust
1876 //-----------------------------------------------------------------------------
1877
1878 static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
1879 {
1880 DEBUG_MAIN_THREAD
1881
1882 if (g_isIdle)
1883 wxapp_install_idle_handler();
1884
1885 if (g_blockEventsOnDrag) return;
1886
1887 if (!win->m_hasVMT) return;
1888
1889 float diff = adjust->value - win->m_oldVerticalPos;
1890 if (fabs(diff) < 0.2) return;
1891
1892 win->m_oldVerticalPos = adjust->value;
1893
1894 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1895 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
1896
1897 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1898 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1899 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1900 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1901 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1902
1903 int value = (int)(adjust->value+0.5);
1904
1905 wxScrollWinEvent event( command, value, wxVERTICAL );
1906 event.SetEventObject( win );
1907 win->GetEventHandler()->ProcessEvent( event );
1908 }
1909
1910 //-----------------------------------------------------------------------------
1911 // "value_changed" from m_hAdjust
1912 //-----------------------------------------------------------------------------
1913
1914 static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
1915 {
1916 DEBUG_MAIN_THREAD
1917
1918 if (g_isIdle)
1919 wxapp_install_idle_handler();
1920
1921 if (g_blockEventsOnDrag) return;
1922 if (!win->m_hasVMT) return;
1923
1924 float diff = adjust->value - win->m_oldHorizontalPos;
1925 if (fabs(diff) < 0.2) return;
1926
1927 win->m_oldHorizontalPos = adjust->value;
1928
1929 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1930 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
1931
1932 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1933 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1934 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1935 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1936 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1937
1938 int value = (int)(adjust->value+0.5);
1939
1940 wxScrollWinEvent event( command, value, wxHORIZONTAL );
1941 event.SetEventObject( win );
1942 win->GetEventHandler()->ProcessEvent( event );
1943 }
1944
1945 //-----------------------------------------------------------------------------
1946 // "button_press_event" from scrollbar
1947 //-----------------------------------------------------------------------------
1948
1949 static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
1950 GdkEventButton *gdk_event,
1951 wxWindowGTK *win)
1952 {
1953 DEBUG_MAIN_THREAD
1954
1955 if (g_isIdle)
1956 wxapp_install_idle_handler();
1957
1958
1959 g_blockEventsOnScroll = TRUE;
1960 win->m_isScrolling = (gdk_event->window == widget->slider);
1961
1962 return FALSE;
1963 }
1964
1965 //-----------------------------------------------------------------------------
1966 // "button_release_event" from scrollbar
1967 //-----------------------------------------------------------------------------
1968
1969 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
1970 GdkEventButton *WXUNUSED(gdk_event),
1971 wxWindowGTK *win)
1972 {
1973 DEBUG_MAIN_THREAD
1974
1975 // don't test here as we can release the mouse while being over
1976 // a different window than the slider
1977 //
1978 // if (gdk_event->window != widget->slider) return FALSE;
1979
1980 g_blockEventsOnScroll = FALSE;
1981
1982 if (win->m_isScrolling)
1983 {
1984 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
1985 int value = -1;
1986 int dir = -1;
1987
1988 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1989 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
1990 {
1991 value = (int)(win->m_hAdjust->value+0.5);
1992 dir = wxHORIZONTAL;
1993 }
1994 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
1995 {
1996 value = (int)(win->m_vAdjust->value+0.5);
1997 dir = wxVERTICAL;
1998 }
1999
2000 wxScrollWinEvent event( command, value, dir );
2001 event.SetEventObject( win );
2002 win->GetEventHandler()->ProcessEvent( event );
2003 }
2004
2005 win->m_isScrolling = FALSE;
2006
2007 return FALSE;
2008 }
2009
2010 // ----------------------------------------------------------------------------
2011 // this wxWindowBase function is implemented here (in platform-specific file)
2012 // because it is static and so couldn't be made virtual
2013 // ----------------------------------------------------------------------------
2014
2015 wxWindow *wxWindowBase::FindFocus()
2016 {
2017 // the cast is necessary when we compile in wxUniversal mode
2018 return (wxWindow *)g_focusWindow;
2019 }
2020
2021 //-----------------------------------------------------------------------------
2022 // "realize" from m_widget
2023 //-----------------------------------------------------------------------------
2024
2025 /* We cannot set colours and fonts before the widget has
2026 been realized, so we do this directly after realization. */
2027
2028 static gint
2029 gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
2030 {
2031 DEBUG_MAIN_THREAD
2032
2033 if (g_isIdle)
2034 wxapp_install_idle_handler();
2035
2036 if (win->m_delayedBackgroundColour)
2037 win->SetBackgroundColour( win->GetBackgroundColour() );
2038
2039 if (win->m_delayedForegroundColour)
2040 win->SetForegroundColour( win->GetForegroundColour() );
2041
2042 wxWindowCreateEvent event( win );
2043 event.SetEventObject( win );
2044 win->GetEventHandler()->ProcessEvent( event );
2045
2046 return FALSE;
2047 }
2048
2049 //-----------------------------------------------------------------------------
2050 // "size_allocate"
2051 //-----------------------------------------------------------------------------
2052
2053 static
2054 void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2055 GtkAllocation *WXUNUSED(alloc),
2056 wxWindow *win )
2057 {
2058 if (g_isIdle)
2059 wxapp_install_idle_handler();
2060
2061 if (!win->m_hasScrolling) return;
2062
2063 int client_width = 0;
2064 int client_height = 0;
2065 win->GetClientSize( &client_width, &client_height );
2066 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2067 return;
2068
2069 win->m_oldClientWidth = client_width;
2070 win->m_oldClientHeight = client_height;
2071
2072 if (!win->m_nativeSizeEvent)
2073 {
2074 wxSizeEvent event( win->GetSize(), win->GetId() );
2075 event.SetEventObject( win );
2076 win->GetEventHandler()->ProcessEvent( event );
2077 }
2078 }
2079
2080
2081 #ifdef HAVE_XIM
2082 #define WXUNUSED_UNLESS_XIM(param) param
2083 #else
2084 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2085 #endif
2086
2087 /* Resize XIM window */
2088
2089 static
2090 void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2091 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
2092 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
2093 {
2094 if (g_isIdle)
2095 wxapp_install_idle_handler();
2096
2097 #ifdef HAVE_XIM
2098 if (!win->m_ic)
2099 return;
2100
2101 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2102 {
2103 gint width, height;
2104
2105 gdk_window_get_size (widget->window, &width, &height);
2106 win->m_icattr->preedit_area.width = width;
2107 win->m_icattr->preedit_area.height = height;
2108 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2109 }
2110 #endif // HAVE_XIM
2111 }
2112
2113 //-----------------------------------------------------------------------------
2114 // "realize" from m_wxwindow
2115 //-----------------------------------------------------------------------------
2116
2117 /* Initialize XIM support */
2118
2119 static gint
2120 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
2121 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
2122 {
2123 if (g_isIdle)
2124 wxapp_install_idle_handler();
2125
2126 #ifdef HAVE_XIM
2127 if (win->m_ic) return FALSE;
2128 if (!widget) return FALSE;
2129 if (!gdk_im_ready()) return FALSE;
2130
2131 win->m_icattr = gdk_ic_attr_new();
2132 if (!win->m_icattr) return FALSE;
2133
2134 gint width, height;
2135 GdkEventMask mask;
2136 GdkColormap *colormap;
2137 GdkICAttr *attr = win->m_icattr;
2138 unsigned attrmask = GDK_IC_ALL_REQ;
2139 GdkIMStyle style;
2140 GdkIMStyle supported_style = (GdkIMStyle)
2141 (GDK_IM_PREEDIT_NONE |
2142 GDK_IM_PREEDIT_NOTHING |
2143 GDK_IM_PREEDIT_POSITION |
2144 GDK_IM_STATUS_NONE |
2145 GDK_IM_STATUS_NOTHING);
2146
2147 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2148 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
2149
2150 attr->style = style = gdk_im_decide_style (supported_style);
2151 attr->client_window = widget->window;
2152
2153 if ((colormap = gtk_widget_get_colormap (widget)) !=
2154 gtk_widget_get_default_colormap ())
2155 {
2156 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2157 attr->preedit_colormap = colormap;
2158 }
2159
2160 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2161 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2162 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2163 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2164
2165 switch (style & GDK_IM_PREEDIT_MASK)
2166 {
2167 case GDK_IM_PREEDIT_POSITION:
2168 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2169 {
2170 g_warning ("over-the-spot style requires fontset");
2171 break;
2172 }
2173
2174 gdk_window_get_size (widget->window, &width, &height);
2175
2176 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2177 attr->spot_location.x = 0;
2178 attr->spot_location.y = height;
2179 attr->preedit_area.x = 0;
2180 attr->preedit_area.y = 0;
2181 attr->preedit_area.width = width;
2182 attr->preedit_area.height = height;
2183 attr->preedit_fontset = widget->style->font;
2184
2185 break;
2186 }
2187
2188 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2189
2190 if (win->m_ic == NULL)
2191 g_warning ("Can't create input context.");
2192 else
2193 {
2194 mask = gdk_window_get_events (widget->window);
2195 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2196 gdk_window_set_events (widget->window, mask);
2197
2198 if (GTK_WIDGET_HAS_FOCUS(widget))
2199 gdk_im_begin (win->m_ic, widget->window);
2200 }
2201 #endif // HAVE_XIM
2202
2203 return FALSE;
2204 }
2205
2206 //-----------------------------------------------------------------------------
2207 // InsertChild for wxWindowGTK.
2208 //-----------------------------------------------------------------------------
2209
2210 /* Callback for wxWindowGTK. This very strange beast has to be used because
2211 * C++ has no virtual methods in a constructor. We have to emulate a
2212 * virtual function here as wxNotebook requires a different way to insert
2213 * a child in it. I had opted for creating a wxNotebookPage window class
2214 * which would have made this superfluous (such in the MDI window system),
2215 * but no-one was listening to me... */
2216
2217 static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
2218 {
2219 /* the window might have been scrolled already, do we
2220 have to adapt the position */
2221 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2222 child->m_x += pizza->xoffset;
2223 child->m_y += pizza->yoffset;
2224
2225 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
2226 GTK_WIDGET(child->m_widget),
2227 child->m_x,
2228 child->m_y,
2229 child->m_width,
2230 child->m_height );
2231 }
2232
2233 //-----------------------------------------------------------------------------
2234 // global functions
2235 //-----------------------------------------------------------------------------
2236
2237 wxWindow *wxGetActiveWindow()
2238 {
2239 // the cast is necessary when we compile in wxUniversal mode
2240 return (wxWindow *)g_focusWindow;
2241 }
2242
2243 //-----------------------------------------------------------------------------
2244 // wxWindowGTK
2245 //-----------------------------------------------------------------------------
2246
2247 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2248 // method
2249 #ifdef __WXUNIVERSAL__
2250 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2251 #else // __WXGTK__
2252 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
2253 #endif // __WXUNIVERSAL__/__WXGTK__
2254
2255 void wxWindowGTK::Init()
2256 {
2257 // common init
2258 InitBase();
2259
2260 // GTK specific
2261 m_widget = (GtkWidget *) NULL;
2262 m_wxwindow = (GtkWidget *) NULL;
2263 m_focusWidget = (GtkWidget *) NULL;
2264
2265 // position/size
2266 m_x = 0;
2267 m_y = 0;
2268 m_width = 0;
2269 m_height = 0;
2270
2271 m_sizeSet = FALSE;
2272 m_hasVMT = FALSE;
2273 m_needParent = TRUE;
2274 m_isBeingDeleted = FALSE;
2275
2276 m_noExpose = FALSE;
2277 m_nativeSizeEvent = FALSE;
2278
2279 m_hasScrolling = FALSE;
2280 m_isScrolling = FALSE;
2281
2282 m_hAdjust = (GtkAdjustment*) NULL;
2283 m_vAdjust = (GtkAdjustment*) NULL;
2284 m_oldHorizontalPos = 0.0;
2285 m_oldVerticalPos = 0.0;
2286
2287 m_resizing = FALSE;
2288 m_widgetStyle = (GtkStyle*) NULL;
2289
2290 m_insertCallback = (wxInsertChildFunction) NULL;
2291
2292 m_isStaticBox = FALSE;
2293 m_isRadioButton = FALSE;
2294 m_isListBox = FALSE;
2295 m_isFrame = FALSE;
2296 m_acceptsFocus = FALSE;
2297
2298 m_clipPaintRegion = FALSE;
2299
2300 m_cursor = *wxSTANDARD_CURSOR;
2301
2302 m_delayedForegroundColour = FALSE;
2303 m_delayedBackgroundColour = FALSE;
2304
2305 #ifdef HAVE_XIM
2306 m_ic = (GdkIC*) NULL;
2307 m_icattr = (GdkICAttr*) NULL;
2308 #endif
2309 }
2310
2311 wxWindowGTK::wxWindowGTK()
2312 {
2313 Init();
2314 }
2315
2316 wxWindowGTK::wxWindowGTK( wxWindow *parent,
2317 wxWindowID id,
2318 const wxPoint &pos,
2319 const wxSize &size,
2320 long style,
2321 const wxString &name )
2322 {
2323 Init();
2324
2325 Create( parent, id, pos, size, style, name );
2326 }
2327
2328 bool wxWindowGTK::Create( wxWindow *parent,
2329 wxWindowID id,
2330 const wxPoint &pos,
2331 const wxSize &size,
2332 long style,
2333 const wxString &name )
2334 {
2335 if (!PreCreation( parent, pos, size ) ||
2336 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2337 {
2338 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2339 return FALSE;
2340 }
2341
2342 m_insertCallback = wxInsertChildInWindow;
2343
2344 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2345 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2346
2347 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2348
2349 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2350 scroll_class->scrollbar_spacing = 0;
2351
2352 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2353
2354 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2355 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2356
2357 m_wxwindow = gtk_pizza_new();
2358
2359 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2360
2361 #ifndef __WXUNIVERSAL__
2362 #if (GTK_MINOR_VERSION > 0)
2363 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2364
2365 if (HasFlag(wxRAISED_BORDER))
2366 {
2367 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2368 }
2369 else if (HasFlag(wxSUNKEN_BORDER))
2370 {
2371 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2372 }
2373 else if (HasFlag(wxSIMPLE_BORDER))
2374 {
2375 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2376 }
2377 else
2378 {
2379 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2380 }
2381 #else // GTK_MINOR_VERSION == 0
2382 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
2383
2384 if (HasFlag(wxRAISED_BORDER))
2385 {
2386 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2387 }
2388 else if (HasFlag(wxSUNKEN_BORDER))
2389 {
2390 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2391 }
2392 else
2393 {
2394 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2395 }
2396 #endif // GTK_MINOR_VERSION
2397 #endif // __WXUNIVERSAL__
2398
2399 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2400 m_acceptsFocus = TRUE;
2401
2402 #if (GTK_MINOR_VERSION == 0)
2403 // shut the viewport up
2404 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2405 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2406 #endif // GTK_MINOR_VERSION == 0
2407
2408 // I _really_ don't want scrollbars in the beginning
2409 m_vAdjust->lower = 0.0;
2410 m_vAdjust->upper = 1.0;
2411 m_vAdjust->value = 0.0;
2412 m_vAdjust->step_increment = 1.0;
2413 m_vAdjust->page_increment = 1.0;
2414 m_vAdjust->page_size = 5.0;
2415 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2416 m_hAdjust->lower = 0.0;
2417 m_hAdjust->upper = 1.0;
2418 m_hAdjust->value = 0.0;
2419 m_hAdjust->step_increment = 1.0;
2420 m_hAdjust->page_increment = 1.0;
2421 m_hAdjust->page_size = 5.0;
2422 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2423
2424 // these handlers block mouse events to any window during scrolling such as
2425 // motion events and prevent GTK and wxWindows from fighting over where the
2426 // slider should be
2427
2428 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2429 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2430
2431 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2432 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2433
2434 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2435 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2436
2437 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2438 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2439
2440 // these handlers get notified when screen updates are required either when
2441 // scrolling or when the window size (and therefore scrollbar configuration)
2442 // has changed
2443
2444 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2445 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2446 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2447 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2448
2449 gtk_widget_show( m_wxwindow );
2450
2451 if (m_parent)
2452 m_parent->DoAddChild( this );
2453
2454 m_focusWidget = m_wxwindow;
2455
2456 PostCreation();
2457
2458 Show( TRUE );
2459
2460 return TRUE;
2461 }
2462
2463 wxWindowGTK::~wxWindowGTK()
2464 {
2465 if (g_focusWindow == this)
2466 g_focusWindow = NULL;
2467
2468 if (g_activeFrame == this)
2469 g_activeFrame = NULL;
2470
2471 m_isBeingDeleted = TRUE;
2472 m_hasVMT = FALSE;
2473
2474 if (m_widget)
2475 Show( FALSE );
2476
2477 DestroyChildren();
2478
2479 if (m_parent)
2480 m_parent->RemoveChild( this );
2481
2482 #ifdef HAVE_XIM
2483 if (m_ic)
2484 gdk_ic_destroy (m_ic);
2485 if (m_icattr)
2486 gdk_ic_attr_destroy (m_icattr);
2487 #endif
2488
2489 if (m_widgetStyle)
2490 {
2491 #if DISABLE_STYLE_IF_BROKEN_THEME
2492 // don't delete if it's a pixmap theme style
2493 if (!m_widgetStyle->engine_data)
2494 gtk_style_unref( m_widgetStyle );
2495 #endif
2496 m_widgetStyle = (GtkStyle*) NULL;
2497 }
2498
2499 if (m_wxwindow)
2500 {
2501 gtk_widget_destroy( m_wxwindow );
2502 m_wxwindow = (GtkWidget*) NULL;
2503 }
2504
2505 if (m_widget)
2506 {
2507 gtk_widget_destroy( m_widget );
2508 m_widget = (GtkWidget*) NULL;
2509 }
2510 }
2511
2512 bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
2513 {
2514 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2515
2516 /* this turns -1 into 20 so that a minimal window is
2517 visible even although -1,-1 has been given as the
2518 size of the window. the same trick is used in other
2519 ports and should make debugging easier */
2520 m_width = WidthDefault(size.x);
2521 m_height = HeightDefault(size.y);
2522
2523 m_x = (int)pos.x;
2524 m_y = (int)pos.y;
2525
2526 /* some reasonable defaults */
2527 if (!parent)
2528 {
2529 if (m_x == -1)
2530 {
2531 m_x = (gdk_screen_width () - m_width) / 2;
2532 if (m_x < 10) m_x = 10;
2533 }
2534 if (m_y == -1)
2535 {
2536 m_y = (gdk_screen_height () - m_height) / 2;
2537 if (m_y < 10) m_y = 10;
2538 }
2539 }
2540
2541 return TRUE;
2542 }
2543
2544 void wxWindowGTK::PostCreation()
2545 {
2546 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2547
2548 if (m_wxwindow)
2549 {
2550 if (!m_noExpose)
2551 {
2552 // these get reported to wxWindows -> wxPaintEvent
2553
2554 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2555
2556 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2557 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2558
2559 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2560 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2561
2562 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE))
2563 {
2564 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2565 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2566 }
2567 }
2568
2569 // these are called when the "sunken" or "raised" borders are drawn */
2570 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2571 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2572
2573 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2574 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2575 }
2576
2577 // focus handling
2578
2579 if (m_focusWidget == NULL)
2580 m_focusWidget = m_widget;
2581
2582 #if 0
2583 if (GetClassInfo() && GetClassInfo()->GetClassName())
2584 wxPrintf( GetClassInfo()->GetClassName() );
2585 wxPrintf( ".\n" );
2586 #endif
2587
2588 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2589 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2590
2591 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event",
2592 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2593
2594 // connect to the various key and mouse handlers
2595
2596 GtkWidget *connect_widget = GetConnectWidget();
2597
2598 ConnectWidget( connect_widget );
2599
2600 /* We cannot set colours, fonts and cursors before the widget has
2601 been realized, so we do this directly after realization */
2602 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2603 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2604
2605 if (m_wxwindow)
2606 {
2607 // Catch native resize events
2608 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2609 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2610
2611 // Initialize XIM support
2612 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2613 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2614
2615 // And resize XIM window
2616 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2617 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2618 }
2619
2620 if (!GTK_IS_COMBO(m_widget))
2621 {
2622 // This is needed if we want to add our windows into native
2623 // GTK control, such as the toolbar. With this callback, the
2624 // toolbar gets to know the correct size (the one set by the
2625 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2626 // when moving to GTK 2.0.
2627 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2628 GTK_SIGNAL_FUNC(gtk_window_size_request_callback), (gpointer) this );
2629 }
2630
2631 m_hasVMT = TRUE;
2632 }
2633
2634 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
2635 {
2636 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2637 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2638
2639 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2640 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2641
2642 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2643 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2644
2645 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2646 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2647
2648 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2649 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2650
2651 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2652 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2653
2654 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2655 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2656 }
2657
2658 bool wxWindowGTK::Destroy()
2659 {
2660 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2661
2662 m_hasVMT = FALSE;
2663
2664 return wxWindowBase::Destroy();
2665 }
2666
2667 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
2668 {
2669 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2670 }
2671
2672 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2673 {
2674 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2675 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
2676
2677 /*
2678 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2679 */
2680
2681 if (m_resizing) return; /* I don't like recursions */
2682 m_resizing = TRUE;
2683
2684 int currentX, currentY;
2685 GetPosition(&currentX, &currentY);
2686 if (x == -1)
2687 x = currentX;
2688 if (y == -1)
2689 y = currentY;
2690 AdjustForParentClientOrigin(x, y, sizeFlags);
2691
2692 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2693 {
2694 /* don't set the size for children of wxNotebook, just take the values. */
2695 m_x = x;
2696 m_y = y;
2697 m_width = width;
2698 m_height = height;
2699 }
2700 else
2701 {
2702 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2703
2704 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2705 {
2706 if (x != -1) m_x = x + pizza->xoffset;
2707 if (y != -1) m_y = y + pizza->yoffset;
2708 if (width != -1) m_width = width;
2709 if (height != -1) m_height = height;
2710 }
2711 else
2712 {
2713 m_x = x + pizza->xoffset;
2714 m_y = y + pizza->yoffset;
2715 m_width = width;
2716 m_height = height;
2717 }
2718
2719 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2720 {
2721 if (width == -1) m_width = 80;
2722 }
2723
2724 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2725 {
2726 if (height == -1) m_height = 26;
2727 }
2728
2729 int minWidth = GetMinWidth(),
2730 minHeight = GetMinHeight(),
2731 maxWidth = GetMaxWidth(),
2732 maxHeight = GetMaxHeight();
2733
2734 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
2735 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
2736 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
2737 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
2738
2739 int border = 0;
2740 int bottom_border = 0;
2741
2742 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2743 {
2744 /* the default button has a border around it */
2745 border = 6;
2746 bottom_border = 5;
2747 }
2748
2749 DoMoveWindow( m_x-border,
2750 m_y-border,
2751 m_width+2*border,
2752 m_height+border+bottom_border );
2753 }
2754
2755 if (m_hasScrolling)
2756 {
2757 /* Sometimes the client area changes size without the
2758 whole windows's size changing, but if the whole
2759 windows's size doesn't change, no wxSizeEvent will
2760 normally be sent. Here we add an extra test if
2761 the client test has been changed and this will
2762 be used then. */
2763 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2764 }
2765
2766 /*
2767 wxPrintf( "OnSize sent from " );
2768 if (GetClassInfo() && GetClassInfo()->GetClassName())
2769 wxPrintf( GetClassInfo()->GetClassName() );
2770 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2771 */
2772
2773 if (!m_nativeSizeEvent)
2774 {
2775 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2776 event.SetEventObject( this );
2777 GetEventHandler()->ProcessEvent( event );
2778 }
2779
2780 m_resizing = FALSE;
2781 }
2782
2783 void wxWindowGTK::OnInternalIdle()
2784 {
2785 // Update invalidated regions.
2786 Update();
2787
2788 // Synthetize activate events.
2789 if ( g_sendActivateEvent != -1 )
2790 {
2791 bool activate = g_sendActivateEvent != 0;
2792
2793 // do it only once
2794 g_sendActivateEvent = -1;
2795
2796 wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
2797 }
2798
2799 if ( g_activeFrameLostFocus )
2800 {
2801 if ( g_activeFrame )
2802 {
2803 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame);
2804 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
2805 event.SetEventObject(g_activeFrame);
2806 g_activeFrame->GetEventHandler()->ProcessEvent(event);
2807 g_activeFrame = NULL;
2808 }
2809 g_activeFrameLostFocus = FALSE;
2810 }
2811
2812 wxCursor cursor = m_cursor;
2813 if (g_globalCursor.Ok()) cursor = g_globalCursor;
2814
2815 if (cursor.Ok())
2816 {
2817 /* I now set the cursor anew in every OnInternalIdle call
2818 as setting the cursor in a parent window also effects the
2819 windows above so that checking for the current cursor is
2820 not possible. */
2821
2822 if (m_wxwindow)
2823 {
2824 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2825 if (window)
2826 gdk_window_set_cursor( window, cursor.GetCursor() );
2827
2828 if (!g_globalCursor.Ok())
2829 cursor = *wxSTANDARD_CURSOR;
2830
2831 window = m_widget->window;
2832 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2833 gdk_window_set_cursor( window, cursor.GetCursor() );
2834
2835 }
2836 else
2837 {
2838
2839 GdkWindow *window = m_widget->window;
2840 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2841 gdk_window_set_cursor( window, cursor.GetCursor() );
2842
2843 }
2844 }
2845
2846 UpdateWindowUI();
2847 }
2848
2849 void wxWindowGTK::DoGetSize( int *width, int *height ) const
2850 {
2851 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2852
2853 if (width) (*width) = m_width;
2854 if (height) (*height) = m_height;
2855 }
2856
2857 void wxWindowGTK::DoSetClientSize( int width, int height )
2858 {
2859 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2860
2861 if (!m_wxwindow)
2862 {
2863 SetSize( width, height );
2864 }
2865 else
2866 {
2867 int dw = 0;
2868 int dh = 0;
2869
2870 #ifndef __WXUNIVERSAL__
2871 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2872 {
2873 /* when using GTK 1.2 we set the shadow border size to 2 */
2874 dw += 2 * 2;
2875 dh += 2 * 2;
2876 }
2877 if (HasFlag(wxSIMPLE_BORDER))
2878 {
2879 /* when using GTK 1.2 we set the simple border size to 1 */
2880 dw += 1 * 2;
2881 dh += 1 * 2;
2882 }
2883 #endif // __WXUNIVERSAL__
2884
2885 if (m_hasScrolling)
2886 {
2887 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2888
2889 GtkRequisition vscroll_req;
2890 vscroll_req.width = 2;
2891 vscroll_req.height = 2;
2892 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2893 (scroll_window->vscrollbar, &vscroll_req );
2894
2895 GtkRequisition hscroll_req;
2896 hscroll_req.width = 2;
2897 hscroll_req.height = 2;
2898 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2899 (scroll_window->hscrollbar, &hscroll_req );
2900
2901 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2902
2903 if (scroll_window->vscrollbar_visible)
2904 {
2905 dw += vscroll_req.width;
2906 dw += scroll_class->scrollbar_spacing;
2907 }
2908
2909 if (scroll_window->hscrollbar_visible)
2910 {
2911 dh += hscroll_req.height;
2912 dh += scroll_class->scrollbar_spacing;
2913 }
2914 }
2915
2916 SetSize( width+dw, height+dh );
2917 }
2918 }
2919
2920 void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
2921 {
2922 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2923
2924 if (!m_wxwindow)
2925 {
2926 if (width) (*width) = m_width;
2927 if (height) (*height) = m_height;
2928 }
2929 else
2930 {
2931 int dw = 0;
2932 int dh = 0;
2933
2934 #ifndef __WXUNIVERSAL__
2935 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2936 {
2937 /* when using GTK 1.2 we set the shadow border size to 2 */
2938 dw += 2 * 2;
2939 dh += 2 * 2;
2940 }
2941 if (HasFlag(wxSIMPLE_BORDER))
2942 {
2943 /* when using GTK 1.2 we set the simple border size to 1 */
2944 dw += 1 * 2;
2945 dh += 1 * 2;
2946 }
2947 #endif // __WXUNIVERSAL__
2948
2949 if (m_hasScrolling)
2950 {
2951 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2952
2953 GtkRequisition vscroll_req;
2954 vscroll_req.width = 2;
2955 vscroll_req.height = 2;
2956 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2957 (scroll_window->vscrollbar, &vscroll_req );
2958
2959 GtkRequisition hscroll_req;
2960 hscroll_req.width = 2;
2961 hscroll_req.height = 2;
2962 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2963 (scroll_window->hscrollbar, &hscroll_req );
2964
2965 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2966
2967 if (scroll_window->vscrollbar_visible)
2968 {
2969 dw += vscroll_req.width;
2970 dw += scroll_class->scrollbar_spacing;
2971 }
2972
2973 if (scroll_window->hscrollbar_visible)
2974 {
2975 dh += hscroll_req.height;
2976 dh += scroll_class->scrollbar_spacing;
2977 }
2978 }
2979
2980 if (width) (*width) = m_width - dw;
2981 if (height) (*height) = m_height - dh;
2982 }
2983
2984 /*
2985 printf( "GetClientSize, name %s ", GetName().c_str() );
2986 if (width) printf( " width = %d", (*width) );
2987 if (height) printf( " height = %d", (*height) );
2988 printf( "\n" );
2989 */
2990 }
2991
2992 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
2993 {
2994 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2995
2996 int dx = 0;
2997 int dy = 0;
2998 if (m_parent && m_parent->m_wxwindow)
2999 {
3000 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3001 dx = pizza->xoffset;
3002 dy = pizza->yoffset;
3003 }
3004
3005 if (x) (*x) = m_x - dx;
3006 if (y) (*y) = m_y - dy;
3007 }
3008
3009 void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
3010 {
3011 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3012
3013 if (!m_widget->window) return;
3014
3015 GdkWindow *source = (GdkWindow *) NULL;
3016 if (m_wxwindow)
3017 source = GTK_PIZZA(m_wxwindow)->bin_window;
3018 else
3019 source = m_widget->window;
3020
3021 int org_x = 0;
3022 int org_y = 0;
3023 gdk_window_get_origin( source, &org_x, &org_y );
3024
3025 if (!m_wxwindow)
3026 {
3027 if (GTK_WIDGET_NO_WINDOW (m_widget))
3028 {
3029 org_x += m_widget->allocation.x;
3030 org_y += m_widget->allocation.y;
3031 }
3032 }
3033
3034 if (x) *x += org_x;
3035 if (y) *y += org_y;
3036 }
3037
3038 void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
3039 {
3040 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3041
3042 if (!m_widget->window) return;
3043
3044 GdkWindow *source = (GdkWindow *) NULL;
3045 if (m_wxwindow)
3046 source = GTK_PIZZA(m_wxwindow)->bin_window;
3047 else
3048 source = m_widget->window;
3049
3050 int org_x = 0;
3051 int org_y = 0;
3052 gdk_window_get_origin( source, &org_x, &org_y );
3053
3054 if (!m_wxwindow)
3055 {
3056 if (GTK_WIDGET_NO_WINDOW (m_widget))
3057 {
3058 org_x += m_widget->allocation.x;
3059 org_y += m_widget->allocation.y;
3060 }
3061 }
3062
3063 if (x) *x -= org_x;
3064 if (y) *y -= org_y;
3065 }
3066
3067 bool wxWindowGTK::Show( bool show )
3068 {
3069 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3070
3071 if (!wxWindowBase::Show(show))
3072 {
3073 // nothing to do
3074 return FALSE;
3075 }
3076
3077 if (show)
3078 gtk_widget_show( m_widget );
3079 else
3080 gtk_widget_hide( m_widget );
3081
3082 return TRUE;
3083 }
3084
3085 static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
3086 {
3087 win->OnParentEnable(enable);
3088
3089 // Recurse, so that children have the opportunity to Do The Right Thing
3090 // and reset colours that have been messed up by a parent's (really ancestor's)
3091 // Enable call
3092 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
3093 node;
3094 node = node->GetNext() )
3095 {
3096 wxWindow *child = node->GetData();
3097 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3098 wxWindowNotifyEnable(child, enable);
3099 }
3100 }
3101
3102 bool wxWindowGTK::Enable( bool enable )
3103 {
3104 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3105
3106 if (!wxWindowBase::Enable(enable))
3107 {
3108 // nothing to do
3109 return FALSE;
3110 }
3111
3112 gtk_widget_set_sensitive( m_widget, enable );
3113 if ( m_wxwindow )
3114 gtk_widget_set_sensitive( m_wxwindow, enable );
3115
3116 wxWindowNotifyEnable(this, enable);
3117
3118 return TRUE;
3119 }
3120
3121 int wxWindowGTK::GetCharHeight() const
3122 {
3123 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
3124
3125 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
3126
3127 GdkFont *font = m_font.GetInternalFont( 1.0 );
3128
3129 return font->ascent + font->descent;
3130 }
3131
3132 int wxWindowGTK::GetCharWidth() const
3133 {
3134 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
3135
3136 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
3137
3138 GdkFont *font = m_font.GetInternalFont( 1.0 );
3139
3140 return gdk_string_width( font, "H" );
3141 }
3142
3143 void wxWindowGTK::GetTextExtent( const wxString& string,
3144 int *x,
3145 int *y,
3146 int *descent,
3147 int *externalLeading,
3148 const wxFont *theFont ) const
3149 {
3150 wxFont fontToUse = m_font;
3151 if (theFont) fontToUse = *theFont;
3152
3153 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
3154
3155 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3156 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
3157 if (y) (*y) = font->ascent + font->descent;
3158 if (descent) (*descent) = font->descent;
3159 if (externalLeading) (*externalLeading) = 0; // ??
3160 }
3161
3162 void wxWindowGTK::SetFocus()
3163 {
3164 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3165
3166 #if 0
3167 wxPrintf( "SetFocus from " );
3168 if (GetClassInfo() && GetClassInfo()->GetClassName())
3169 wxPrintf( GetClassInfo()->GetClassName() );
3170 wxPrintf( ".\n" );
3171 #endif
3172
3173 if (m_wxwindow)
3174 {
3175 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3176 {
3177 // see comment in gtk_window_focus_out_callback()
3178 gs_widgetLastFocus = m_wxwindow;
3179 gtk_widget_grab_focus (m_wxwindow);
3180 }
3181 }
3182 else if (m_widget)
3183 {
3184 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3185 {
3186 gtk_widget_grab_focus (m_widget);
3187 }
3188 else if (GTK_IS_CONTAINER(m_widget))
3189 {
3190 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3191 }
3192 else
3193 {
3194 // ?
3195 }
3196 }
3197
3198 #if 0
3199 wxPrintf( "SetFocus finished in " );
3200 if (GetClassInfo() && GetClassInfo()->GetClassName())
3201 wxPrintf( GetClassInfo()->GetClassName() );
3202 wxPrintf( ".\n" );
3203 #endif
3204
3205 }
3206
3207 bool wxWindowGTK::AcceptsFocus() const
3208 {
3209 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3210 }
3211
3212 bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
3213 {
3214 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3215
3216 wxWindowGTK *oldParent = m_parent,
3217 *newParent = (wxWindowGTK *)newParentBase;
3218
3219 wxASSERT( GTK_IS_WIDGET(m_widget) );
3220
3221 if ( !wxWindowBase::Reparent(newParent) )
3222 return FALSE;
3223
3224 wxASSERT( GTK_IS_WIDGET(m_widget) );
3225
3226 /* prevent GTK from deleting the widget arbitrarily */
3227 gtk_widget_ref( m_widget );
3228
3229 if (oldParent)
3230 {
3231 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3232 }
3233
3234 wxASSERT( GTK_IS_WIDGET(m_widget) );
3235
3236 if (newParent)
3237 {
3238 /* insert GTK representation */
3239 (*(newParent->m_insertCallback))(newParent, this);
3240 }
3241
3242 /* reverse: prevent GTK from deleting the widget arbitrarily */
3243 gtk_widget_unref( m_widget );
3244
3245 return TRUE;
3246 }
3247
3248 void wxWindowGTK::DoAddChild(wxWindowGTK *child)
3249 {
3250 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3251
3252 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3253
3254 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3255
3256 /* add to list */
3257 AddChild( child );
3258
3259 /* insert GTK representation */
3260 (*m_insertCallback)(this, child);
3261 }
3262
3263 void wxWindowGTK::Raise()
3264 {
3265 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3266
3267 if (!m_widget->window) return;
3268
3269 gdk_window_raise( m_widget->window );
3270 }
3271
3272 void wxWindowGTK::Lower()
3273 {
3274 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3275
3276 if (!m_widget->window) return;
3277
3278 gdk_window_lower( m_widget->window );
3279 }
3280
3281 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
3282 {
3283 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3284
3285 if (cursor == m_cursor)
3286 return FALSE;
3287
3288 if (g_isIdle)
3289 wxapp_install_idle_handler();
3290
3291 if (cursor == wxNullCursor)
3292 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3293 else
3294 return wxWindowBase::SetCursor( cursor );
3295 }
3296
3297 void wxWindowGTK::WarpPointer( int x, int y )
3298 {
3299 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3300
3301 // We provide this function ourselves as it is
3302 // missing in GDK (top of this file).
3303
3304 GdkWindow *window = (GdkWindow*) NULL;
3305 if (m_wxwindow)
3306 window = GTK_PIZZA(m_wxwindow)->bin_window;
3307 else
3308 window = GetConnectWidget()->window;
3309
3310 if (window)
3311 gdk_window_warp_pointer( window, x, y );
3312 }
3313
3314 void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
3315 {
3316 if (!m_widget) return;
3317 if (!m_widget->window) return;
3318
3319 // temporarily hide the caret to avoid nasty interactions between caret
3320 // drawing and the window contents redraw
3321 #if 0 // def wxUSE_CARET -- doesn't seem to help :-(
3322 wxCaretSuspend cs((wxWindow *)this);
3323 #endif // wxUSE_CARET
3324
3325 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3326 {
3327 if (rect)
3328 {
3329 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3330 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
3331 }
3332 else
3333 {
3334 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3335 m_clearRegion.Clear();
3336 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3337 }
3338 }
3339
3340 if (rect)
3341 {
3342 if (m_wxwindow)
3343 {
3344 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3345 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
3346 }
3347 else
3348 {
3349 GdkRectangle gdk_rect;
3350 gdk_rect.x = rect->x;
3351 gdk_rect.y = rect->y;
3352 gdk_rect.width = rect->width;
3353 gdk_rect.height = rect->height;
3354 gtk_widget_draw( m_widget, &gdk_rect );
3355 }
3356 }
3357 else
3358 {
3359 if (m_wxwindow)
3360 {
3361 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3362 m_updateRegion.Clear();
3363 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3364 }
3365 else
3366 {
3367 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
3368 }
3369 }
3370 }
3371
3372 void wxWindowGTK::Update()
3373 {
3374 if (!m_updateRegion.IsEmpty())
3375 {
3376 GtkSendPaintEvents();
3377 }
3378 }
3379
3380 void wxWindowGTK::GtkSendPaintEvents()
3381 {
3382 if (!m_wxwindow)
3383 {
3384 m_clearRegion.Clear();
3385 m_updateRegion.Clear();
3386 return;
3387 }
3388
3389 m_clipPaintRegion = TRUE;
3390
3391 if (!m_clearRegion.IsEmpty())
3392 {
3393 wxWindowDC dc( (wxWindow*)this );
3394 dc.SetClippingRegion( m_clearRegion );
3395
3396 wxEraseEvent erase_event( GetId(), &dc );
3397 erase_event.SetEventObject( this );
3398
3399 if (!GetEventHandler()->ProcessEvent(erase_event))
3400 {
3401 wxRegionIterator upd( m_clearRegion );
3402 while (upd)
3403 {
3404 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
3405 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
3406 upd ++;
3407 }
3408 }
3409 m_clearRegion.Clear();
3410 }
3411
3412 wxNcPaintEvent nc_paint_event( GetId() );
3413 nc_paint_event.SetEventObject( this );
3414 GetEventHandler()->ProcessEvent( nc_paint_event );
3415
3416 wxPaintEvent paint_event( GetId() );
3417 paint_event.SetEventObject( this );
3418 GetEventHandler()->ProcessEvent( paint_event );
3419
3420 m_clipPaintRegion = FALSE;
3421
3422 #ifndef __WXUNIVERSAL__
3423 // The following code will result in all window-less widgets
3424 // being redrawn because the wxWindows class is allowed to
3425 // paint over the window-less widgets.
3426
3427 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3428
3429 GList *children = pizza->children;
3430 while (children)
3431 {
3432 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
3433 children = children->next;
3434
3435 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
3436 GTK_WIDGET_DRAWABLE (child->widget))
3437 {
3438 // Get intersection of widget area and update region
3439 wxRegion region( m_updateRegion );
3440
3441 GdkEventExpose gdk_event;
3442 gdk_event.type = GDK_EXPOSE;
3443 gdk_event.window = pizza->bin_window;
3444 gdk_event.count = 0;
3445
3446 wxRegionIterator upd( m_updateRegion );
3447 while (upd)
3448 {
3449 GdkRectangle rect;
3450 rect.x = upd.GetX();
3451 rect.y = upd.GetY();
3452 rect.width = upd.GetWidth();
3453 rect.height = upd.GetHeight();
3454
3455 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
3456 {
3457 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
3458 }
3459
3460 upd ++;
3461 }
3462 }
3463 }
3464 #endif
3465
3466 m_updateRegion.Clear();
3467 }
3468
3469 void wxWindowGTK::Clear()
3470 {
3471 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3472
3473 if (!m_widget->window) return;
3474
3475 if (m_wxwindow && m_wxwindow->window)
3476 {
3477 // gdk_window_clear( m_wxwindow->window );
3478 }
3479 }
3480
3481 #if wxUSE_TOOLTIPS
3482 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
3483 {
3484 wxWindowBase::DoSetToolTip(tip);
3485
3486 if (m_tooltip)
3487 m_tooltip->Apply( (wxWindow *)this );
3488 }
3489
3490 void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
3491 {
3492 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
3493 }
3494 #endif // wxUSE_TOOLTIPS
3495
3496 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
3497 {
3498 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3499
3500 if (!wxWindowBase::SetBackgroundColour(colour))
3501 {
3502 // don't leave if the GTK widget has just
3503 // been realized
3504 if (!m_delayedBackgroundColour) return FALSE;
3505 }
3506
3507 GdkWindow *window = (GdkWindow*) NULL;
3508 if (m_wxwindow)
3509 window = GTK_PIZZA(m_wxwindow)->bin_window;
3510 else
3511 window = GetConnectWidget()->window;
3512
3513 if (!window)
3514 {
3515 // indicate that a new style has been set
3516 // but it couldn't get applied as the
3517 // widget hasn't been realized yet.
3518 m_delayedBackgroundColour = TRUE;
3519 }
3520
3521 if ((m_wxwindow) &&
3522 (m_wxwindow->window) &&
3523 (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)))
3524 {
3525 /* wxMSW doesn't clear the window here. I don't do that either to
3526 provide compatibility. call Clear() to do the job. */
3527
3528 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
3529 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3530 }
3531
3532 ApplyWidgetStyle();
3533
3534 return TRUE;
3535 }
3536
3537 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
3538 {
3539 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3540
3541 if (!wxWindowBase::SetForegroundColour(colour))
3542 {
3543 // don't leave if the GTK widget has just
3544 // been realized
3545 if (!m_delayedForegroundColour) return FALSE;
3546 }
3547
3548 GdkWindow *window = (GdkWindow*) NULL;
3549 if (m_wxwindow)
3550 window = GTK_PIZZA(m_wxwindow)->bin_window;
3551 else
3552 window = GetConnectWidget()->window;
3553
3554 if (!window)
3555 {
3556 // indicate that a new style has been set
3557 // but it couldn't get applied as the
3558 // widget hasn't been realized yet.
3559 m_delayedForegroundColour = TRUE;
3560 }
3561
3562 ApplyWidgetStyle();
3563
3564 return TRUE;
3565 }
3566
3567 GtkStyle *wxWindowGTK::GetWidgetStyle()
3568 {
3569 if (m_widgetStyle)
3570 {
3571 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
3572 #ifdef __WXGTK20__
3573 /* FIXME: is this necessary? */
3574 _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
3575 #else
3576 remake->klass = m_widgetStyle->klass;
3577 #endif
3578
3579 gtk_style_unref( m_widgetStyle );
3580 m_widgetStyle = remake;
3581 }
3582 else
3583 {
3584 GtkStyle *def = gtk_rc_get_style( m_widget );
3585
3586 if (!def)
3587 def = gtk_widget_get_default_style();
3588
3589 m_widgetStyle = gtk_style_copy( def );
3590 #ifdef __WXGTK20__
3591 /* FIXME: is this necessary? */
3592 _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
3593 #else
3594 m_widgetStyle->klass = def->klass;
3595 #endif
3596 }
3597
3598 return m_widgetStyle;
3599 }
3600
3601 void wxWindowGTK::SetWidgetStyle()
3602 {
3603 #if DISABLE_STYLE_IF_BROKEN_THEME
3604 if (m_widget->style->engine_data)
3605 {
3606 static bool s_warningPrinted = FALSE;
3607 if (!s_warningPrinted)
3608 {
3609 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3610 s_warningPrinted = TRUE;
3611 }
3612 m_widgetStyle = m_widget->style;
3613 return;
3614 }
3615 #endif
3616
3617 GtkStyle *style = GetWidgetStyle();
3618
3619 if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ))
3620 {
3621 gdk_font_unref( style->font );
3622 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3623 }
3624
3625 if (m_foregroundColour.Ok())
3626 {
3627 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3628 if (m_foregroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT))
3629 {
3630 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3631 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3632 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3633 }
3634 else
3635 {
3636 // Try to restore the gtk default style. This is still a little
3637 // oversimplified for what is probably really needed here for controls
3638 // other than buttons, but is better than not being able to (re)set a
3639 // control's foreground colour to *wxBLACK -- RL
3640 GtkStyle *def = gtk_rc_get_style( m_widget );
3641
3642 if (!def)
3643 def = gtk_widget_get_default_style();
3644
3645 style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL];
3646 style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT];
3647 style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE];
3648 }
3649 }
3650
3651 if (m_backgroundColour.Ok())
3652 {
3653 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3654 if (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE))
3655 {
3656 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3657 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3658 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3659 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3660 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3661 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3662 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3663 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3664 }
3665 else
3666 {
3667 // Try to restore the gtk default style. This is still a little
3668 // oversimplified for what is probably really needed here for controls
3669 // other than buttons, but is better than not being able to (re)set a
3670 // control's background colour to default grey and means resetting a
3671 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3672 // behavior -- RL
3673 GtkStyle *def = gtk_rc_get_style( m_widget );
3674
3675 if (!def)
3676 def = gtk_widget_get_default_style();
3677
3678 style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL];
3679 style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL];
3680 style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT];
3681 style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT];
3682 style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE];
3683 style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE];
3684 style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE];
3685 style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE];
3686 }
3687 }
3688 }
3689
3690 void wxWindowGTK::ApplyWidgetStyle()
3691 {
3692 }
3693
3694 //-----------------------------------------------------------------------------
3695 // Pop-up menu stuff
3696 //-----------------------------------------------------------------------------
3697
3698 #if wxUSE_MENUS_NATIVE
3699
3700 extern "C"
3701 void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
3702 {
3703 *is_waiting = FALSE;
3704 }
3705
3706 static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
3707 {
3708 menu->SetInvokingWindow( win );
3709 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
3710 while (node)
3711 {
3712 wxMenuItem *menuitem = node->GetData();
3713 if (menuitem->IsSubMenu())
3714 {
3715 SetInvokingWindow( menuitem->GetSubMenu(), win );
3716 }
3717
3718 node = node->GetNext();
3719 }
3720 }
3721
3722 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3723 // wxPopupMenuPositionCallback()
3724 //
3725 // should be safe even in the MT case as the user can hardly popup 2 menus
3726 // simultaneously, can he?
3727 static gint gs_pop_x = 0;
3728 static gint gs_pop_y = 0;
3729
3730 extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
3731 gint *x, gint *y,
3732 gpointer WXUNUSED(user_data) )
3733 {
3734 // ensure that the menu appears entirely on screen
3735 GtkRequisition req;
3736 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
3737
3738 wxSize sizeScreen = wxGetDisplaySize();
3739
3740 gint xmax = sizeScreen.x - req.width,
3741 ymax = sizeScreen.y - req.height;
3742
3743 *x = gs_pop_x < xmax ? gs_pop_x : xmax;
3744 *y = gs_pop_y < ymax ? gs_pop_y : ymax;
3745 }
3746
3747 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
3748 {
3749 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3750
3751 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
3752
3753 SetInvokingWindow( menu, this );
3754
3755 menu->UpdateUI();
3756
3757 gs_pop_x = x;
3758 gs_pop_y = y;
3759 ClientToScreen( &gs_pop_x, &gs_pop_y );
3760
3761 bool is_waiting = TRUE;
3762
3763 gtk_signal_connect( GTK_OBJECT(menu->m_menu),
3764 "hide",
3765 GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
3766 (gpointer)&is_waiting );
3767
3768 gtk_menu_popup(
3769 GTK_MENU(menu->m_menu),
3770 (GtkWidget *) NULL, // parent menu shell
3771 (GtkWidget *) NULL, // parent menu item
3772 wxPopupMenuPositionCallback, // function to position it
3773 NULL, // client data
3774 0, // button used to activate it
3775 gs_timeLastClick // the time of activation
3776 );
3777
3778 while (is_waiting)
3779 {
3780 while (gtk_events_pending())
3781 gtk_main_iteration();
3782 }
3783
3784 return TRUE;
3785 }
3786
3787 #endif // wxUSE_MENUS_NATIVE
3788
3789 #if wxUSE_DRAG_AND_DROP
3790
3791 void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
3792 {
3793 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3794
3795 GtkWidget *dnd_widget = GetConnectWidget();
3796
3797 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3798
3799 if (m_dropTarget) delete m_dropTarget;
3800 m_dropTarget = dropTarget;
3801
3802 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3803 }
3804
3805 #endif // wxUSE_DRAG_AND_DROP
3806
3807 GtkWidget* wxWindowGTK::GetConnectWidget()
3808 {
3809 GtkWidget *connect_widget = m_widget;
3810 if (m_wxwindow) connect_widget = m_wxwindow;
3811
3812 return connect_widget;
3813 }
3814
3815 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
3816 {
3817 if (m_wxwindow)
3818 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3819
3820 return (window == m_widget->window);
3821 }
3822
3823 bool wxWindowGTK::SetFont( const wxFont &font )
3824 {
3825 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3826
3827 if (!wxWindowBase::SetFont(font))
3828 {
3829 return FALSE;
3830 }
3831
3832 wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
3833 if ( sysbg == m_backgroundColour )
3834 {
3835 m_backgroundColour = wxNullColour;
3836 ApplyWidgetStyle();
3837 m_backgroundColour = sysbg;
3838 }
3839 else
3840 {
3841 ApplyWidgetStyle();
3842 }
3843
3844 return TRUE;
3845 }
3846
3847 void wxWindowGTK::DoCaptureMouse()
3848 {
3849 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3850
3851 GdkWindow *window = (GdkWindow*) NULL;
3852 if (m_wxwindow)
3853 window = GTK_PIZZA(m_wxwindow)->bin_window;
3854 else
3855 window = GetConnectWidget()->window;
3856
3857 wxCHECK_RET( window, _T("CaptureMouse() failed") );
3858
3859 wxCursor* cursor = & m_cursor;
3860 if (!cursor->Ok())
3861 cursor = wxSTANDARD_CURSOR;
3862
3863 gdk_pointer_grab( window, FALSE,
3864 (GdkEventMask)
3865 (GDK_BUTTON_PRESS_MASK |
3866 GDK_BUTTON_RELEASE_MASK |
3867 GDK_POINTER_MOTION_HINT_MASK |
3868 GDK_POINTER_MOTION_MASK),
3869 (GdkWindow *) NULL,
3870 cursor->GetCursor(),
3871 (guint32)GDK_CURRENT_TIME );
3872 g_captureWindow = this;
3873 g_captureWindowHasMouse = TRUE;
3874 }
3875
3876 void wxWindowGTK::DoReleaseMouse()
3877 {
3878 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3879
3880 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
3881
3882 g_captureWindow = (wxWindowGTK*) NULL;
3883
3884 GdkWindow *window = (GdkWindow*) NULL;
3885 if (m_wxwindow)
3886 window = GTK_PIZZA(m_wxwindow)->bin_window;
3887 else
3888 window = GetConnectWidget()->window;
3889
3890 if (!window)
3891 return;
3892
3893 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3894 }
3895
3896 /* static */
3897 wxWindow *wxWindowBase::GetCapture()
3898 {
3899 return (wxWindow *)g_captureWindow;
3900 }
3901
3902 bool wxWindowGTK::IsRetained() const
3903 {
3904 return FALSE;
3905 }
3906
3907 void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
3908 int range, bool refresh )
3909 {
3910 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3911
3912 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3913
3914 m_hasScrolling = TRUE;
3915
3916 if (orient == wxHORIZONTAL)
3917 {
3918 float fpos = (float)pos;
3919 float frange = (float)range;
3920 float fthumb = (float)thumbVisible;
3921 if (fpos > frange-fthumb) fpos = frange-fthumb;
3922 if (fpos < 0.0) fpos = 0.0;
3923
3924 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3925 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3926 {
3927 SetScrollPos( orient, pos, refresh );
3928 return;
3929 }
3930
3931 m_oldHorizontalPos = fpos;
3932
3933 m_hAdjust->lower = 0.0;
3934 m_hAdjust->upper = frange;
3935 m_hAdjust->value = fpos;
3936 m_hAdjust->step_increment = 1.0;
3937 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3938 m_hAdjust->page_size = fthumb;
3939 }
3940 else
3941 {
3942 float fpos = (float)pos;
3943 float frange = (float)range;
3944 float fthumb = (float)thumbVisible;
3945 if (fpos > frange-fthumb) fpos = frange-fthumb;
3946 if (fpos < 0.0) fpos = 0.0;
3947
3948 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3949 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3950 {
3951 SetScrollPos( orient, pos, refresh );
3952 return;
3953 }
3954
3955 m_oldVerticalPos = fpos;
3956
3957 m_vAdjust->lower = 0.0;
3958 m_vAdjust->upper = frange;
3959 m_vAdjust->value = fpos;
3960 m_vAdjust->step_increment = 1.0;
3961 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3962 m_vAdjust->page_size = fthumb;
3963 }
3964
3965 if (orient == wxHORIZONTAL)
3966 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3967 else
3968 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3969 }
3970
3971 void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3972 {
3973 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3974
3975 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3976
3977 if (orient == wxHORIZONTAL)
3978 {
3979 float fpos = (float)pos;
3980 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3981 if (fpos < 0.0) fpos = 0.0;
3982 m_oldHorizontalPos = fpos;
3983
3984 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3985 m_hAdjust->value = fpos;
3986 }
3987 else
3988 {
3989 float fpos = (float)pos;
3990 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3991 if (fpos < 0.0) fpos = 0.0;
3992 m_oldVerticalPos = fpos;
3993
3994 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3995 m_vAdjust->value = fpos;
3996 }
3997
3998 if (m_wxwindow->window)
3999 {
4000 if (orient == wxHORIZONTAL)
4001 {
4002 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
4003 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4004
4005 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
4006
4007 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
4008 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4009 }
4010 else
4011 {
4012 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
4013 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4014
4015 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
4016
4017 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
4018 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4019 }
4020 }
4021 }
4022
4023 int wxWindowGTK::GetScrollThumb( int orient ) const
4024 {
4025 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4026
4027 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4028
4029 if (orient == wxHORIZONTAL)
4030 return (int)(m_hAdjust->page_size+0.5);
4031 else
4032 return (int)(m_vAdjust->page_size+0.5);
4033 }
4034
4035 int wxWindowGTK::GetScrollPos( int orient ) const
4036 {
4037 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4038
4039 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4040
4041 if (orient == wxHORIZONTAL)
4042 return (int)(m_hAdjust->value+0.5);
4043 else
4044 return (int)(m_vAdjust->value+0.5);
4045 }
4046
4047 int wxWindowGTK::GetScrollRange( int orient ) const
4048 {
4049 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4050
4051 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4052
4053 if (orient == wxHORIZONTAL)
4054 return (int)(m_hAdjust->upper+0.5);
4055 else
4056 return (int)(m_vAdjust->upper+0.5);
4057 }
4058
4059 void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
4060 {
4061 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4062
4063 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4064
4065 // No scrolling requested.
4066 if ((dx == 0) && (dy == 0)) return;
4067
4068 if (!m_updateRegion.IsEmpty())
4069 {
4070 m_updateRegion.Offset( dx, dy );
4071
4072 int cw = 0;
4073 int ch = 0;
4074 GetClientSize( &cw, &ch );
4075 m_updateRegion.Intersect( 0, 0, cw, ch );
4076 }
4077
4078 if (!m_clearRegion.IsEmpty())
4079 {
4080 m_clearRegion.Offset( dx, dy );
4081
4082 int cw = 0;
4083 int ch = 0;
4084 GetClientSize( &cw, &ch );
4085 m_clearRegion.Intersect( 0, 0, cw, ch );
4086 }
4087
4088 #if 1
4089
4090 m_clipPaintRegion = TRUE;
4091
4092 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4093
4094 m_clipPaintRegion = FALSE;
4095
4096 #else
4097
4098 if (m_children.GetCount() > 0)
4099 {
4100 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4101 }
4102 else
4103 {
4104 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
4105
4106 pizza->xoffset -= dx;
4107 pizza->yoffset -= dy;
4108
4109 GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
4110 gdk_gc_set_exposures( m_scrollGC, TRUE );
4111
4112 int cw = 0;
4113 int ch = 0;
4114 GetClientSize( &cw, &ch );
4115 int w = cw - abs(dx);
4116 int h = ch - abs(dy);
4117
4118 if ((h < 0) || (w < 0))
4119 {
4120 Refresh();
4121 }
4122 else
4123 {
4124 int s_x = 0;
4125 int s_y = 0;
4126 if (dx < 0) s_x = -dx;
4127 if (dy < 0) s_y = -dy;
4128 int d_x = 0;
4129 int d_y = 0;
4130 if (dx > 0) d_x = dx;
4131 if (dy > 0) d_y = dy;
4132
4133 gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
4134 pizza->bin_window, s_x, s_y, w, h );
4135
4136 wxRect rect;
4137 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
4138 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
4139 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
4140 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
4141
4142 Refresh( TRUE, &rect );
4143 }
4144
4145 gdk_gc_unref( m_scrollGC );
4146 }
4147 #endif
4148 }
4149
4150 // Find the wxWindow at the current mouse position, also returning the mouse
4151 // position.
4152 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4153 {
4154 pt = wxGetMousePosition();
4155 wxWindow* found = wxFindWindowAtPoint(pt);
4156 return found;
4157 }
4158
4159 // Get the current mouse position.
4160 wxPoint wxGetMousePosition()
4161 {
4162 /* This crashes when used within wxHelpContext,
4163 so we have to use the X-specific implementation below.
4164 gint x, y;
4165 GdkModifierType *mask;
4166 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4167
4168 return wxPoint(x, y);
4169 */
4170
4171 int x, y;
4172 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
4173 if (!windowAtPtr)
4174 return wxPoint(-999, -999);
4175
4176 Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
4177 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4178 Window rootReturn, childReturn;
4179 int rootX, rootY, winX, winY;
4180 unsigned int maskReturn;
4181
4182 XQueryPointer (display,
4183 rootWindow,
4184 &rootReturn,
4185 &childReturn,
4186 &rootX, &rootY, &winX, &winY, &maskReturn);
4187 return wxPoint(rootX, rootY);
4188
4189 }
4190