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