1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/window.cpp 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling, Julian Smart 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  14 #define XWarpPointer XWARPPOINTER 
  17 #include "wx/window.h" 
  23     #include "wx/dcclient.h" 
  25     #include "wx/settings.h" 
  26     #include "wx/msgdlg.h" 
  27     #include "wx/textctrl.h" 
  28     #include "wx/radiobut.h" 
  29     #include "wx/toolbar.h" 
  30     #include "wx/combobox.h" 
  31     #include "wx/layout.h" 
  36 #include "wx/tooltip.h" 
  38 #include "wx/fontutil.h" 
  41     #include "wx/thread.h" 
  46 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0 
  47 #include <gtk/gtkversion.h> 
  48 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0) 
  49     #undef GTK_DISABLE_DEPRECATED 
  50     #include <gtk/gtkcombo.h> 
  51     #define GTK_DISABLE_DEPRECATED 
  54 #include "wx/gtk/private.h" 
  55 #include "wx/gtk/win_gtk.h" 
  56 #include <gdk/gdkkeysyms.h> 
  59 //----------------------------------------------------------------------------- 
  60 // documentation on internals 
  61 //----------------------------------------------------------------------------- 
  64    I have been asked several times about writing some documentation about 
  65    the GTK port of wxWidgets, especially its internal structures. Obviously, 
  66    you cannot understand wxGTK without knowing a little about the GTK, but 
  67    some more information about what the wxWindow, which is the base class 
  68    for all other window classes, does seems required as well. 
  72    What does wxWindow do? It contains the common interface for the following 
  73    jobs of its descendants: 
  75    1) Define the rudimentary behaviour common to all window classes, such as 
  76    resizing, intercepting user input (so as to make it possible to use these 
  77    events for special purposes in a derived class), window names etc. 
  79    2) Provide the possibility to contain and manage children, if the derived 
  80    class is allowed to contain children, which holds true for those window 
  81    classes which do not display a native GTK widget. To name them, these 
  82    classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame- 
  83    work classes are a special case and are handled a bit differently from 
  84    the rest. The same holds true for the wxNotebook class. 
  86    3) Provide the possibility to draw into a client area of a window. This, 
  87    too, only holds true for classes that do not display a native GTK widget 
  90    4) Provide the entire mechanism for scrolling widgets. This actual inter- 
  91    face for this is usually in wxScrolledWindow, but the GTK implementation 
  94    5) A multitude of helper or extra methods for special purposes, such as 
  95    Drag'n'Drop, managing validators etc. 
  97    6) Display a border (sunken, raised, simple or none). 
  99    Normally one might expect, that one wxWidgets window would always correspond 
 100    to one GTK widget. Under GTK, there is no such all-round widget that has all 
 101    the functionality. Moreover, the GTK defines a client area as a different 
 102    widget from the actual widget you are handling. Last but not least some 
 103    special classes (e.g. wxFrame) handle different categories of widgets and 
 104    still have the possibility to draw something in the client area. 
 105    It was therefore required to write a special purpose GTK widget, that would 
 106    represent a client area in the sense of wxWidgets capable to do the jobs 
 107    2), 3) and 4). I have written this class and it resides in win_gtk.c of 
 110    All windows must have a widget, with which they interact with other under- 
 111    lying GTK widgets. It is this widget, e.g. that has to be resized etc and 
 112    the wxWindow class has a member variable called m_widget which holds a 
 113    pointer to this widget. When the window class represents a GTK native widget, 
 114    this is (in most cases) the only GTK widget the class manages. E.g. the 
 115    wxStaticText class handles only a GtkLabel widget a pointer to which you 
 116    can find in m_widget (defined in wxWindow) 
 118    When the class has a client area for drawing into and for containing children 
 119    it has to handle the client area widget (of the type GtkPizza, defined in 
 120    win_gtk.c), but there could be any number of widgets, handled by a class 
 121    The common rule for all windows is only, that the widget that interacts with 
 122    the rest of GTK must be referenced in m_widget and all other widgets must be 
 123    children of this widget on the GTK level. The top-most widget, which also 
 124    represents the client area, must be in the m_wxwindow field and must be of 
 127    As I said, the window classes that display a GTK native widget only have 
 128    one widget, so in the case of e.g. the wxButton class m_widget holds a 
 129    pointer to a GtkButton widget. But windows with client areas (for drawing 
 130    and children) have a m_widget field that is a pointer to a GtkScrolled- 
 131    Window and a m_wxwindow field that is pointer to a GtkPizza and this 
 132    one is (in the GTK sense) a child of the GtkScrolledWindow. 
 134    If the m_wxwindow field is set, then all input to this widget is inter- 
 135    cepted and sent to the wxWidgets class. If not, all input to the widget 
 136    that gets pointed to by m_widget gets intercepted and sent to the class. 
 140    The design of scrolling in wxWidgets is markedly different from that offered 
 141    by the GTK itself and therefore we cannot simply take it as it is. In GTK, 
 142    clicking on a scrollbar belonging to scrolled window will inevitably move 
 143    the window. In wxWidgets, the scrollbar will only emit an event, send this 
 144    to (normally) a wxScrolledWindow and that class will call ScrollWindow() 
 145    which actually moves the window and its sub-windows. Note that GtkPizza 
 146    memorizes how much it has been scrolled but that wxWidgets forgets this 
 147    so that the two coordinates systems have to be kept in synch. This is done 
 148    in various places using the pizza->xoffset and pizza->yoffset values. 
 152    Singularly the most broken code in GTK is the code that is supposed to 
 153    inform subwindows (child windows) about new positions. Very often, duplicate 
 154    events are sent without changes in size or position, equally often no 
 155    events are sent at all (All this is due to a bug in the GtkContainer code 
 156    which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores 
 157    GTK's own system and it simply waits for size events for toplevel windows 
 158    and then iterates down the respective size events to all window. This has 
 159    the disadvantage that windows might get size events before the GTK widget 
 160    actually has the reported size. This doesn't normally pose any problem, but 
 161    the OpenGL drawing routines rely on correct behaviour. Therefore, I have 
 162    added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas, 
 163    i.e. the wxGLCanvas will emit a size event, when (and not before) the X11 
 164    window that is used for OpenGL output really has that size (as reported by 
 169    If someone at some point of time feels the immense desire to have a look at, 
 170    change or attempt to optimise the Refresh() logic, this person will need an 
 171    intimate understanding of what "draw" and "expose" events are and what 
 172    they are used for, in particular when used in connection with GTK's 
 173    own windowless widgets. Beware. 
 177    Cursors, too, have been a constant source of pleasure. The main difficulty 
 178    is that a GdkWindow inherits a cursor if the programmer sets a new cursor 
 179    for the parent. To prevent this from doing too much harm, I use idle time 
 180    to set the cursor over and over again, starting from the toplevel windows 
 181    and ending with the youngest generation (speaking of parent and child windows). 
 182    Also don't forget that cursors (like much else) are connected to GdkWindows, 
 183    not GtkWidgets and that the "window" field of a GtkWidget might very well 
 184    point to the GdkWindow of the parent widget (-> "window-less widget") and 
 185    that the two obviously have very different meanings. 
 189 //----------------------------------------------------------------------------- 
 191 //----------------------------------------------------------------------------- 
 193 extern bool       g_blockEventsOnDrag
; 
 194 extern bool       g_blockEventsOnScroll
; 
 195 extern wxCursor   g_globalCursor
; 
 197 // mouse capture state: the window which has it and if the mouse is currently 
 199 static wxWindowGTK  
*g_captureWindow 
= (wxWindowGTK
*) NULL
; 
 200 static bool g_captureWindowHasMouse 
= false; 
 202 wxWindowGTK  
*g_focusWindow 
= (wxWindowGTK
*) NULL
; 
 204 // the last window which had the focus - this is normally never NULL (except 
 205 // if we never had focus at all) as even when g_focusWindow is NULL it still 
 206 // keeps its previous value 
 207 wxWindowGTK 
*g_focusWindowLast 
= (wxWindowGTK
*) NULL
; 
 209 // If a window get the focus set but has not been realized 
 210 // yet, defer setting the focus to idle time. 
 211 wxWindowGTK 
*g_delayedFocus 
= (wxWindowGTK
*) NULL
; 
 213 extern bool g_mainThreadLocked
; 
 215 //----------------------------------------------------------------------------- 
 217 //----------------------------------------------------------------------------- 
 222 #   define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance"); 
 224 #   define DEBUG_MAIN_THREAD 
 227 #define DEBUG_MAIN_THREAD 
 230 // the trace mask used for the focus debugging messages 
 231 #define TRACE_FOCUS _T("focus") 
 233 //----------------------------------------------------------------------------- 
 234 // missing gdk functions 
 235 //----------------------------------------------------------------------------- 
 238 gdk_window_warp_pointer (GdkWindow      
*window
, 
 243     window 
= gdk_get_default_root_window(); 
 245   if (!GDK_WINDOW_DESTROYED(window
)) 
 247       XWarpPointer (GDK_WINDOW_XDISPLAY(window
), 
 248                     None
,              /* not source window -> move from anywhere */ 
 249                     GDK_WINDOW_XID(window
),  /* dest window */ 
 250                     0, 0, 0, 0,        /* not source window -> move from anywhere */ 
 255 //----------------------------------------------------------------------------- 
 256 // local code (see below) 
 257 //----------------------------------------------------------------------------- 
 259 // returns the child of win which currently has focus or NULL if not found 
 261 // Note: can't be static, needed by textctrl.cpp. 
 262 wxWindow 
*wxFindFocusedChild(wxWindowGTK 
*win
) 
 264     wxWindow 
*winFocus 
= wxWindowGTK::FindFocus(); 
 266         return (wxWindow 
*)NULL
; 
 268     if ( winFocus 
== win 
) 
 269         return (wxWindow 
*)win
; 
 271     for ( wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
 273           node 
= node
->GetNext() ) 
 275         wxWindow 
*child 
= wxFindFocusedChild(node
->GetData()); 
 280     return (wxWindow 
*)NULL
; 
 283 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
) 
 285     GtkScrolledWindow
* scroll_window 
= GTK_SCROLLED_WINDOW(widget
); 
 286     GtkScrolledWindowClass
* scroll_class 
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
)); 
 287     GtkRequisition scroll_req
; 
 290     if (scroll_window
->vscrollbar_visible
) 
 292         scroll_req
.width 
= 2; 
 293         scroll_req
.height 
= 2; 
 294         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request 
) 
 295             (scroll_window
->vscrollbar
, &scroll_req 
); 
 296         w 
= scroll_req
.width 
+ 
 297             scroll_class
->scrollbar_spacing
; 
 301     if (scroll_window
->hscrollbar_visible
) 
 303         scroll_req
.width 
= 2; 
 304         scroll_req
.height 
= 2; 
 305         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request 
) 
 306             (scroll_window
->hscrollbar
, &scroll_req 
); 
 307         h 
= scroll_req
.height 
+ 
 308             scroll_class
->scrollbar_spacing
; 
 312 static void draw_frame( GtkWidget 
*widget
, wxWindowGTK 
*win 
) 
 314     // wxUniversal widgets draw the borders and scrollbars themselves 
 315 #ifndef __WXUNIVERSAL__ 
 321     if (GTK_WIDGET_NO_WINDOW (widget
)) 
 323         dx 
+= widget
->allocation
.x
; 
 324         dy 
+= widget
->allocation
.y
; 
 332     if (win
->m_hasScrolling
) 
 334         GetScrollbarWidth(widget
, dw
, dh
); 
 336         if (win
->GetLayoutDirection() == wxLayout_RightToLeft
) 
 338             // This is actually wrong for old GTK+ version 
 339             // which do not display the scrollbar on the 
 345     int w 
= widget
->allocation
.width
-dw
; 
 346     int h 
= widget
->allocation
.height
-dh
; 
 348     if (win
->HasFlag(wxRAISED_BORDER
)) 
 350         gtk_paint_shadow (widget
->style
, 
 354                           NULL
, NULL
, NULL
, // FIXME: No clipping? 
 359     if (win
->HasFlag(wxSUNKEN_BORDER
)) 
 361         gtk_paint_shadow (widget
->style
, 
 365                           NULL
, NULL
, NULL
, // FIXME: No clipping? 
 370     if (win
->HasFlag(wxSIMPLE_BORDER
)) 
 373         gc 
= gdk_gc_new( widget
->window 
); 
 374         gdk_gc_set_foreground( gc
, &widget
->style
->black 
); 
 375         gdk_draw_rectangle( widget
->window
, gc
, FALSE
, x
, y
, w
-1, h
-1 ); 
 379 #endif // __WXUNIVERSAL__ 
 382 //----------------------------------------------------------------------------- 
 383 // "expose_event" of m_widget 
 384 //----------------------------------------------------------------------------- 
 388 gtk_window_own_expose_callback( GtkWidget 
*widget
, 
 389                                 GdkEventExpose 
*gdk_event
, 
 392     if (gdk_event
->count 
== 0) 
 393         draw_frame(widget
, win
); 
 398 //----------------------------------------------------------------------------- 
 399 // "size_request" of m_widget 
 400 //----------------------------------------------------------------------------- 
 402 // make it extern because wxStaticText needs to disconnect this one 
 404 void wxgtk_window_size_request_callback(GtkWidget 
*widget
, 
 405                                         GtkRequisition 
*requisition
, 
 409     win
->GetSize( &w
, &h 
); 
 415     requisition
->height 
= h
; 
 416     requisition
->width 
= w
; 
 422 void wxgtk_combo_size_request_callback(GtkWidget 
*widget
, 
 423                                        GtkRequisition 
*requisition
, 
 426     // This callback is actually hooked into the text entry 
 427     // of the combo box, not the GtkHBox. 
 430     win
->GetSize( &w
, &h 
); 
 436     GtkCombo 
*gcombo 
= GTK_COMBO(win
->m_widget
); 
 438     GtkRequisition entry_req
; 
 440     entry_req
.height 
= 2; 
 441     (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->entry
) )->size_request 
) 
 442         (gcombo
->entry
, &entry_req 
); 
 444     GtkRequisition button_req
; 
 445     button_req
.width 
= 2; 
 446     button_req
.height 
= 2; 
 447     (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request 
) 
 448         (gcombo
->button
, &button_req 
); 
 450     requisition
->width 
= w 
- button_req
.width
; 
 451     requisition
->height 
= entry_req
.height
; 
 455 //----------------------------------------------------------------------------- 
 456 // "expose_event" of m_wxwindow 
 457 //----------------------------------------------------------------------------- 
 461 gtk_window_expose_callback( GtkWidget 
*widget
, 
 462                             GdkEventExpose 
*gdk_event
, 
 467     // don't need to install idle handler, its done from "event" signal 
 469     // This callback gets called in drawing-idle time under 
 470     // GTK 2.0, so we don't need to defer anything to idle 
 473     GtkPizza 
*pizza 
= GTK_PIZZA( widget 
); 
 474     if (gdk_event
->window 
!= pizza
->bin_window
) 
 476         // block expose events on GTK_WIDGET(pizza)->window, 
 477         //   all drawing is done on pizza->bin_window 
 485         wxPrintf( wxT("OnExpose from ") ); 
 486         if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName()) 
 487             wxPrintf( win
->GetClassInfo()->GetClassName() ); 
 488         wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
, 
 489                                          (int)gdk_event
->area
.y
, 
 490                                          (int)gdk_event
->area
.width
, 
 491                                          (int)gdk_event
->area
.height 
); 
 496         win
->m_wxwindow
->style
, 
 500         (GdkRectangle
*) NULL
, 
 502         (char *)"button", // const_cast 
 507     win
->GetUpdateRegion() = wxRegion( gdk_event
->region 
); 
 509     win
->GtkSendPaintEvents(); 
 511     // Let parent window draw window-less widgets 
 516 //----------------------------------------------------------------------------- 
 517 // "key_press_event" from any window 
 518 //----------------------------------------------------------------------------- 
 520 // These are used when transforming Ctrl-alpha to ascii values 1-26 
 521 inline bool wxIsLowerChar(int code
) 
 523     return (code 
>= 'a' && code 
<= 'z' ); 
 526 inline bool wxIsUpperChar(int code
) 
 528     return (code 
>= 'A' && code 
<= 'Z' ); 
 532 // set WXTRACE to this to see the key event codes on the console 
 533 #define TRACE_KEYS  _T("keyevent") 
 535 // translates an X key symbol to WXK_XXX value 
 537 // if isChar is true it means that the value returned will be used for EVT_CHAR 
 538 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide, 
 539 // for example, while if it is false it means that the value is going to be 
 540 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to 
 542 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
) 
 548         // Shift, Control and Alt don't generate the CHAR events at all 
 551             key_code 
= isChar 
? 0 : WXK_SHIFT
; 
 555             key_code 
= isChar 
? 0 : WXK_CONTROL
; 
 563             key_code 
= isChar 
? 0 : WXK_ALT
; 
 566         // neither do the toggle modifies 
 567         case GDK_Scroll_Lock
: 
 568             key_code 
= isChar 
? 0 : WXK_SCROLL
; 
 572             key_code 
= isChar 
? 0 : WXK_CAPITAL
; 
 576             key_code 
= isChar 
? 0 : WXK_NUMLOCK
; 
 580         // various other special keys 
 593         case GDK_ISO_Left_Tab
: 
 600             key_code 
= WXK_RETURN
; 
 604             key_code 
= WXK_CLEAR
; 
 608             key_code 
= WXK_PAUSE
; 
 612             key_code 
= WXK_SELECT
; 
 616             key_code 
= WXK_PRINT
; 
 620             key_code 
= WXK_EXECUTE
; 
 624             key_code 
= WXK_ESCAPE
; 
 627         // cursor and other extended keyboard keys 
 629             key_code 
= WXK_DELETE
; 
 645             key_code 
= WXK_RIGHT
; 
 652         case GDK_Prior
:     // == GDK_Page_Up 
 653             key_code 
= WXK_PAGEUP
; 
 656         case GDK_Next
:      // == GDK_Page_Down 
 657             key_code 
= WXK_PAGEDOWN
; 
 669             key_code 
= WXK_INSERT
; 
 684             key_code 
= (isChar 
? '0' : WXK_NUMPAD0
) + keysym 
- GDK_KP_0
; 
 688             key_code 
= isChar 
? ' ' : WXK_NUMPAD_SPACE
; 
 692             key_code 
= isChar 
? WXK_TAB 
: WXK_NUMPAD_TAB
; 
 696             key_code 
= isChar 
? WXK_RETURN 
: WXK_NUMPAD_ENTER
; 
 700             key_code 
= isChar 
? WXK_F1 
: WXK_NUMPAD_F1
; 
 704             key_code 
= isChar 
? WXK_F2 
: WXK_NUMPAD_F2
; 
 708             key_code 
= isChar 
? WXK_F3 
: WXK_NUMPAD_F3
; 
 712             key_code 
= isChar 
? WXK_F4 
: WXK_NUMPAD_F4
; 
 716             key_code 
= isChar 
? WXK_HOME 
: WXK_NUMPAD_HOME
; 
 720             key_code 
= isChar 
? WXK_LEFT 
: WXK_NUMPAD_LEFT
; 
 724             key_code 
= isChar 
? WXK_UP 
: WXK_NUMPAD_UP
; 
 728             key_code 
= isChar 
? WXK_RIGHT 
: WXK_NUMPAD_RIGHT
; 
 732             key_code 
= isChar 
? WXK_DOWN 
: WXK_NUMPAD_DOWN
; 
 735         case GDK_KP_Prior
: // == GDK_KP_Page_Up 
 736             key_code 
= isChar 
? WXK_PAGEUP 
: WXK_NUMPAD_PAGEUP
; 
 739         case GDK_KP_Next
: // == GDK_KP_Page_Down 
 740             key_code 
= isChar 
? WXK_PAGEDOWN 
: WXK_NUMPAD_PAGEDOWN
; 
 744             key_code 
= isChar 
? WXK_END 
: WXK_NUMPAD_END
; 
 748             key_code 
= isChar 
? WXK_HOME 
: WXK_NUMPAD_BEGIN
; 
 752             key_code 
= isChar 
? WXK_INSERT 
: WXK_NUMPAD_INSERT
; 
 756             key_code 
= isChar 
? WXK_DELETE 
: WXK_NUMPAD_DELETE
; 
 760             key_code 
= isChar 
? '=' : WXK_NUMPAD_EQUAL
; 
 763         case GDK_KP_Multiply
: 
 764             key_code 
= isChar 
? '*' : WXK_NUMPAD_MULTIPLY
; 
 768             key_code 
= isChar 
? '+' : WXK_NUMPAD_ADD
; 
 771         case GDK_KP_Separator
: 
 772             // FIXME: what is this? 
 773             key_code 
= isChar 
? '.' : WXK_NUMPAD_SEPARATOR
; 
 776         case GDK_KP_Subtract
: 
 777             key_code 
= isChar 
? '-' : WXK_NUMPAD_SUBTRACT
; 
 781             key_code 
= isChar 
? '.' : WXK_NUMPAD_DECIMAL
; 
 785             key_code 
= isChar 
? '/' : WXK_NUMPAD_DIVIDE
; 
 802             key_code 
= WXK_F1 
+ keysym 
- GDK_F1
; 
 812 static inline bool wxIsAsciiKeysym(KeySym ks
) 
 817 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
, 
 819                                       GdkEventKey 
*gdk_event
) 
 823     GdkModifierType state
; 
 824     if (gdk_event
->window
) 
 825         gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
 827     event
.SetTimestamp( gdk_event
->time 
); 
 828     event
.SetId(win
->GetId()); 
 829     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
) != 0; 
 830     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
) != 0; 
 831     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
) != 0; 
 832     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
) != 0; 
 833     event
.m_scanCode 
= gdk_event
->keyval
; 
 834     event
.m_rawCode 
= (wxUint32
) gdk_event
->keyval
; 
 835     event
.m_rawFlags 
= 0; 
 837     event
.m_uniChar 
= gdk_keyval_to_unicode(gdk_event
->keyval
); 
 839     wxGetMousePosition( &x
, &y 
); 
 840     win
->ScreenToClient( &x
, &y 
); 
 843     event
.SetEventObject( win 
); 
 848 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
, 
 850                            GdkEventKey 
*gdk_event
) 
 852     // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string 
 853     //     but only event->keyval which is quite useless to us, so remember 
 854     //     the last character from GDK_KEY_PRESS and reuse it as last resort 
 856     // NB: should be MT-safe as we're always called from the main thread only 
 861     } s_lastKeyPress 
= { 0, 0 }; 
 863     KeySym keysym 
= gdk_event
->keyval
; 
 865     wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"), 
 866                event
.GetEventType() == wxEVT_KEY_UP 
? _T("release") 
 870     long key_code 
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */); 
 874         // do we have the translation or is it a plain ASCII character? 
 875         if ( (gdk_event
->length 
== 1) || wxIsAsciiKeysym(keysym
) ) 
 877             // we should use keysym if it is ASCII as X does some translations 
 878             // like "I pressed while Control is down" => "Ctrl-I" == "TAB" 
 879             // which we don't want here (but which we do use for OnChar()) 
 880             if ( !wxIsAsciiKeysym(keysym
) ) 
 882                 keysym 
= (KeySym
)gdk_event
->string
[0]; 
 885             // we want to always get the same key code when the same key is 
 886             // pressed regardless of the state of the modifiers, i.e. on a 
 887             // standard US keyboard pressing '5' or '%' ('5' key with 
 888             // Shift) should result in the same key code in OnKeyDown(): 
 889             // '5' (although OnChar() will get either '5' or '%'). 
 891             // to do it we first translate keysym to keycode (== scan code) 
 892             // and then back but always using the lower register 
 893             Display 
*dpy 
= (Display 
*)wxGetDisplay(); 
 894             KeyCode keycode 
= XKeysymToKeycode(dpy
, keysym
); 
 896             wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
); 
 898             KeySym keysymNormalized 
= XKeycodeToKeysym(dpy
, keycode
, 0); 
 900             // use the normalized, i.e. lower register, keysym if we've 
 902             key_code 
= keysymNormalized 
? keysymNormalized 
: keysym
; 
 904             // as explained above, we want to have lower register key codes 
 905             // normally but for the letter keys we want to have the upper ones 
 907             // NB: don't use XConvertCase() here, we want to do it for letters 
 909             key_code 
= toupper(key_code
); 
 911         else // non ASCII key, what to do? 
 913             // by default, ignore it 
 916             // but if we have cached information from the last KEY_PRESS 
 917             if ( gdk_event
->type 
== GDK_KEY_RELEASE 
) 
 920                 if ( keysym 
== s_lastKeyPress
.keysym 
) 
 922                     key_code 
= s_lastKeyPress
.keycode
; 
 927         if ( gdk_event
->type 
== GDK_KEY_PRESS 
) 
 929             // remember it to be reused for KEY_UP event later 
 930             s_lastKeyPress
.keysym 
= keysym
; 
 931             s_lastKeyPress
.keycode 
= key_code
; 
 935     wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
); 
 937     // sending unknown key events doesn't really make sense 
 941     // now fill all the other fields 
 942     wxFillOtherKeyEventFields(event
, win
, gdk_event
); 
 944     event
.m_keyCode 
= key_code
; 
 946     if ( gdk_event
->type 
== GDK_KEY_PRESS 
||  gdk_event
->type 
== GDK_KEY_RELEASE 
) 
 948         event
.m_uniChar 
= key_code
; 
 958     GtkIMContext 
*context
; 
 959     GdkEventKey  
*lastKeyEvent
; 
 963         context 
= gtk_im_multicontext_new(); 
 968         g_object_unref (context
); 
 974 gtk_window_key_press_callback( GtkWidget 
*widget
, 
 975                                GdkEventKey 
*gdk_event
, 
 980     // don't need to install idle handler, its done from "event" signal 
 984     if (g_blockEventsOnDrag
) 
 988     wxKeyEvent 
event( wxEVT_KEY_DOWN 
); 
 990     bool return_after_IM 
= false; 
 992     if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) ) 
 994         // Emit KEY_DOWN event 
 995         ret 
= win
->GetEventHandler()->ProcessEvent( event 
); 
 999         // Return after IM processing as we cannot do 
1000         // anything with it anyhow. 
1001         return_after_IM 
= true; 
1004     // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw): 
1005     // When we get a key_press event here, it could be originate 
1006     // from the current widget or its child widgets.  However, only the widget 
1007     // with the INPUT FOCUS can generate the INITIAL key_press event.  That is, 
1008     // if the CURRENT widget doesn't have the FOCUS at all, this event definitely 
1009     // originated from its child widgets and shouldn't be passed to IM context. 
1010     // In fact, what a GTK+ IM should do is filtering keyEvents and convert them 
1011     // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS.  Besides, when current 
1012     // widgets has both IM context and input focus, the event should be filtered 
1013     // by gtk_im_context_filter_keypress(). 
1014     // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns. 
1015     if ((!ret
) && (win
->m_imData 
!= NULL
) && ( wxWindow::FindFocus() == win 
)) 
1017         // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API 
1018         // docs, if IM filter returns true, no further processing should be done. 
1019         // we should send the key_down event anyway. 
1020         bool intercepted_by_IM 
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
); 
1021         win
->m_imData
->lastKeyEvent 
= NULL
; 
1022         if (intercepted_by_IM
) 
1024             wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM")); 
1029     if (return_after_IM
) 
1035         wxWindowGTK 
*ancestor 
= win
; 
1038             int command 
= ancestor
->GetAcceleratorTable()->GetCommand( event 
); 
1041                 wxCommandEvent 
command_event( wxEVT_COMMAND_MENU_SELECTED
, command 
); 
1042                 ret 
= ancestor
->GetEventHandler()->ProcessEvent( command_event 
); 
1045             if (ancestor
->IsTopLevel()) 
1047             ancestor 
= ancestor
->GetParent(); 
1050 #endif // wxUSE_ACCEL 
1052     // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x 
1053     // will only be sent if it is not in an accelerator table. 
1057         KeySym keysym 
= gdk_event
->keyval
; 
1058         // Find key code for EVT_CHAR and EVT_CHAR_HOOK events 
1059         key_code 
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */); 
1062             if ( wxIsAsciiKeysym(keysym
) ) 
1065                 key_code 
= (unsigned char)keysym
; 
1067             // gdk_event->string is actually deprecated 
1068             else if ( gdk_event
->length 
== 1 ) 
1070                 key_code 
= (unsigned char)gdk_event
->string
[0]; 
1076             wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
); 
1078             event
.m_keyCode 
= key_code
; 
1080             // To conform to the docs we need to translate Ctrl-alpha 
1081             // characters to values in the range 1-26. 
1082             if ( event
.ControlDown() && 
1083                  ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) )) 
1085                 if ( wxIsLowerChar(key_code
) ) 
1086                     event
.m_keyCode 
= key_code 
- 'a' + 1; 
1087                 if ( wxIsUpperChar(key_code
) ) 
1088                     event
.m_keyCode 
= key_code 
- 'A' + 1; 
1090                 event
.m_uniChar 
= event
.m_keyCode
; 
1094             // Implement OnCharHook by checking ancestor top level windows 
1095             wxWindow 
*parent 
= win
; 
1096             while (parent 
&& !parent
->IsTopLevel()) 
1097                 parent 
= parent
->GetParent(); 
1100                 event
.SetEventType( wxEVT_CHAR_HOOK 
); 
1101                 ret 
= parent
->GetEventHandler()->ProcessEvent( event 
); 
1106                 event
.SetEventType(wxEVT_CHAR
); 
1107                 ret 
= win
->GetEventHandler()->ProcessEvent( event 
); 
1112     // win is a control: tab can be propagated up 
1114          ((gdk_event
->keyval 
== GDK_Tab
) || (gdk_event
->keyval 
== GDK_ISO_Left_Tab
)) && 
1115 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may 
1116 //     have this style, yet choose not to process this particular TAB in which 
1117 //     case TAB must still work as a navigational character 
1118 // JS: enabling again to make consistent with other platforms 
1119 //     (with wxTE_PROCESS_TAB you have to call Navigate to get default 
1120 //     navigation behaviour) 
1122          (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) && 
1124          win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) ) 
1126         wxNavigationKeyEvent new_event
; 
1127         new_event
.SetEventObject( win
->GetParent() ); 
1128         // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB 
1129         new_event
.SetDirection( (gdk_event
->keyval 
== GDK_Tab
) ); 
1130         // CTRL-TAB changes the (parent) window, i.e. switch notebook page 
1131         new_event
.SetWindowChange( (gdk_event
->state 
& GDK_CONTROL_MASK
) ); 
1132         new_event
.SetCurrentFocus( win 
); 
1133         ret 
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event 
); 
1142 gtk_wxwindow_commit_cb (GtkIMContext 
*context
, 
1146     wxKeyEvent 
event( wxEVT_KEY_DOWN 
); 
1148     // take modifiers, cursor position, timestamp etc. from the last 
1149     // key_press_event that was fed into Input Method: 
1150     if (window
->m_imData
->lastKeyEvent
) 
1152         wxFillOtherKeyEventFields(event
, 
1153                                   window
, window
->m_imData
->lastKeyEvent
); 
1156     const wxWxCharBuffer 
data(wxGTK_CONV_BACK(str
)); 
1162     // Implement OnCharHook by checking ancestor top level windows 
1163     wxWindow 
*parent 
= window
; 
1164     while (parent 
&& !parent
->IsTopLevel()) 
1165         parent 
= parent
->GetParent(); 
1167     for( const wxChar
* pstr 
= data
; *pstr
; pstr
++ ) 
1170         event
.m_uniChar 
= *pstr
; 
1171         // Backward compatible for ISO-8859-1 
1172         event
.m_keyCode 
= *pstr 
< 256 ? event
.m_uniChar 
: 0; 
1173         wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
); 
1175         event
.m_keyCode 
= *pstr
; 
1176 #endif  // wxUSE_UNICODE 
1178         // To conform to the docs we need to translate Ctrl-alpha 
1179         // characters to values in the range 1-26. 
1180         if ( event
.ControlDown() && 
1181              ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) )) 
1183             if ( wxIsLowerChar(*pstr
) ) 
1184                 event
.m_keyCode 
= *pstr 
- 'a' + 1; 
1185             if ( wxIsUpperChar(*pstr
) ) 
1186                 event
.m_keyCode 
= *pstr 
- 'A' + 1; 
1188             event
.m_keyCode 
= *pstr 
- 'a' + 1; 
1190             event
.m_uniChar 
= event
.m_keyCode
; 
1196             event
.SetEventType( wxEVT_CHAR_HOOK 
); 
1197             ret 
= parent
->GetEventHandler()->ProcessEvent( event 
); 
1202             event
.SetEventType(wxEVT_CHAR
); 
1203             ret 
= window
->GetEventHandler()->ProcessEvent( event 
); 
1210 //----------------------------------------------------------------------------- 
1211 // "key_release_event" from any window 
1212 //----------------------------------------------------------------------------- 
1216 gtk_window_key_release_callback( GtkWidget 
*widget
, 
1217                                  GdkEventKey 
*gdk_event
, 
1222     // don't need to install idle handler, its done from "event" signal 
1227     if (g_blockEventsOnDrag
) 
1230     wxKeyEvent 
event( wxEVT_KEY_UP 
); 
1231     if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) ) 
1233         // unknown key pressed, ignore (the event would be useless anyhow) 
1237     return win
->GTKProcessEvent(event
); 
1241 // ============================================================================ 
1243 // ============================================================================ 
1245 // ---------------------------------------------------------------------------- 
1246 // mouse event processing helpers 
1247 // ---------------------------------------------------------------------------- 
1249 // init wxMouseEvent with the info from GdkEventXXX struct 
1250 template<typename T
> void InitMouseEvent(wxWindowGTK 
*win
, 
1251                                          wxMouseEvent
& event
, 
1254     event
.SetTimestamp( gdk_event
->time 
); 
1255     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
); 
1256     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
); 
1257     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
); 
1258     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
); 
1259     event
.m_leftDown 
= (gdk_event
->state 
& GDK_BUTTON1_MASK
); 
1260     event
.m_middleDown 
= (gdk_event
->state 
& GDK_BUTTON2_MASK
); 
1261     event
.m_rightDown 
= (gdk_event
->state 
& GDK_BUTTON3_MASK
); 
1262     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
1264        event
.m_linesPerAction 
= 3; 
1265        event
.m_wheelDelta 
= 120; 
1266        if (((GdkEventButton
*)gdk_event
)->button 
== 4) 
1267            event
.m_wheelRotation 
= 120; 
1268        else if (((GdkEventButton
*)gdk_event
)->button 
== 5) 
1269            event
.m_wheelRotation 
= -120; 
1272     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1273     event
.m_x 
= (wxCoord
)gdk_event
->x 
- pt
.x
; 
1274     event
.m_y 
= (wxCoord
)gdk_event
->y 
- pt
.y
; 
1276     if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
)) 
1278         // origin in the upper right corner 
1279         int window_width 
= gtk_pizza_get_rtl_offset( GTK_PIZZA(win
->m_wxwindow
) ); 
1280         event
.m_x 
= window_width 
- event
.m_x
; 
1283     event
.SetEventObject( win 
); 
1284     event
.SetId( win
->GetId() ); 
1285     event
.SetTimestamp( gdk_event
->time 
); 
1288 static void AdjustEventButtonState(wxMouseEvent
& event
) 
1290     // GDK reports the old state of the button for a button press event, but 
1291     // for compatibility with MSW and common sense we want m_leftDown be TRUE 
1292     // for a LEFT_DOWN event, not FALSE, so we will invert 
1293     // left/right/middleDown for the corresponding click events 
1295     if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) || 
1296         (event
.GetEventType() == wxEVT_LEFT_DCLICK
) || 
1297         (event
.GetEventType() == wxEVT_LEFT_UP
)) 
1299         event
.m_leftDown 
= !event
.m_leftDown
; 
1303     if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) || 
1304         (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) || 
1305         (event
.GetEventType() == wxEVT_MIDDLE_UP
)) 
1307         event
.m_middleDown 
= !event
.m_middleDown
; 
1311     if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) || 
1312         (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) || 
1313         (event
.GetEventType() == wxEVT_RIGHT_UP
)) 
1315         event
.m_rightDown 
= !event
.m_rightDown
; 
1320 // find the window to send the mouse event too 
1322 wxWindowGTK 
*FindWindowForMouseEvent(wxWindowGTK 
*win
, wxCoord
& x
, wxCoord
& y
) 
1327     if (win
->m_wxwindow
) 
1329         GtkPizza 
*pizza 
= GTK_PIZZA(win
->m_wxwindow
); 
1330         xx 
+= gtk_pizza_get_xoffset( pizza 
); 
1331         yy 
+= gtk_pizza_get_yoffset( pizza 
); 
1334     wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
1337         wxWindowGTK 
*child 
= node
->GetData(); 
1339         node 
= node
->GetNext(); 
1340         if (!child
->IsShown()) 
1343         if (child
->IsTransparentForMouse()) 
1345             // wxStaticBox is transparent in the box itself 
1346             int xx1 
= child
->m_x
; 
1347             int yy1 
= child
->m_y
; 
1348             int xx2 
= child
->m_x 
+ child
->m_width
; 
1349             int yy2 
= child
->m_y 
+ child
->m_height
; 
1352             if (((xx 
>= xx1
) && (xx 
<= xx1
+10) && (yy 
>= yy1
) && (yy 
<= yy2
)) || 
1354                 ((xx 
>= xx2
-10) && (xx 
<= xx2
) && (yy 
>= yy1
) && (yy 
<= yy2
)) || 
1356                 ((xx 
>= xx1
) && (xx 
<= xx2
) && (yy 
>= yy1
) && (yy 
<= yy1
+10)) || 
1358                 ((xx 
>= xx1
) && (xx 
<= xx2
) && (yy 
>= yy2
-1) && (yy 
<= yy2
))) 
1369             if ((child
->m_wxwindow 
== (GtkWidget
*) NULL
) && 
1370                 (child
->m_x 
<= xx
) && 
1371                 (child
->m_y 
<= yy
) && 
1372                 (child
->m_x
+child
->m_width  
>= xx
) && 
1373                 (child
->m_y
+child
->m_height 
>= yy
)) 
1386 // ---------------------------------------------------------------------------- 
1387 // common event handlers helpers 
1388 // ---------------------------------------------------------------------------- 
1390 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const 
1392     // nothing special at this level 
1393     return GetEventHandler()->ProcessEvent(event
); 
1396 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny 
*event
) const 
1400     // don't need to install idle handler, its done from "event" signal 
1404     if (g_blockEventsOnDrag
) 
1406     if (g_blockEventsOnScroll
) 
1409     if (!GTKIsOwnWindow(event
->window
)) 
1415 // overloads for all GDK event types we use here: we need to have this as 
1416 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact, 
1417 // derives from it in the sense that the structs have the same layout 
1418 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T)                                  \ 
1419     static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win)        \ 
1421         return win->GTKCallbackCommonPrologue((GdkEventAny *)event);          \ 
1424 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
) 
1425 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
) 
1426 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
) 
1428 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD 
1430 #define wxCOMMON_CALLBACK_PROLOGUE(event, win)                                \ 
1431     const int rc = wxGtkCallbackCommonPrologue(event, win);                   \ 
1435 // send the wxChildFocusEvent and wxFocusEvent, common code of 
1436 // gtk_window_focus_in_callback() and SetFocus() 
1437 static bool DoSendFocusEvents(wxWindow 
*win
) 
1439     // Notify the parent keeping track of focus for the kbd navigation 
1440     // purposes that we got it. 
1441     wxChildFocusEvent 
eventChildFocus(win
); 
1442     (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
); 
1444     wxFocusEvent 
eventFocus(wxEVT_SET_FOCUS
, win
->GetId()); 
1445     eventFocus
.SetEventObject(win
); 
1447     return win
->GetEventHandler()->ProcessEvent(eventFocus
); 
1450 // all event handlers must have C linkage as they're called from GTK+ C code 
1454 //----------------------------------------------------------------------------- 
1455 // "button_press_event" 
1456 //----------------------------------------------------------------------------- 
1459 gtk_window_button_press_callback( GtkWidget 
*widget
, 
1460                                   GdkEventButton 
*gdk_event
, 
1463     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1465     if (win
->m_wxwindow 
&& (g_focusWindow 
!= win
) && win
->AcceptsFocus()) 
1467         gtk_widget_grab_focus( win
->m_wxwindow 
); 
1470     // GDK sends surplus button down events 
1471     // before a double click event. We 
1472     // need to filter these out. 
1473     if ((gdk_event
->type 
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
)) 
1475         GdkEvent 
*peek_event 
= gdk_event_peek(); 
1478             if ((peek_event
->type 
== GDK_2BUTTON_PRESS
) || 
1479                 (peek_event
->type 
== GDK_3BUTTON_PRESS
)) 
1481                 gdk_event_free( peek_event 
); 
1486                 gdk_event_free( peek_event 
); 
1491     wxEventType event_type 
= wxEVT_NULL
; 
1493     // GdkDisplay is a GTK+ 2.2.0 thing 
1494 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0) 
1495     if ( gdk_event
->type 
== GDK_2BUTTON_PRESS 
&& 
1496             !gtk_check_version(2,2,0) && 
1497             gdk_event
->button 
>= 1 && gdk_event
->button 
<= 3 ) 
1499         // Reset GDK internal timestamp variables in order to disable GDK 
1500         // triple click events. GDK will then next time believe no button has 
1501         // been clicked just before, and send a normal button click event. 
1502         GdkDisplay
* display 
= gtk_widget_get_display (widget
); 
1503         display
->button_click_time
[1] = 0; 
1504         display
->button_click_time
[0] = 0; 
1508     if (gdk_event
->button 
== 1) 
1510         // note that GDK generates triple click events which are not supported 
1511         // by wxWidgets but still have to be passed to the app as otherwise 
1512         // clicks would simply go missing 
1513         switch (gdk_event
->type
) 
1515             // we shouldn't get triple clicks at all for GTK2 because we 
1516             // suppress them artificially using the code above but we still 
1517             // should map them to something for GTK1 and not just ignore them 
1518             // as this would lose clicks 
1519             case GDK_3BUTTON_PRESS
:     // we could also map this to DCLICK... 
1520             case GDK_BUTTON_PRESS
: 
1521                 event_type 
= wxEVT_LEFT_DOWN
; 
1524             case GDK_2BUTTON_PRESS
: 
1525                 event_type 
= wxEVT_LEFT_DCLICK
; 
1529                 // just to silence gcc warnings 
1533     else if (gdk_event
->button 
== 2) 
1535         switch (gdk_event
->type
) 
1537             case GDK_3BUTTON_PRESS
: 
1538             case GDK_BUTTON_PRESS
: 
1539                 event_type 
= wxEVT_MIDDLE_DOWN
; 
1542             case GDK_2BUTTON_PRESS
: 
1543                 event_type 
= wxEVT_MIDDLE_DCLICK
; 
1550     else if (gdk_event
->button 
== 3) 
1552         switch (gdk_event
->type
) 
1554             case GDK_3BUTTON_PRESS
: 
1555             case GDK_BUTTON_PRESS
: 
1556                 event_type 
= wxEVT_RIGHT_DOWN
; 
1559             case GDK_2BUTTON_PRESS
: 
1560                 event_type 
= wxEVT_RIGHT_DCLICK
; 
1567     else if (gdk_event
->button 
== 4 || gdk_event
->button 
== 5) 
1569         if (gdk_event
->type 
== GDK_BUTTON_PRESS 
) 
1571             event_type 
= wxEVT_MOUSEWHEEL
; 
1575     if ( event_type 
== wxEVT_NULL 
) 
1577         // unknown mouse button or click type 
1581     wxMouseEvent 
event( event_type 
); 
1582     InitMouseEvent( win
, event
, gdk_event 
); 
1584     AdjustEventButtonState(event
); 
1586     // wxListBox actually gets mouse events from the item, so we need to give it 
1587     // a chance to correct this 
1588     win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
); 
1590     // find the correct window to send the event to: it may be a different one 
1591     // from the one which got it at GTK+ level because some controls don't have 
1592     // their own X window and thus cannot get any events. 
1593     if ( !g_captureWindow 
) 
1594         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1596     // reset the event object and id in case win changed. 
1597     event
.SetEventObject( win 
); 
1598     event
.SetId( win
->GetId() ); 
1600     if (win
->GTKProcessEvent( event 
)) 
1605     if (event_type 
== wxEVT_RIGHT_DOWN
) 
1607         // generate a "context menu" event: this is similar to right mouse 
1608         // click under many GUIs except that it is generated differently 
1609         // (right up under MSW, ctrl-click under Mac, right down here) and 
1611         // (a) it's a command event and so is propagated to the parent 
1612         // (b) under some ports it can be generated from kbd too 
1613         // (c) it uses screen coords (because of (a)) 
1614         wxContextMenuEvent 
evtCtx( 
1617             win
->ClientToScreen(event
.GetPosition())); 
1618         evtCtx
.SetEventObject(win
); 
1619         return win
->GTKProcessEvent(evtCtx
); 
1625 //----------------------------------------------------------------------------- 
1626 // "button_release_event" 
1627 //----------------------------------------------------------------------------- 
1630 gtk_window_button_release_callback( GtkWidget 
*widget
, 
1631                                     GdkEventButton 
*gdk_event
, 
1634     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1636     wxEventType event_type 
= wxEVT_NULL
; 
1638     switch (gdk_event
->button
) 
1641             event_type 
= wxEVT_LEFT_UP
; 
1645             event_type 
= wxEVT_MIDDLE_UP
; 
1649             event_type 
= wxEVT_RIGHT_UP
; 
1653             // unknown button, don't process 
1657     wxMouseEvent 
event( event_type 
); 
1658     InitMouseEvent( win
, event
, gdk_event 
); 
1660     AdjustEventButtonState(event
); 
1662     // same wxListBox hack as above 
1663     win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
); 
1665     if ( !g_captureWindow 
) 
1666         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1668     // reset the event object and id in case win changed. 
1669     event
.SetEventObject( win 
); 
1670     event
.SetId( win
->GetId() ); 
1672     return win
->GTKProcessEvent(event
); 
1675 //----------------------------------------------------------------------------- 
1676 // "motion_notify_event" 
1677 //----------------------------------------------------------------------------- 
1680 gtk_window_motion_notify_callback( GtkWidget 
*widget
, 
1681                                    GdkEventMotion 
*gdk_event
, 
1684     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1686     if (gdk_event
->is_hint
) 
1690         GdkModifierType state
; 
1691         gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
1696     wxMouseEvent 
event( wxEVT_MOTION 
); 
1697     InitMouseEvent(win
, event
, gdk_event
); 
1699     if ( g_captureWindow 
) 
1701         // synthesise a mouse enter or leave event if needed 
1702         GdkWindow 
*winUnderMouse 
= gdk_window_at_pointer(NULL
, NULL
); 
1703         // This seems to be necessary and actually been added to 
1704         // GDK itself in version 2.0.X 
1707         bool hasMouse 
= winUnderMouse 
== gdk_event
->window
; 
1708         if ( hasMouse 
!= g_captureWindowHasMouse 
) 
1710             // the mouse changed window 
1711             g_captureWindowHasMouse 
= hasMouse
; 
1713             wxMouseEvent 
eventM(g_captureWindowHasMouse 
? wxEVT_ENTER_WINDOW
 
1714                                                         : wxEVT_LEAVE_WINDOW
); 
1715             InitMouseEvent(win
, eventM
, gdk_event
); 
1716             eventM
.SetEventObject(win
); 
1717             win
->GTKProcessEvent(eventM
); 
1722         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1724         // reset the event object and id in case win changed. 
1725         event
.SetEventObject( win 
); 
1726         event
.SetId( win
->GetId() ); 
1729     if ( !g_captureWindow 
) 
1731         wxSetCursorEvent 
cevent( event
.m_x
, event
.m_y 
); 
1732         if (win
->GTKProcessEvent( cevent 
)) 
1734             win
->SetCursor( cevent
.GetCursor() ); 
1738     return win
->GTKProcessEvent(event
); 
1741 //----------------------------------------------------------------------------- 
1742 // "scroll_event", (mouse wheel event) 
1743 //----------------------------------------------------------------------------- 
1746 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
) 
1750     // don't need to install idle handler, its done from "event" signal 
1752     if (gdk_event
->direction 
!= GDK_SCROLL_UP 
&& 
1753         gdk_event
->direction 
!= GDK_SCROLL_DOWN
) 
1758     wxMouseEvent 
event(wxEVT_MOUSEWHEEL
); 
1759     // Can't use InitMouse macro because scroll events don't have button 
1760     event
.SetTimestamp( gdk_event
->time 
); 
1761     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
); 
1762     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
); 
1763     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
); 
1764     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
); 
1765     event
.m_leftDown 
= (gdk_event
->state 
& GDK_BUTTON1_MASK
); 
1766     event
.m_middleDown 
= (gdk_event
->state 
& GDK_BUTTON2_MASK
); 
1767     event
.m_rightDown 
= (gdk_event
->state 
& GDK_BUTTON3_MASK
); 
1768     event
.m_linesPerAction 
= 3; 
1769     event
.m_wheelDelta 
= 120; 
1770     if (gdk_event
->direction 
== GDK_SCROLL_UP
) 
1771         event
.m_wheelRotation 
= 120; 
1773         event
.m_wheelRotation 
= -120; 
1775     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1776     event
.m_x 
= (wxCoord
)gdk_event
->x 
- pt
.x
; 
1777     event
.m_y 
= (wxCoord
)gdk_event
->y 
- pt
.y
; 
1779     event
.SetEventObject( win 
); 
1780     event
.SetId( win
->GetId() ); 
1781     event
.SetTimestamp( gdk_event
->time 
); 
1783     return win
->GTKProcessEvent(event
); 
1786 //----------------------------------------------------------------------------- 
1788 //----------------------------------------------------------------------------- 
1790 static gboolean 
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
) 
1792     wxContextMenuEvent 
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1)); 
1793     event
.SetEventObject(win
); 
1794     return win
->GTKProcessEvent(event
); 
1797 //----------------------------------------------------------------------------- 
1799 //----------------------------------------------------------------------------- 
1802 gtk_window_focus_in_callback( GtkWidget 
*widget
, 
1803                               GdkEventFocus 
*WXUNUSED(event
), 
1808     // don't need to install idle handler, its done from "event" signal 
1811         gtk_im_context_focus_in(win
->m_imData
->context
); 
1814     g_focusWindow 
= win
; 
1816     wxLogTrace(TRACE_FOCUS
, 
1817                _T("%s: focus in"), win
->GetName().c_str()); 
1820     // caret needs to be informed about focus change 
1821     wxCaret 
*caret 
= win
->GetCaret(); 
1824         caret
->OnSetFocus(); 
1826 #endif // wxUSE_CARET 
1828     gboolean ret 
= FALSE
; 
1830     // does the window itself think that it has the focus? 
1831     if ( !win
->m_hasFocus 
) 
1833         // not yet, notify it 
1834         win
->m_hasFocus 
= true; 
1836         (void)DoSendFocusEvents(win
); 
1841     // Disable default focus handling for custom windows 
1842     // since the default GTK+ handler issues a repaint 
1843     if (win
->m_wxwindow
) 
1849 //----------------------------------------------------------------------------- 
1850 // "focus_out_event" 
1851 //----------------------------------------------------------------------------- 
1854 gtk_window_focus_out_callback( GtkWidget 
*widget
, 
1855                                GdkEventFocus 
*gdk_event
, 
1860     // don't need to install idle handler, its done from "event" signal 
1863         gtk_im_context_focus_out(win
->m_imData
->context
); 
1865     wxLogTrace( TRACE_FOCUS
, 
1866                 _T("%s: focus out"), win
->GetName().c_str() ); 
1869     wxWindowGTK 
*winFocus 
= wxFindFocusedChild(win
); 
1873     g_focusWindow 
= (wxWindowGTK 
*)NULL
; 
1876     // caret needs to be informed about focus change 
1877     wxCaret 
*caret 
= win
->GetCaret(); 
1880         caret
->OnKillFocus(); 
1882 #endif // wxUSE_CARET 
1884     gboolean ret 
= FALSE
; 
1886     // don't send the window a kill focus event if it thinks that it doesn't 
1887     // have focus already 
1888     if ( win
->m_hasFocus 
) 
1890         win
->m_hasFocus 
= false; 
1892         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, win
->GetId() ); 
1893         event
.SetEventObject( win 
); 
1895         (void)win
->GTKProcessEvent( event 
); 
1900     // Disable default focus handling for custom windows 
1901     // since the default GTK+ handler issues a repaint 
1902     if (win
->m_wxwindow
) 
1908 //----------------------------------------------------------------------------- 
1909 // "enter_notify_event" 
1910 //----------------------------------------------------------------------------- 
1913 gtk_window_enter_callback( GtkWidget 
*widget
, 
1914                            GdkEventCrossing 
*gdk_event
, 
1917     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1919     // Event was emitted after a grab 
1920     if (gdk_event
->mode 
!= GDK_CROSSING_NORMAL
) return FALSE
; 
1924     GdkModifierType state 
= (GdkModifierType
)0; 
1926     gdk_window_get_pointer( widget
->window
, &x
, &y
, &state 
); 
1928     wxMouseEvent 
event( wxEVT_ENTER_WINDOW 
); 
1929     InitMouseEvent(win
, event
, gdk_event
); 
1930     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1931     event
.m_x 
= x 
+ pt
.x
; 
1932     event
.m_y 
= y 
+ pt
.y
; 
1934     if ( !g_captureWindow 
) 
1936         wxSetCursorEvent 
cevent( event
.m_x
, event
.m_y 
); 
1937         if (win
->GTKProcessEvent( cevent 
)) 
1939             win
->SetCursor( cevent
.GetCursor() ); 
1943     return win
->GTKProcessEvent(event
); 
1946 //----------------------------------------------------------------------------- 
1947 // "leave_notify_event" 
1948 //----------------------------------------------------------------------------- 
1951 gtk_window_leave_callback( GtkWidget 
*widget
, 
1952                            GdkEventCrossing 
*gdk_event
, 
1955     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1957     // Event was emitted after an ungrab 
1958     if (gdk_event
->mode 
!= GDK_CROSSING_NORMAL
) return FALSE
; 
1960     wxMouseEvent 
event( wxEVT_LEAVE_WINDOW 
); 
1961     event
.SetTimestamp( gdk_event
->time 
); 
1962     event
.SetEventObject( win 
); 
1966     GdkModifierType state 
= (GdkModifierType
)0; 
1968     gdk_window_get_pointer( widget
->window
, &x
, &y
, &state 
); 
1970     event
.m_shiftDown 
= (state 
& GDK_SHIFT_MASK
) != 0; 
1971     event
.m_controlDown 
= (state 
& GDK_CONTROL_MASK
) != 0; 
1972     event
.m_altDown 
= (state 
& GDK_MOD1_MASK
) != 0; 
1973     event
.m_metaDown 
= (state 
& GDK_MOD2_MASK
) != 0; 
1974     event
.m_leftDown 
= (state 
& GDK_BUTTON1_MASK
) != 0; 
1975     event
.m_middleDown 
= (state 
& GDK_BUTTON2_MASK
) != 0; 
1976     event
.m_rightDown 
= (state 
& GDK_BUTTON3_MASK
) != 0; 
1978     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1979     event
.m_x 
= x 
+ pt
.x
; 
1980     event
.m_y 
= y 
+ pt
.y
; 
1982     return win
->GTKProcessEvent(event
); 
1985 //----------------------------------------------------------------------------- 
1986 // "value_changed" from scrollbar 
1987 //----------------------------------------------------------------------------- 
1990 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
) 
1992     wxEventType eventType 
= win
->GetScrollEventType(range
); 
1993     if (eventType 
!= wxEVT_NULL
) 
1995         // Convert scroll event type to scrollwin event type 
1996         eventType 
+= wxEVT_SCROLLWIN_TOP 
- wxEVT_SCROLL_TOP
; 
1998         // find the scrollbar which generated the event 
1999         wxWindowGTK::ScrollDir dir 
= win
->ScrollDirFromRange(range
); 
2001         // generate the corresponding wx event 
2002         const int orient 
= wxWindow::OrientFromScrollDir(dir
); 
2003         wxScrollWinEvent 
event(eventType
, win
->GetScrollPos(orient
), orient
); 
2004         event
.SetEventObject(win
); 
2006         win
->m_blockValueChanged
[dir
] = true; 
2007         win
->GTKProcessEvent(event
); 
2008         win
->m_blockValueChanged
[dir
] = false; 
2012 //----------------------------------------------------------------------------- 
2013 // "button_press_event" from scrollbar 
2014 //----------------------------------------------------------------------------- 
2017 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
) 
2021     // don't need to install idle handler, its done from "event" signal 
2023     g_blockEventsOnScroll 
= true; 
2024     win
->m_mouseButtonDown 
= true; 
2029 //----------------------------------------------------------------------------- 
2030 // "event_after" from scrollbar 
2031 //----------------------------------------------------------------------------- 
2034 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
) 
2036     if (event
->type 
== GDK_BUTTON_RELEASE
) 
2038         g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
); 
2040         const int orient 
= wxWindow::OrientFromScrollDir( 
2041                                         win
->ScrollDirFromRange(range
)); 
2042         wxScrollWinEvent 
event(wxEVT_SCROLLWIN_THUMBRELEASE
, win
->GetScrollPos(orient
), orient
); 
2043         event
.SetEventObject(win
); 
2044         win
->GTKProcessEvent(event
); 
2048 //----------------------------------------------------------------------------- 
2049 // "button_release_event" from scrollbar 
2050 //----------------------------------------------------------------------------- 
2053 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
) 
2057     g_blockEventsOnScroll 
= false; 
2058     win
->m_mouseButtonDown 
= false; 
2059     // If thumb tracking 
2060     if (win
->m_isScrolling
) 
2062         win
->m_isScrolling 
= false; 
2063         // Hook up handler to send thumb release event after this emission is finished. 
2064         // To allow setting scroll position from event handler, sending event must 
2065         // be deferred until after the GtkRange handler for this signal has run 
2066         g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
); 
2072 //----------------------------------------------------------------------------- 
2073 // "realize" from m_widget 
2074 //----------------------------------------------------------------------------- 
2076 /* We cannot set colours and fonts before the widget has 
2077    been realized, so we do this directly after realization. */ 
2080 gtk_window_realized_callback( GtkWidget 
*m_widget
, wxWindow 
*win 
) 
2085         wxapp_install_idle_handler(); 
2089         GtkPizza 
*pizza 
= GTK_PIZZA( m_widget 
); 
2090         gtk_im_context_set_client_window( win
->m_imData
->context
, 
2091                                           pizza
->bin_window 
); 
2094     wxWindowCreateEvent 
event( win 
); 
2095     event
.SetEventObject( win 
); 
2096     win
->GTKProcessEvent( event 
); 
2099 //----------------------------------------------------------------------------- 
2101 //----------------------------------------------------------------------------- 
2104 void gtk_window_size_callback( GtkWidget 
*WXUNUSED(widget
), 
2105                                GtkAllocation 
*alloc
, 
2109         wxapp_install_idle_handler(); 
2111     int client_width 
= 0; 
2112     int client_height 
= 0; 
2113     win
->GetClientSize( &client_width
, &client_height 
); 
2114     if ((client_width 
== win
->m_oldClientWidth
) && (client_height 
== win
->m_oldClientHeight
)) 
2118         wxPrintf( wxT("size_allocate ") ); 
2119         if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName()) 
2120             wxPrintf( win
->GetClassInfo()->GetClassName() ); 
2121         wxPrintf( wxT(" %d %d %d %d\n"), 
2128     win
->m_oldClientWidth 
= client_width
; 
2129     win
->m_oldClientHeight 
= client_height
; 
2131     if (!win
->m_nativeSizeEvent
) 
2133         wxSizeEvent 
event( win
->GetSize(), win
->GetId() ); 
2134         event
.SetEventObject( win 
); 
2135         win
->GTKProcessEvent( event 
); 
2141 // ---------------------------------------------------------------------------- 
2142 // this wxWindowBase function is implemented here (in platform-specific file) 
2143 // because it is static and so couldn't be made virtual 
2144 // ---------------------------------------------------------------------------- 
2146 wxWindow 
*wxWindowBase::DoFindFocus() 
2148     // the cast is necessary when we compile in wxUniversal mode 
2149     return (wxWindow 
*)g_focusWindow
; 
2152 //----------------------------------------------------------------------------- 
2153 // InsertChild for wxWindowGTK. 
2154 //----------------------------------------------------------------------------- 
2156 /* Callback for wxWindowGTK. This very strange beast has to be used because 
2157  * C++ has no virtual methods in a constructor. We have to emulate a 
2158  * virtual function here as wxNotebook requires a different way to insert 
2159  * a child in it. I had opted for creating a wxNotebookPage window class 
2160  * which would have made this superfluous (such in the MDI window system), 
2161  * but no-one was listening to me... */ 
2163 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child 
) 
2165     /* the window might have been scrolled already, do we 
2166        have to adapt the position */ 
2167     GtkPizza 
*pizza 
= GTK_PIZZA(parent
->m_wxwindow
); 
2168     child
->m_x 
+= gtk_pizza_get_xoffset( pizza 
); 
2169     child
->m_y 
+= gtk_pizza_get_yoffset( pizza 
); 
2171     gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
), 
2172                      GTK_WIDGET(child
->m_widget
), 
2179 //----------------------------------------------------------------------------- 
2181 //----------------------------------------------------------------------------- 
2183 wxWindow 
*wxGetActiveWindow() 
2185     return wxWindow::FindFocus(); 
2189 wxMouseState 
wxGetMouseState() 
2195     GdkModifierType mask
; 
2197     gdk_window_get_pointer(NULL
, &x
, &y
, &mask
); 
2201     ms
.SetLeftDown(mask 
& GDK_BUTTON1_MASK
); 
2202     ms
.SetMiddleDown(mask 
& GDK_BUTTON2_MASK
); 
2203     ms
.SetRightDown(mask 
& GDK_BUTTON3_MASK
); 
2205     ms
.SetControlDown(mask 
& GDK_CONTROL_MASK
); 
2206     ms
.SetShiftDown(mask 
& GDK_SHIFT_MASK
); 
2207     ms
.SetAltDown(mask 
& GDK_MOD1_MASK
); 
2208     ms
.SetMetaDown(mask 
& GDK_MOD2_MASK
); 
2213 //----------------------------------------------------------------------------- 
2215 //----------------------------------------------------------------------------- 
2217 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu() 
2219 #ifdef __WXUNIVERSAL__ 
2220     IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
) 
2222     IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
) 
2223 #endif // __WXUNIVERSAL__/__WXGTK__ 
2225 void wxWindowGTK::Init() 
2228     m_widget 
= (GtkWidget 
*) NULL
; 
2229     m_wxwindow 
= (GtkWidget 
*) NULL
; 
2230     m_focusWidget 
= (GtkWidget 
*) NULL
; 
2240     m_needParent 
= true; 
2241     m_isBeingDeleted 
= false; 
2243     m_showOnIdle
= false; 
2246     m_nativeSizeEvent 
= false; 
2248     m_hasScrolling 
= false; 
2249     m_isScrolling 
= false; 
2250     m_mouseButtonDown 
= false; 
2251     m_blockScrollEvent 
= false; 
2253     // initialize scrolling stuff 
2254     for ( int dir 
= 0; dir 
< ScrollDir_Max
; dir
++ ) 
2256         m_scrollBar
[dir
] = NULL
; 
2257         m_scrollPos
[dir
] = 0; 
2258         m_blockValueChanged
[dir
] = false; 
2262     m_oldClientHeight 
= 0; 
2266     m_insertCallback 
= (wxInsertChildFunction
) NULL
; 
2268     m_acceptsFocus 
= false; 
2271     m_clipPaintRegion 
= false; 
2273     m_needsStyleChange 
= false; 
2275     m_cursor 
= *wxSTANDARD_CURSOR
; 
2278     m_dirtyTabOrder 
= false; 
2281 wxWindowGTK::wxWindowGTK() 
2286 wxWindowGTK::wxWindowGTK( wxWindow 
*parent
, 
2291                           const wxString 
&name  
) 
2295     Create( parent
, id
, pos
, size
, style
, name 
); 
2298 bool wxWindowGTK::Create( wxWindow 
*parent
, 
2303                           const wxString 
&name  
) 
2305     if (!PreCreation( parent
, pos
, size 
) || 
2306         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
2308         wxFAIL_MSG( wxT("wxWindowGTK creation failed") ); 
2312     m_insertCallback 
= wxInsertChildInWindow
; 
2314     m_widget 
= gtk_scrolled_window_new( (GtkAdjustment 
*) NULL
, (GtkAdjustment 
*) NULL 
); 
2315     GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
2317     GtkScrolledWindow 
*scrolledWindow 
= GTK_SCROLLED_WINDOW(m_widget
); 
2319     GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) ); 
2320     scroll_class
->scrollbar_spacing 
= 0; 
2322     gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC 
); 
2324     m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
); 
2325     m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
); 
2326     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
2327         gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE 
); 
2329     m_wxwindow 
= gtk_pizza_new(); 
2331 #ifndef __WXUNIVERSAL__ 
2332     if (HasFlag(wxSIMPLE_BORDER
)) 
2333         gtk_container_set_border_width((GtkContainer
*)m_wxwindow
, 1); 
2334     else if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
)) 
2335         gtk_container_set_border_width((GtkContainer
*)m_wxwindow
, 2); 
2336 #endif // __WXUNIVERSAL__ 
2338     gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow 
); 
2340     GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS 
); 
2341     m_acceptsFocus 
= true; 
2343     // connect various scroll-related events 
2344     for ( int dir 
= 0; dir 
< ScrollDir_Max
; dir
++ ) 
2346         // these handlers block mouse events to any window during scrolling 
2347         // such as motion events and prevent GTK and wxWidgets from fighting 
2348         // over where the slider should be 
2349         g_signal_connect(m_scrollBar
[dir
], "button_press_event", 
2350                          G_CALLBACK(gtk_scrollbar_button_press_event
), this); 
2351         g_signal_connect(m_scrollBar
[dir
], "button_release_event", 
2352                          G_CALLBACK(gtk_scrollbar_button_release_event
), this); 
2354         gulong handler_id 
= g_signal_connect(m_scrollBar
[dir
], "event_after", 
2355                                 G_CALLBACK(gtk_scrollbar_event_after
), this); 
2356         g_signal_handler_block(m_scrollBar
[dir
], handler_id
); 
2358         // these handlers get notified when scrollbar slider moves 
2359         g_signal_connect(m_scrollBar
[dir
], "value_changed", 
2360                          G_CALLBACK(gtk_scrollbar_value_changed
), this); 
2363     gtk_widget_show( m_wxwindow 
); 
2366         m_parent
->DoAddChild( this ); 
2368     m_focusWidget 
= m_wxwindow
; 
2375 wxWindowGTK::~wxWindowGTK() 
2379     if (g_focusWindow 
== this) 
2380         g_focusWindow 
= NULL
; 
2382     if ( g_delayedFocus 
== this ) 
2383         g_delayedFocus 
= NULL
; 
2385     m_isBeingDeleted 
= true; 
2388     // destroy children before destroying this window itself 
2391     // unhook focus handlers to prevent stray events being 
2392     // propagated to this (soon to be) dead object 
2393     if (m_focusWidget 
!= NULL
) 
2395         g_signal_handlers_disconnect_by_func (m_focusWidget
, 
2396                                               (gpointer
) gtk_window_focus_in_callback
, 
2398         g_signal_handlers_disconnect_by_func (m_focusWidget
, 
2399                                               (gpointer
) gtk_window_focus_out_callback
, 
2406     // delete before the widgets to avoid a crash on solaris 
2411         gtk_widget_destroy( m_wxwindow 
); 
2412         m_wxwindow 
= (GtkWidget
*) NULL
; 
2417         gtk_widget_destroy( m_widget 
); 
2418         m_widget 
= (GtkWidget
*) NULL
; 
2422 bool wxWindowGTK::PreCreation( wxWindowGTK 
*parent
, const wxPoint 
&pos
,  const wxSize 
&size 
) 
2424     wxCHECK_MSG( !m_needParent 
|| parent
, false, wxT("Need complete parent.") ); 
2426     // Use either the given size, or the default if -1 is given. 
2427     // See wxWindowBase for these functions. 
2428     m_width 
= WidthDefault(size
.x
) ; 
2429     m_height 
= HeightDefault(size
.y
); 
2437 void wxWindowGTK::PostCreation() 
2439     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2445             // these get reported to wxWidgets -> wxPaintEvent 
2447             g_signal_connect (m_wxwindow
, "expose_event", 
2448                               G_CALLBACK (gtk_window_expose_callback
), this); 
2450             if (GetLayoutDirection() == wxLayout_LeftToRight
) 
2451                 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE 
) ); 
2454         // Create input method handler 
2455         m_imData 
= new wxGtkIMData
; 
2457         // Cannot handle drawing preedited text yet 
2458         gtk_im_context_set_use_preedit( m_imData
->context
, FALSE 
); 
2460         g_signal_connect (m_imData
->context
, "commit", 
2461                           G_CALLBACK (gtk_wxwindow_commit_cb
), this); 
2463         // these are called when the "sunken" or "raised" borders are drawn 
2464         g_signal_connect (m_widget
, "expose_event", 
2465                           G_CALLBACK (gtk_window_own_expose_callback
), this); 
2470     if (!GTK_IS_WINDOW(m_widget
)) 
2472         if (m_focusWidget 
== NULL
) 
2473             m_focusWidget 
= m_widget
; 
2477             g_signal_connect (m_focusWidget
, "focus_in_event", 
2478                           G_CALLBACK (gtk_window_focus_in_callback
), this); 
2479             g_signal_connect (m_focusWidget
, "focus_out_event", 
2480                                 G_CALLBACK (gtk_window_focus_out_callback
), this); 
2484             g_signal_connect_after (m_focusWidget
, "focus_in_event", 
2485                           G_CALLBACK (gtk_window_focus_in_callback
), this); 
2486             g_signal_connect_after (m_focusWidget
, "focus_out_event", 
2487                                 G_CALLBACK (gtk_window_focus_out_callback
), this); 
2491     // connect to the various key and mouse handlers 
2493     GtkWidget 
*connect_widget 
= GetConnectWidget(); 
2495     ConnectWidget( connect_widget 
); 
2497     /* We cannot set colours, fonts and cursors before the widget has 
2498        been realized, so we do this directly after realization */ 
2499     g_signal_connect (connect_widget
, "realize", 
2500                       G_CALLBACK (gtk_window_realized_callback
), this); 
2504         // Catch native resize events 
2505         g_signal_connect (m_wxwindow
, "size_allocate", 
2506                           G_CALLBACK (gtk_window_size_callback
), this); 
2509     if (GTK_IS_COMBO(m_widget
)) 
2511         GtkCombo 
*gcombo 
= GTK_COMBO(m_widget
); 
2513         g_signal_connect (gcombo
->entry
, "size_request", 
2514                           G_CALLBACK (wxgtk_combo_size_request_callback
), 
2517 #ifdef GTK_IS_FILE_CHOOSER_BUTTON 
2518     else if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget
)) 
2520         // If we connect to the "size_request" signal of a GtkFileChooserButton 
2521         // then that control won't be sized properly when placed inside sizers 
2522         // (this can be tested removing this elseif and running XRC or WIDGETS samples) 
2523         // FIXME: what should be done here ? 
2528         // This is needed if we want to add our windows into native 
2529         // GTK controls, such as the toolbar. With this callback, the 
2530         // toolbar gets to know the correct size (the one set by the 
2531         // programmer). Sadly, it misbehaves for wxComboBox. 
2532         g_signal_connect (m_widget
, "size_request", 
2533                           G_CALLBACK (wxgtk_window_size_request_callback
), 
2537     InheritAttributes(); 
2541     SetLayoutDirection(wxLayout_Default
); 
2543     // unless the window was created initially hidden (i.e. Hide() had been 
2544     // called before Create()), we should show it at GTK+ level as well 
2546         gtk_widget_show( m_widget 
); 
2549 void wxWindowGTK::ConnectWidget( GtkWidget 
*widget 
) 
2551     g_signal_connect (widget
, "key_press_event", 
2552                       G_CALLBACK (gtk_window_key_press_callback
), this); 
2553     g_signal_connect (widget
, "key_release_event", 
2554                       G_CALLBACK (gtk_window_key_release_callback
), this); 
2555     g_signal_connect (widget
, "button_press_event", 
2556                       G_CALLBACK (gtk_window_button_press_callback
), this); 
2557     g_signal_connect (widget
, "button_release_event", 
2558                       G_CALLBACK (gtk_window_button_release_callback
), this); 
2559     g_signal_connect (widget
, "motion_notify_event", 
2560                       G_CALLBACK (gtk_window_motion_notify_callback
), this); 
2561     g_signal_connect (widget
, "scroll_event", 
2562                       G_CALLBACK (window_scroll_event
), this); 
2563     g_signal_connect (widget
, "popup_menu", 
2564                      G_CALLBACK (wxgtk_window_popup_menu_callback
), this); 
2565     g_signal_connect (widget
, "enter_notify_event", 
2566                       G_CALLBACK (gtk_window_enter_callback
), this); 
2567     g_signal_connect (widget
, "leave_notify_event", 
2568                       G_CALLBACK (gtk_window_leave_callback
), this); 
2571 bool wxWindowGTK::Destroy() 
2573     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2577     return wxWindowBase::Destroy(); 
2580 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
) 
2582     // inform the parent to perform the move 
2583     gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height 
); 
2587 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
2589     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2590     wxASSERT_MSG( (m_parent 
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") ); 
2592     if (m_resizing
) return; /* I don't like recursions */ 
2595     int currentX
, currentY
; 
2596     GetPosition(¤tX
, ¤tY
); 
2597     if (x 
== -1 && !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
2599     if (y 
== -1 && !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
2601     AdjustForParentClientOrigin(x
, y
, sizeFlags
); 
2603     // calculate the best size if we should auto size the window 
2604     if ( ((sizeFlags 
& wxSIZE_AUTO_WIDTH
) && width 
== -1) || 
2605          ((sizeFlags 
& wxSIZE_AUTO_HEIGHT
) && height 
== -1) ) 
2607         const wxSize sizeBest 
= GetBestSize(); 
2608         if ( (sizeFlags 
& wxSIZE_AUTO_WIDTH
) && width 
== -1 ) 
2610         if ( (sizeFlags 
& wxSIZE_AUTO_HEIGHT
) && height 
== -1 ) 
2611             height 
= sizeBest
.y
; 
2619     int minWidth  
= GetMinWidth(), 
2620         minHeight 
= GetMinHeight(), 
2621         maxWidth  
= GetMaxWidth(), 
2622         maxHeight 
= GetMaxHeight(); 
2624     if ((minWidth  
!= -1) && (m_width  
< minWidth 
)) m_width  
= minWidth
; 
2625     if ((minHeight 
!= -1) && (m_height 
< minHeight
)) m_height 
= minHeight
; 
2626     if ((maxWidth  
!= -1) && (m_width  
> maxWidth 
)) m_width  
= maxWidth
; 
2627     if ((maxHeight 
!= -1) && (m_height 
> maxHeight
)) m_height 
= maxHeight
; 
2629 #if wxUSE_TOOLBAR_NATIVE 
2630     if (wxDynamicCast(GetParent(), wxToolBar
)) 
2632        // don't take the x,y values, they're wrong because toolbar sets them 
2633        GtkWidget  
*widget 
= GTK_WIDGET(m_widget
); 
2634        gtk_widget_set_size_request (widget
, m_width
, m_height
); 
2638     if (m_parent
->m_wxwindow 
== NULL
) // i.e. wxNotebook 
2640         // don't set the size for children of wxNotebook, just take the values. 
2648         GtkPizza 
*pizza 
= GTK_PIZZA(m_parent
->m_wxwindow
); 
2649         if ((sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
) == 0) 
2651             if (x 
!= -1) m_x 
= x 
+ gtk_pizza_get_xoffset( pizza 
); 
2652             if (y 
!= -1) m_y 
= y 
+ gtk_pizza_get_yoffset( pizza 
); 
2656             m_x 
= x 
+ gtk_pizza_get_xoffset( pizza 
); 
2657             m_y 
= y 
+ gtk_pizza_get_yoffset( pizza 
); 
2660         int left_border 
= 0; 
2661         int right_border 
= 0; 
2663         int bottom_border 
= 0; 
2665         /* the default button has a border around it */ 
2666         if (GTK_WIDGET_CAN_DEFAULT(m_widget
)) 
2668             GtkBorder 
*default_border 
= NULL
; 
2669             gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL 
); 
2672                 left_border 
+= default_border
->left
; 
2673                 right_border 
+= default_border
->right
; 
2674                 top_border 
+= default_border
->top
; 
2675                 bottom_border 
+= default_border
->bottom
; 
2676                 g_free( default_border 
); 
2680         DoMoveWindow( m_x
-top_border
, 
2682                       m_width
+left_border
+right_border
, 
2683                       m_height
+top_border
+bottom_border 
); 
2688         /* Sometimes the client area changes size without the 
2689            whole windows's size changing, but if the whole 
2690            windows's size doesn't change, no wxSizeEvent will 
2691            normally be sent. Here we add an extra test if 
2692            the client test has been changed and this will 
2694         GetClientSize( &m_oldClientWidth
, &m_oldClientHeight 
); 
2698     wxPrintf( "OnSize sent from " ); 
2699     if (GetClassInfo() && GetClassInfo()->GetClassName()) 
2700         wxPrintf( GetClassInfo()->GetClassName() ); 
2701     wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height ); 
2704     if (!m_nativeSizeEvent
) 
2706         wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
2707         event
.SetEventObject( this ); 
2708         GetEventHandler()->ProcessEvent( event 
); 
2714 bool wxWindowGTK::GtkShowFromOnIdle() 
2716     if (IsShown() && m_showOnIdle 
&& !GTK_WIDGET_VISIBLE (m_widget
)) 
2718         GtkAllocation alloc
; 
2721         alloc
.width 
= m_width
; 
2722         alloc
.height 
= m_height
; 
2723         gtk_widget_size_allocate( m_widget
, &alloc 
); 
2724         gtk_widget_show( m_widget 
); 
2725         wxShowEvent 
eventShow(GetId(), true); 
2726         eventShow
.SetEventObject(this); 
2727         GetEventHandler()->ProcessEvent(eventShow
); 
2728         m_showOnIdle 
= false; 
2735 void wxWindowGTK::OnInternalIdle() 
2737     // Check if we have to show window now 
2738     if (GtkShowFromOnIdle()) return; 
2740     if ( m_dirtyTabOrder 
) 
2742         m_dirtyTabOrder 
= false; 
2746     // Update style if the window was not yet realized 
2747     // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called 
2748     if (m_needsStyleChange
) 
2750         SetBackgroundStyle(GetBackgroundStyle()); 
2751         m_needsStyleChange 
= false; 
2754     wxCursor cursor 
= m_cursor
; 
2755     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
2759         /* I now set the cursor anew in every OnInternalIdle call 
2760            as setting the cursor in a parent window also effects the 
2761            windows above so that checking for the current cursor is 
2766             GdkWindow 
*window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
2768                 gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
2770             if (!g_globalCursor
.Ok()) 
2771                 cursor 
= *wxSTANDARD_CURSOR
; 
2773             window 
= m_widget
->window
; 
2774             if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
))) 
2775                 gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
2778         else if ( m_widget 
) 
2780             GdkWindow 
*window 
= m_widget
->window
; 
2781             if ( window 
&& !GTK_WIDGET_NO_WINDOW(m_widget
) ) 
2782                gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
2786     if (wxUpdateUIEvent::CanUpdate(this)) 
2787         UpdateWindowUI(wxUPDATE_UI_FROMIDLE
); 
2790 void wxWindowGTK::DoGetSize( int *width
, int *height 
) const 
2792     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2794     if (width
) (*width
) = m_width
; 
2795     if (height
) (*height
) = m_height
; 
2798 void wxWindowGTK::DoSetClientSize( int width
, int height 
) 
2800     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2809             GetScrollbarWidth(m_widget
, dw
, dh
); 
2812         const int border 
= GTK_CONTAINER(m_wxwindow
)->border_width
; 
2820     SetSize(width
, height
); 
2823 void wxWindowGTK::DoGetClientSize( int *width
, int *height 
) const 
2825     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2836             GetScrollbarWidth(m_widget
, dw
, dh
); 
2838         const int border 
= GTK_CONTAINER(m_wxwindow
)->border_width
; 
2850     if (width
) *width 
= w
; 
2851     if (height
) *height 
= h
; 
2854 void wxWindowGTK::DoGetPosition( int *x
, int *y 
) const 
2856     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2860     if (m_parent 
&& m_parent
->m_wxwindow
) 
2862         GtkPizza 
*pizza 
= GTK_PIZZA(m_parent
->m_wxwindow
); 
2863         dx 
= gtk_pizza_get_xoffset( pizza 
); 
2864         dy 
= gtk_pizza_get_yoffset( pizza 
); 
2867     if (m_x 
== -1 && m_y 
== -1) 
2869         GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
2871             source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
2873             source 
= m_widget
->window
; 
2879             gdk_window_get_origin( source
, &org_x
, &org_y 
); 
2882                 GetParent()->ScreenToClient(&org_x
, &org_y
); 
2884             wx_const_cast(wxWindowGTK
*, this)->m_x 
= org_x
; 
2885             wx_const_cast(wxWindowGTK
*, this)->m_y 
= org_y
; 
2889     if (x
) (*x
) = m_x 
- dx
; 
2890     if (y
) (*y
) = m_y 
- dy
; 
2893 void wxWindowGTK::DoClientToScreen( int *x
, int *y 
) const 
2895     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2897     if (!m_widget
->window
) return; 
2899     GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
2901         source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
2903         source 
= m_widget
->window
; 
2907     gdk_window_get_origin( source
, &org_x
, &org_y 
); 
2911         if (GTK_WIDGET_NO_WINDOW (m_widget
)) 
2913             org_x 
+= m_widget
->allocation
.x
; 
2914             org_y 
+= m_widget
->allocation
.y
; 
2921         if (GetLayoutDirection() == wxLayout_RightToLeft
) 
2922             *x 
= (GetClientSize().x 
- *x
) + org_x
; 
2930 void wxWindowGTK::DoScreenToClient( int *x
, int *y 
) const 
2932     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2934     if (!m_widget
->window
) return; 
2936     GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
2938         source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
2940         source 
= m_widget
->window
; 
2944     gdk_window_get_origin( source
, &org_x
, &org_y 
); 
2948         if (GTK_WIDGET_NO_WINDOW (m_widget
)) 
2950             org_x 
+= m_widget
->allocation
.x
; 
2951             org_y 
+= m_widget
->allocation
.y
; 
2957         if (GetLayoutDirection() == wxLayout_RightToLeft
) 
2958             *x 
= (GetClientSize().x 
- *x
) - org_x
; 
2965 bool wxWindowGTK::Show( bool show 
) 
2967     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
2969     if (!wxWindowBase::Show(show
)) 
2979             gtk_widget_show( m_widget 
); 
2980             wxShowEvent 
eventShow(GetId(), show
); 
2981             eventShow
.SetEventObject(this); 
2982             GetEventHandler()->ProcessEvent(eventShow
); 
2987         gtk_widget_hide( m_widget 
); 
2988         wxShowEvent 
eventShow(GetId(), show
); 
2989         eventShow
.SetEventObject(this); 
2990         GetEventHandler()->ProcessEvent(eventShow
); 
2996 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
) 
2998     win
->OnParentEnable(enable
); 
3000     // Recurse, so that children have the opportunity to Do The Right Thing 
3001     // and reset colours that have been messed up by a parent's (really ancestor's) 
3003     for ( wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
3005           node 
= node
->GetNext() ) 
3007         wxWindow 
*child 
= node
->GetData(); 
3008         if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
))) 
3009             wxWindowNotifyEnable(child
, enable
); 
3013 bool wxWindowGTK::Enable( bool enable 
) 
3015     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3017     if (!wxWindowBase::Enable(enable
)) 
3023     gtk_widget_set_sensitive( m_widget
, enable 
); 
3025         gtk_widget_set_sensitive( m_wxwindow
, enable 
); 
3027     wxWindowNotifyEnable(this, enable
); 
3032 int wxWindowGTK::GetCharHeight() const 
3034     wxCHECK_MSG( (m_widget 
!= NULL
), 12, wxT("invalid window") ); 
3036     wxFont font 
= GetFont(); 
3037     wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") ); 
3039     PangoContext 
*context 
= NULL
; 
3041         context 
= gtk_widget_get_pango_context( m_widget 
); 
3046     PangoFontDescription 
*desc 
= font
.GetNativeFontInfo()->description
; 
3047     PangoLayout 
*layout 
= pango_layout_new(context
); 
3048     pango_layout_set_font_description(layout
, desc
); 
3049     pango_layout_set_text(layout
, "H", 1); 
3050     PangoLayoutLine 
*line 
= (PangoLayoutLine 
*)pango_layout_get_lines(layout
)->data
; 
3052     PangoRectangle rect
; 
3053     pango_layout_line_get_extents(line
, NULL
, &rect
); 
3055     g_object_unref (layout
); 
3057     return (int) PANGO_PIXELS(rect
.height
); 
3060 int wxWindowGTK::GetCharWidth() const 
3062     wxCHECK_MSG( (m_widget 
!= NULL
), 8, wxT("invalid window") ); 
3064     wxFont font 
= GetFont(); 
3065     wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") ); 
3067     PangoContext 
*context 
= NULL
; 
3069         context 
= gtk_widget_get_pango_context( m_widget 
); 
3074     PangoFontDescription 
*desc 
= font
.GetNativeFontInfo()->description
; 
3075     PangoLayout 
*layout 
= pango_layout_new(context
); 
3076     pango_layout_set_font_description(layout
, desc
); 
3077     pango_layout_set_text(layout
, "g", 1); 
3078     PangoLayoutLine 
*line 
= (PangoLayoutLine 
*)pango_layout_get_lines(layout
)->data
; 
3080     PangoRectangle rect
; 
3081     pango_layout_line_get_extents(line
, NULL
, &rect
); 
3083     g_object_unref (layout
); 
3085     return (int) PANGO_PIXELS(rect
.width
); 
3088 void wxWindowGTK::GetTextExtent( const wxString
& string
, 
3092                                  int *externalLeading
, 
3093                                  const wxFont 
*theFont 
) const 
3095     wxFont fontToUse 
= theFont 
? *theFont 
: GetFont(); 
3097     wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") ); 
3106     PangoContext 
*context 
= NULL
; 
3108         context 
= gtk_widget_get_pango_context( m_widget 
); 
3117     PangoFontDescription 
*desc 
= fontToUse
.GetNativeFontInfo()->description
; 
3118     PangoLayout 
*layout 
= pango_layout_new(context
); 
3119     pango_layout_set_font_description(layout
, desc
); 
3121         const wxCharBuffer data 
= wxGTK_CONV( string 
); 
3123             pango_layout_set_text(layout
, data
, strlen(data
)); 
3126     PangoRectangle rect
; 
3127     pango_layout_get_extents(layout
, NULL
, &rect
); 
3129     if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
); 
3130     if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
); 
3133         PangoLayoutIter 
*iter 
= pango_layout_get_iter(layout
); 
3134         int baseline 
= pango_layout_iter_get_baseline(iter
); 
3135         pango_layout_iter_free(iter
); 
3136         *descent 
= *y 
- PANGO_PIXELS(baseline
); 
3138     if (externalLeading
) (*externalLeading
) = 0;  // ?? 
3140     g_object_unref (layout
); 
3143 bool wxWindowGTK::GTKSetDelayedFocusIfNeeded() 
3145     if ( g_delayedFocus 
== this ) 
3147         if ( GTK_WIDGET_REALIZED(m_widget
) ) 
3149             gtk_widget_grab_focus(m_widget
); 
3150             g_delayedFocus 
= NULL
; 
3159 void wxWindowGTK::SetFocus() 
3161     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3164         // don't do anything if we already have focus 
3170         if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
)) 
3172             gtk_widget_grab_focus (m_wxwindow
); 
3177         if (GTK_IS_CONTAINER(m_widget
)) 
3179             if (IsKindOf(CLASSINFO(wxRadioButton
))) 
3181                 gtk_widget_grab_focus (m_widget
); 
3185             gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD 
); 
3188         if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) ) 
3191             if (!GTK_WIDGET_REALIZED(m_widget
)) 
3193                 // we can't set the focus to the widget now so we remember that 
3194                 // it should be focused and will do it later, during the idle 
3195                 // time, as soon as we can 
3196                 wxLogTrace(TRACE_FOCUS
, 
3197                            _T("Delaying setting focus to %s(%s)"), 
3198                            GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3200                 g_delayedFocus 
= this; 
3204                 wxLogTrace(TRACE_FOCUS
, 
3205                            _T("Setting focus to %s(%s)"), 
3206                            GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3208                 gtk_widget_grab_focus (m_widget
); 
3213            wxLogTrace(TRACE_FOCUS
, 
3214                       _T("Can't set focus to %s(%s)"), 
3215                       GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3220 bool wxWindowGTK::AcceptsFocus() const 
3222     return m_acceptsFocus 
&& wxWindowBase::AcceptsFocus(); 
3225 bool wxWindowGTK::Reparent( wxWindowBase 
*newParentBase 
) 
3227     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3229     wxWindowGTK 
*oldParent 
= m_parent
, 
3230              *newParent 
= (wxWindowGTK 
*)newParentBase
; 
3232     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3234     if ( !wxWindowBase::Reparent(newParent
) ) 
3237     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3239     /* prevent GTK from deleting the widget arbitrarily */ 
3240     gtk_widget_ref( m_widget 
); 
3244         gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget 
); 
3247     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3251         if (GTK_WIDGET_VISIBLE (newParent
->m_widget
)) 
3253             m_showOnIdle 
= true; 
3254             gtk_widget_hide( m_widget 
); 
3257         /* insert GTK representation */ 
3258         (*(newParent
->m_insertCallback
))(newParent
, this); 
3261     /* reverse: prevent GTK from deleting the widget arbitrarily */ 
3262     gtk_widget_unref( m_widget 
); 
3264     SetLayoutDirection(wxLayout_Default
); 
3269 void wxWindowGTK::DoAddChild(wxWindowGTK 
*child
) 
3271     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
3273     wxASSERT_MSG( (child 
!= NULL
), wxT("invalid child window") ); 
3275     wxASSERT_MSG( (m_insertCallback 
!= NULL
), wxT("invalid child insertion function") ); 
3280     /* insert GTK representation */ 
3281     (*m_insertCallback
)(this, child
); 
3284 void wxWindowGTK::AddChild(wxWindowBase 
*child
) 
3286     wxWindowBase::AddChild(child
); 
3287     m_dirtyTabOrder 
= true; 
3289         wxapp_install_idle_handler(); 
3292 void wxWindowGTK::RemoveChild(wxWindowBase 
*child
) 
3294     wxWindowBase::RemoveChild(child
); 
3295     m_dirtyTabOrder 
= true; 
3297         wxapp_install_idle_handler(); 
3301 wxLayoutDirection 
wxWindowGTK::GTKGetLayout(GtkWidget 
*widget
) 
3303     return gtk_widget_get_direction(GTK_WIDGET(widget
)) == GTK_TEXT_DIR_RTL
 
3304                 ? wxLayout_RightToLeft
 
3305                 : wxLayout_LeftToRight
; 
3309 void wxWindowGTK::GTKSetLayout(GtkWidget 
*widget
, wxLayoutDirection dir
) 
3311     wxASSERT_MSG( dir 
!= wxLayout_Default
, _T("invalid layout direction") ); 
3313     gtk_widget_set_direction(GTK_WIDGET(widget
), 
3314                              dir 
== wxLayout_RightToLeft 
? GTK_TEXT_DIR_RTL
 
3315                                                          : GTK_TEXT_DIR_LTR
); 
3318 wxLayoutDirection 
wxWindowGTK::GetLayoutDirection() const 
3320     return GTKGetLayout(m_widget
); 
3323 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
) 
3325     if ( dir 
== wxLayout_Default 
) 
3327         const wxWindow 
*const parent 
= GetParent(); 
3330             // inherit layout from parent. 
3331             dir 
= parent
->GetLayoutDirection(); 
3333         else // no parent, use global default layout 
3335             dir 
= wxTheApp
->GetLayoutDirection(); 
3339     if ( dir 
== wxLayout_Default 
) 
3342     GTKSetLayout(m_widget
, dir
); 
3345         GTKSetLayout(m_wxwindow
, dir
); 
3349 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
, 
3350                                       wxCoord 
WXUNUSED(width
), 
3351                                       wxCoord 
WXUNUSED(widthTotal
)) const 
3353     // We now mirrors the coordinates of RTL windows in GtkPizza 
3357 void wxWindowGTK::DoMoveInTabOrder(wxWindow 
*win
, MoveKind move
) 
3359     wxWindowBase::DoMoveInTabOrder(win
, move
); 
3360     m_dirtyTabOrder 
= true; 
3362         wxapp_install_idle_handler(); 
3365 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const 
3367     // none needed by default 
3371 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
)) 
3373     // nothing to do by default since none is needed 
3376 void wxWindowGTK::RealizeTabOrder() 
3380         if ( !m_children
.empty() ) 
3382             // we don't only construct the correct focus chain but also use 
3383             // this opportunity to update the mnemonic widgets for the widgets 
3386             GList 
*chain 
= NULL
; 
3387             wxWindowGTK
* mnemonicWindow 
= NULL
; 
3389             for ( wxWindowList::const_iterator i 
= m_children
.begin(); 
3390                   i 
!= m_children
.end(); 
3393                 wxWindowGTK 
*win 
= *i
; 
3395                 if ( mnemonicWindow 
) 
3397                     if ( win
->AcceptsFocusFromKeyboard() ) 
3399                         // wxComboBox et al. needs to focus on on a different 
3400                         // widget than m_widget, so if the main widget isn't 
3401                         // focusable try the connect widget 
3402                         GtkWidget
* w 
= win
->m_widget
; 
3403                         if ( !GTK_WIDGET_CAN_FOCUS(w
) ) 
3405                             w 
= win
->GetConnectWidget(); 
3406                             if ( !GTK_WIDGET_CAN_FOCUS(w
) ) 
3412                             mnemonicWindow
->GTKWidgetDoSetMnemonic(w
); 
3413                             mnemonicWindow 
= NULL
; 
3417                 else if ( win
->GTKWidgetNeedsMnemonic() ) 
3419                     mnemonicWindow 
= win
; 
3422                 chain 
= g_list_prepend(chain
, win
->m_widget
); 
3425             chain 
= g_list_reverse(chain
); 
3427             gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
); 
3432             gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
)); 
3437 void wxWindowGTK::Raise() 
3439     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3441     if (m_wxwindow 
&& m_wxwindow
->window
) 
3443         gdk_window_raise( m_wxwindow
->window 
); 
3445     else if (m_widget
->window
) 
3447         gdk_window_raise( m_widget
->window 
); 
3451 void wxWindowGTK::Lower() 
3453     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3455     if (m_wxwindow 
&& m_wxwindow
->window
) 
3457         gdk_window_lower( m_wxwindow
->window 
); 
3459     else if (m_widget
->window
) 
3461         gdk_window_lower( m_widget
->window 
); 
3465 bool wxWindowGTK::SetCursor( const wxCursor 
&cursor 
) 
3467     if ( !wxWindowBase::SetCursor(cursor
.Ok() ? cursor 
: *wxSTANDARD_CURSOR
) ) 
3475 void wxWindowGTK::GTKUpdateCursor() 
3477     wxCursor 
cursor(g_globalCursor
.Ok() ? g_globalCursor 
: GetCursor()); 
3480         wxArrayGdkWindows windowsThis
; 
3481         GdkWindow 
* const winThis 
= GTKGetWindow(windowsThis
); 
3484             gdk_window_set_cursor(winThis
, cursor
.GetCursor()); 
3488             const size_t count 
= windowsThis
.size(); 
3489             for ( size_t n 
= 0; n 
< count
; n
++ ) 
3491                 GdkWindow 
*win 
= windowsThis
[n
]; 
3494                     wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?")); 
3498                 gdk_window_set_cursor(win
, cursor
.GetCursor()); 
3504 void wxWindowGTK::WarpPointer( int x
, int y 
) 
3506     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3508     // We provide this function ourselves as it is 
3509     // missing in GDK (top of this file). 
3511     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
3513         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3515         window 
= GetConnectWidget()->window
; 
3518         gdk_window_warp_pointer( window
, x
, y 
); 
3521 wxWindowGTK::ScrollDir 
wxWindowGTK::ScrollDirFromRange(GtkRange 
*range
) const 
3523     // find the scrollbar which generated the event 
3524     for ( int dir 
= 0; dir 
< ScrollDir_Max
; dir
++ ) 
3526         if ( range 
== m_scrollBar
[dir
] ) 
3527             return (ScrollDir
)dir
; 
3530     wxFAIL_MSG( _T("event from unknown scrollbar received") ); 
3532     return ScrollDir_Max
; 
3535 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
) 
3537     bool changed 
= false; 
3538     GtkRange
* range 
= m_scrollBar
[dir
]; 
3539     if ( range 
&& units 
) 
3541         GtkAdjustment
* adj 
= range
->adjustment
; 
3542         gdouble inc 
= unit 
== ScrollUnit_Line 
? adj
->step_increment
 
3543                                               : adj
->page_increment
; 
3545         const int posOld 
= int(adj
->value 
+ 0.5); 
3546         gtk_range_set_value(range
, posOld 
+ units
*inc
); 
3548         changed 
= int(adj
->value 
+ 0.5) != posOld
; 
3554 bool wxWindowGTK::ScrollLines(int lines
) 
3556     return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
); 
3559 bool wxWindowGTK::ScrollPages(int pages
) 
3561     return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
); 
3564 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect 
*rect 
) 
3568     if (!m_widget
->window
) 
3573         if (!GTK_PIZZA(m_wxwindow
)->bin_window
) return; 
3575         GdkRectangle gdk_rect
, 
3579             gdk_rect
.x 
= rect
->x
; 
3580             gdk_rect
.y 
= rect
->y
; 
3581             gdk_rect
.width 
= rect
->width
; 
3582             gdk_rect
.height 
= rect
->height
; 
3583             if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3584                 gdk_rect
.x 
= GetClientSize().x 
- gdk_rect
.x 
- gdk_rect
.width
; 
3588         else // invalidate everything 
3593         gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE 
); 
3597 void wxWindowGTK::Update() 
3601     // when we call Update() we really want to update the window immediately on 
3602     // screen, even if it means flushing the entire queue and hence slowing down 
3603     // everything -- but it should still be done, it's just that Update() should 
3604     // be called very rarely 
3608 void wxWindowGTK::GtkUpdate() 
3610     if (m_wxwindow 
&& GTK_PIZZA(m_wxwindow
)->bin_window
) 
3611         gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE 
); 
3612     if (m_widget 
&& m_widget
->window
) 
3613         gdk_window_process_updates( m_widget
->window
, FALSE 
); 
3615     // for consistency with other platforms (and also because it's convenient 
3616     // to be able to update an entire TLW by calling Update() only once), we 
3617     // should also update all our children here 
3618     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
3620           node 
= node
->GetNext() ) 
3622         node
->GetData()->GtkUpdate(); 
3626 bool wxWindowGTK::DoIsExposed( int x
, int y 
) const 
3628     return m_updateRegion
.Contains(x
, y
) != wxOutRegion
; 
3632 bool wxWindowGTK::DoIsExposed( int x
, int y
, int w
, int h 
) const 
3634     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3635         return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
; 
3637         return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
; 
3640 void wxWindowGTK::GtkSendPaintEvents() 
3644         m_updateRegion
.Clear(); 
3648     // Clip to paint region in wxClientDC 
3649     m_clipPaintRegion 
= true; 
3651     m_nativeUpdateRegion 
= m_updateRegion
; 
3653     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3655         // Transform m_updateRegion under RTL 
3656         m_updateRegion
.Clear(); 
3659         gdk_window_get_geometry( GTK_PIZZA(m_wxwindow
)->bin_window
, 
3660                                  NULL
, NULL
, &width
, NULL
, NULL 
); 
3662         wxRegionIterator 
upd( m_nativeUpdateRegion 
); 
3666             rect
.x 
= upd
.GetX(); 
3667             rect
.y 
= upd
.GetY(); 
3668             rect
.width 
= upd
.GetWidth(); 
3669             rect
.height 
= upd
.GetHeight(); 
3671             rect
.x 
= width 
- rect
.x 
- rect
.width
; 
3672             m_updateRegion
.Union( rect 
); 
3678     // widget to draw on 
3679     GtkPizza 
*pizza 
= GTK_PIZZA (m_wxwindow
); 
3681     if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)) 
3683         // find ancestor from which to steal background 
3684         wxWindow 
*parent 
= wxGetTopLevelParent((wxWindow 
*)this); 
3686             parent 
= (wxWindow
*)this; 
3688         if (GTK_WIDGET_MAPPED(parent
->m_widget
)) 
3690             wxRegionIterator 
upd( m_nativeUpdateRegion 
); 
3694                 rect
.x 
= upd
.GetX(); 
3695                 rect
.y 
= upd
.GetY(); 
3696                 rect
.width 
= upd
.GetWidth(); 
3697                 rect
.height 
= upd
.GetHeight(); 
3699                 gtk_paint_flat_box( parent
->m_widget
->style
, 
3701                             (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
), 
3714         wxWindowDC 
dc( (wxWindow
*)this ); 
3715         dc
.SetClippingRegion( m_updateRegion 
); 
3717         wxEraseEvent 
erase_event( GetId(), &dc 
); 
3718         erase_event
.SetEventObject( this ); 
3720         GetEventHandler()->ProcessEvent(erase_event
); 
3723     wxNcPaintEvent 
nc_paint_event( GetId() ); 
3724     nc_paint_event
.SetEventObject( this ); 
3725     GetEventHandler()->ProcessEvent( nc_paint_event 
); 
3727     wxPaintEvent 
paint_event( GetId() ); 
3728     paint_event
.SetEventObject( this ); 
3729     GetEventHandler()->ProcessEvent( paint_event 
); 
3731     m_clipPaintRegion 
= false; 
3733     m_updateRegion
.Clear(); 
3734     m_nativeUpdateRegion
.Clear(); 
3737 void wxWindowGTK::SetDoubleBuffered( bool on 
) 
3739     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3742         gtk_widget_set_double_buffered( m_wxwindow
, on 
); 
3745 bool wxWindowGTK::IsDoubleBuffered() const 
3747     return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow 
); 
3750 void wxWindowGTK::ClearBackground() 
3752     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3756 void wxWindowGTK::DoSetToolTip( wxToolTip 
*tip 
) 
3758     wxWindowBase::DoSetToolTip(tip
); 
3761         m_tooltip
->Apply( (wxWindow 
*)this ); 
3764 void wxWindowGTK::ApplyToolTip( GtkTooltips 
*tips
, const wxChar 
*tip 
) 
3766     wxString 
tmp( tip 
); 
3767     gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL 
); 
3769 #endif // wxUSE_TOOLTIPS 
3771 bool wxWindowGTK::SetBackgroundColour( const wxColour 
&colour 
) 
3773     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3775     if (!wxWindowBase::SetBackgroundColour(colour
)) 
3780         // We need the pixel value e.g. for background clearing. 
3781         m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
)); 
3784     // apply style change (forceStyle=true so that new style is applied 
3785     // even if the bg colour changed from valid to wxNullColour) 
3786     if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
) 
3787         ApplyWidgetStyle(true); 
3792 bool wxWindowGTK::SetForegroundColour( const wxColour 
&colour 
) 
3794     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3796     if (!wxWindowBase::SetForegroundColour(colour
)) 
3803         // We need the pixel value e.g. for background clearing. 
3804         m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
)); 
3807     // apply style change (forceStyle=true so that new style is applied 
3808     // even if the bg colour changed from valid to wxNullColour): 
3809     ApplyWidgetStyle(true); 
3814 PangoContext 
*wxWindowGTK::GtkGetPangoDefaultContext() 
3816     return gtk_widget_get_pango_context( m_widget 
); 
3819 GtkRcStyle 
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
) 
3821     // do we need to apply any changes at all? 
3824          !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() ) 
3829     GtkRcStyle 
*style 
= gtk_rc_style_new(); 
3834             pango_font_description_copy( m_font
.GetNativeFontInfo()->description 
); 
3837     if ( m_foregroundColour
.Ok() ) 
3839         const GdkColor 
*fg 
= m_foregroundColour
.GetColor(); 
3841         style
->fg
[GTK_STATE_NORMAL
] = *fg
; 
3842         style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
; 
3844         style
->fg
[GTK_STATE_PRELIGHT
] = *fg
; 
3845         style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
; 
3847         style
->fg
[GTK_STATE_ACTIVE
] = *fg
; 
3848         style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
; 
3851     if ( m_backgroundColour
.Ok() ) 
3853         const GdkColor 
*bg 
= m_backgroundColour
.GetColor(); 
3855         style
->bg
[GTK_STATE_NORMAL
] = *bg
; 
3856         style
->base
[GTK_STATE_NORMAL
] = *bg
; 
3857         style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
) 
3858             (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG 
| GTK_RC_BASE
); 
3860         style
->bg
[GTK_STATE_PRELIGHT
] = *bg
; 
3861         style
->base
[GTK_STATE_PRELIGHT
] = *bg
; 
3862         style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
) 
3863             (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG 
| GTK_RC_BASE
); 
3865         style
->bg
[GTK_STATE_ACTIVE
] = *bg
; 
3866         style
->base
[GTK_STATE_ACTIVE
] = *bg
; 
3867         style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
) 
3868             (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG 
| GTK_RC_BASE
); 
3870         style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
; 
3871         style
->base
[GTK_STATE_INSENSITIVE
] = *bg
; 
3872         style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
) 
3873             (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG 
| GTK_RC_BASE
); 
3879 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
) 
3881     GtkRcStyle 
*style 
= CreateWidgetStyle(forceStyle
); 
3884         DoApplyWidgetStyle(style
); 
3885         gtk_rc_style_unref(style
); 
3888     // Style change may affect GTK+'s size calculation: 
3889     InvalidateBestSize(); 
3892 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
3895         gtk_widget_modify_style(m_wxwindow
, style
); 
3897         gtk_widget_modify_style(m_widget
, style
); 
3900 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
) 
3902     wxWindowBase::SetBackgroundStyle(style
); 
3904     if (style 
== wxBG_STYLE_CUSTOM
) 
3906         GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
3908             window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3910             window 
= GetConnectWidget()->window
; 
3914             // Make sure GDK/X11 doesn't refresh the window 
3916             gdk_window_set_back_pixmap( window
, None
, False 
); 
3918             Display
* display 
= GDK_WINDOW_DISPLAY(window
); 
3921             m_needsStyleChange 
= false; 
3924             // Do in OnIdle, because the window is not yet available 
3925             m_needsStyleChange 
= true; 
3927         // Don't apply widget style, or we get a grey background 
3931         // apply style change (forceStyle=true so that new style is applied 
3932         // even if the bg colour changed from valid to wxNullColour): 
3933         ApplyWidgetStyle(true); 
3938 #if wxUSE_DRAG_AND_DROP 
3940 void wxWindowGTK::SetDropTarget( wxDropTarget 
*dropTarget 
) 
3942     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3944     GtkWidget 
*dnd_widget 
= GetConnectWidget(); 
3946     if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget 
); 
3948     if (m_dropTarget
) delete m_dropTarget
; 
3949     m_dropTarget 
= dropTarget
; 
3951     if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget 
); 
3954 #endif // wxUSE_DRAG_AND_DROP 
3956 GtkWidget
* wxWindowGTK::GetConnectWidget() 
3958     GtkWidget 
*connect_widget 
= m_widget
; 
3959     if (m_wxwindow
) connect_widget 
= m_wxwindow
; 
3961     return connect_widget
; 
3964 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow 
*window
) const 
3966     wxArrayGdkWindows windowsThis
; 
3967     GdkWindow 
* const winThis 
= GTKGetWindow(windowsThis
); 
3969     return winThis 
? window 
== winThis
 
3970                    : windowsThis
.Index(window
) != wxNOT_FOUND
; 
3973 GdkWindow 
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const 
3975     return m_wxwindow 
? GTK_PIZZA(m_wxwindow
)->bin_window 
: m_widget
->window
; 
3978 bool wxWindowGTK::SetFont( const wxFont 
&font 
) 
3980     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3982     if (!wxWindowBase::SetFont(font
)) 
3985     // apply style change (forceStyle=true so that new style is applied 
3986     // even if the font changed from valid to wxNullFont): 
3987     ApplyWidgetStyle(true); 
3992 void wxWindowGTK::DoCaptureMouse() 
3994     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3996     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
3998         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4000         window 
= GetConnectWidget()->window
; 
4002     wxCHECK_RET( window
, _T("CaptureMouse() failed") ); 
4004     const wxCursor
* cursor 
= &m_cursor
; 
4006         cursor 
= wxSTANDARD_CURSOR
; 
4008     gdk_pointer_grab( window
, FALSE
, 
4010                          (GDK_BUTTON_PRESS_MASK 
| 
4011                           GDK_BUTTON_RELEASE_MASK 
| 
4012                           GDK_POINTER_MOTION_HINT_MASK 
| 
4013                           GDK_POINTER_MOTION_MASK
), 
4015                       cursor
->GetCursor(), 
4016                       (guint32
)GDK_CURRENT_TIME 
); 
4017     g_captureWindow 
= this; 
4018     g_captureWindowHasMouse 
= true; 
4021 void wxWindowGTK::DoReleaseMouse() 
4023     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4025     wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") ); 
4027     g_captureWindow 
= (wxWindowGTK
*) NULL
; 
4029     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4031         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4033         window 
= GetConnectWidget()->window
; 
4038     gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME 
); 
4042 wxWindow 
*wxWindowBase::GetCapture() 
4044     return (wxWindow 
*)g_captureWindow
; 
4047 bool wxWindowGTK::IsRetained() const 
4052 void wxWindowGTK::BlockScrollEvent() 
4054     wxASSERT(!m_blockScrollEvent
); 
4055     m_blockScrollEvent 
= true; 
4058 void wxWindowGTK::UnblockScrollEvent() 
4060     wxASSERT(m_blockScrollEvent
); 
4061     m_blockScrollEvent 
= false; 
4064 void wxWindowGTK::SetScrollbar(int orient
, 
4068                                bool WXUNUSED(update
)) 
4070     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4071     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4075         m_hasScrolling 
= true; 
4079         // GtkRange requires upper > lower 
4084     if (pos 
> range 
- thumbVisible
) 
4085         pos 
= range 
- thumbVisible
; 
4088     GtkAdjustment
* adj 
= m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
; 
4089     adj
->step_increment 
= 1; 
4090     adj
->page_increment 
= 
4091     adj
->page_size 
= thumbVisible
; 
4093     SetScrollPos(orient
, pos
); 
4094     gtk_adjustment_changed(adj
); 
4097 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
)) 
4099     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4100     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4102     // This check is more than an optimization. Without it, the slider 
4103     //   will not move smoothly while tracking when using wxScrollHelper. 
4104     if (GetScrollPos(orient
) != pos
) 
4106         const int dir 
= ScrollDirFromOrient(orient
); 
4107         GtkAdjustment
* adj 
= m_scrollBar
[dir
]->adjustment
; 
4108         const int max 
= int(adj
->upper 
- adj
->page_size
); 
4113         m_scrollPos
[dir
] = adj
->value 
= pos
; 
4115         // If a "value_changed" signal emission is not already in progress 
4116         if (!m_blockValueChanged
[dir
]) 
4118             gtk_adjustment_value_changed(adj
); 
4123 int wxWindowGTK::GetScrollThumb(int orient
) const 
4125     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4126     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4128     return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->page_size
); 
4131 int wxWindowGTK::GetScrollPos( int orient 
) const 
4133     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4134     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4136     return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->value 
+ 0.5); 
4139 int wxWindowGTK::GetScrollRange( int orient 
) const 
4141     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4142     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4144     return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->upper
); 
4147 // Determine if increment is the same as +/-x, allowing for some small 
4148 //   difference due to possible inexactness in floating point arithmetic 
4149 static inline bool IsScrollIncrement(double increment
, double x
) 
4151     wxASSERT(increment 
> 0); 
4152     const double tolerance 
= 1.0 / 1024; 
4153     return fabs(increment 
- fabs(x
)) < tolerance
; 
4156 wxEventType 
wxWindowGTK::GetScrollEventType(GtkRange
* range
) 
4161         wxapp_install_idle_handler(); 
4163     wxASSERT(range 
== m_scrollBar
[0] || range 
== m_scrollBar
[1]); 
4165     const int barIndex 
= range 
== m_scrollBar
[1]; 
4166     GtkAdjustment
* adj 
= range
->adjustment
; 
4168     const int value 
= int(adj
->value 
+ 0.5); 
4170     // save previous position 
4171     const double oldPos 
= m_scrollPos
[barIndex
]; 
4172     // update current position 
4173     m_scrollPos
[barIndex
] = adj
->value
; 
4174     // If event should be ignored, or integral position has not changed 
4175     if (!m_hasVMT 
|| g_blockEventsOnDrag 
|| value 
== int(oldPos 
+ 0.5)) 
4180     wxEventType eventType 
= wxEVT_SCROLL_THUMBTRACK
; 
4183         // Difference from last change event 
4184         const double diff 
= adj
->value 
- oldPos
; 
4185         const bool isDown 
= diff 
> 0; 
4187         if (IsScrollIncrement(adj
->step_increment
, diff
)) 
4189             eventType 
= isDown 
? wxEVT_SCROLL_LINEDOWN 
: wxEVT_SCROLL_LINEUP
; 
4191         else if (IsScrollIncrement(adj
->page_increment
, diff
)) 
4193             eventType 
= isDown 
? wxEVT_SCROLL_PAGEDOWN 
: wxEVT_SCROLL_PAGEUP
; 
4195         else if (m_mouseButtonDown
) 
4197             // Assume track event 
4198             m_isScrolling 
= true; 
4204 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) ) 
4206     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4208     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4210     // No scrolling requested. 
4211     if ((dx 
== 0) && (dy 
== 0)) return; 
4213     m_clipPaintRegion 
= true; 
4215     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
4216         gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), dx
, -dy 
); 
4218         gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy 
); 
4220     m_clipPaintRegion 
= false; 
4223 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
) 
4225     //RN: Note that static controls usually have no border on gtk, so maybe 
4226     //it makes sense to treat that as simply no border at the wx level 
4228     if (!(wxstyle 
& wxNO_BORDER
) && !(wxstyle 
& wxBORDER_STATIC
)) 
4230         GtkShadowType gtkstyle
; 
4232         if(wxstyle 
& wxBORDER_RAISED
) 
4233             gtkstyle 
= GTK_SHADOW_OUT
; 
4234         else if (wxstyle 
& wxBORDER_SUNKEN
) 
4235             gtkstyle 
= GTK_SHADOW_IN
; 
4236         else if (wxstyle 
& wxBORDER_DOUBLE
) 
4237             gtkstyle 
= GTK_SHADOW_ETCHED_IN
; 
4239             gtkstyle 
= GTK_SHADOW_IN
; 
4241         gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
), 
4246 void wxWindowGTK::SetWindowStyleFlag( long style 
) 
4248     // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already 
4249     wxWindowBase::SetWindowStyleFlag(style
); 
4252 // Find the wxWindow at the current mouse position, also returning the mouse 
4254 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
) 
4256     pt 
= wxGetMousePosition(); 
4257     wxWindow
* found 
= wxFindWindowAtPoint(pt
); 
4261 // Get the current mouse position. 
4262 wxPoint 
wxGetMousePosition() 
4264   /* This crashes when used within wxHelpContext, 
4265      so we have to use the X-specific implementation below. 
4267     GdkModifierType *mask; 
4268     (void) gdk_window_get_pointer(NULL, &x, &y, mask); 
4270     return wxPoint(x, y); 
4274     GdkWindow
* windowAtPtr 
= gdk_window_at_pointer(& x
, & y
); 
4276     Display 
*display 
= windowAtPtr 
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY(); 
4277     Window rootWindow 
= RootWindowOfScreen (DefaultScreenOfDisplay(display
)); 
4278     Window rootReturn
, childReturn
; 
4279     int rootX
, rootY
, winX
, winY
; 
4280     unsigned int maskReturn
; 
4282     XQueryPointer (display
, 
4286                    &rootX
, &rootY
, &winX
, &winY
, &maskReturn
); 
4287     return wxPoint(rootX
, rootY
); 
4291 // Needed for implementing e.g. combobox on wxGTK within a modal dialog. 
4292 void wxAddGrab(wxWindow
* window
) 
4294     gtk_grab_add( (GtkWidget
*) window
->GetHandle() ); 
4297 void wxRemoveGrab(wxWindow
* window
) 
4299     gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );