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