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