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 // Don't allow event propagation during drag 
 194 bool g_blockEventsOnDrag
; 
 195 // Don't allow mouse event propagation during scroll 
 196 bool g_blockEventsOnScroll
; 
 197 extern wxCursor   g_globalCursor
; 
 199 // mouse capture state: the window which has it and if the mouse is currently 
 201 static wxWindowGTK  
*g_captureWindow 
= (wxWindowGTK
*) NULL
; 
 202 static bool g_captureWindowHasMouse 
= false; 
 204 wxWindowGTK  
*g_focusWindow 
= (wxWindowGTK
*) NULL
; 
 206 // the last window which had the focus - this is normally never NULL (except 
 207 // if we never had focus at all) as even when g_focusWindow is NULL it still 
 208 // keeps its previous value 
 209 wxWindowGTK 
*g_focusWindowLast 
= (wxWindowGTK
*) NULL
; 
 211 // If a window get the focus set but has not been realized 
 212 // yet, defer setting the focus to idle time. 
 213 wxWindowGTK 
*g_delayedFocus 
= (wxWindowGTK
*) NULL
; 
 215 // global variables because GTK+ DnD want to have the 
 216 // mouse event that caused it 
 217 GdkEvent    
*g_lastMouseEvent 
= (GdkEvent
*) NULL
; 
 218 int          g_lastButtonNumber 
= 0; 
 220 extern bool g_mainThreadLocked
; 
 222 //----------------------------------------------------------------------------- 
 224 //----------------------------------------------------------------------------- 
 229 #   define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance"); 
 231 #   define DEBUG_MAIN_THREAD 
 234 #define DEBUG_MAIN_THREAD 
 237 // the trace mask used for the focus debugging messages 
 238 #define TRACE_FOCUS _T("focus") 
 240 //----------------------------------------------------------------------------- 
 241 // missing gdk functions 
 242 //----------------------------------------------------------------------------- 
 245 gdk_window_warp_pointer (GdkWindow      
*window
, 
 250     window 
= gdk_get_default_root_window(); 
 252   if (!GDK_WINDOW_DESTROYED(window
)) 
 254       XWarpPointer (GDK_WINDOW_XDISPLAY(window
), 
 255                     None
,              /* not source window -> move from anywhere */ 
 256                     GDK_WINDOW_XID(window
),  /* dest window */ 
 257                     0, 0, 0, 0,        /* not source window -> move from anywhere */ 
 262 //----------------------------------------------------------------------------- 
 263 // local code (see below) 
 264 //----------------------------------------------------------------------------- 
 266 // returns the child of win which currently has focus or NULL if not found 
 268 // Note: can't be static, needed by textctrl.cpp. 
 269 wxWindow 
*wxFindFocusedChild(wxWindowGTK 
*win
) 
 271     wxWindow 
*winFocus 
= wxWindowGTK::FindFocus(); 
 273         return (wxWindow 
*)NULL
; 
 275     if ( winFocus 
== win 
) 
 276         return (wxWindow 
*)win
; 
 278     for ( wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
 280           node 
= node
->GetNext() ) 
 282         wxWindow 
*child 
= wxFindFocusedChild(node
->GetData()); 
 287     return (wxWindow 
*)NULL
; 
 290 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
) 
 292     GtkScrolledWindow
* scroll_window 
= GTK_SCROLLED_WINDOW(widget
); 
 293     GtkScrolledWindowClass
* scroll_class 
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
)); 
 294     GtkRequisition scroll_req
; 
 297     if (scroll_window
->vscrollbar_visible
) 
 299         scroll_req
.width 
= 2; 
 300         scroll_req
.height 
= 2; 
 301         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request 
) 
 302             (scroll_window
->vscrollbar
, &scroll_req 
); 
 303         w 
= scroll_req
.width 
+ 
 304             scroll_class
->scrollbar_spacing
; 
 308     if (scroll_window
->hscrollbar_visible
) 
 310         scroll_req
.width 
= 2; 
 311         scroll_req
.height 
= 2; 
 312         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request 
) 
 313             (scroll_window
->hscrollbar
, &scroll_req 
); 
 314         h 
= scroll_req
.height 
+ 
 315             scroll_class
->scrollbar_spacing
; 
 319 static void draw_frame( GtkWidget 
*widget
, wxWindowGTK 
*win 
) 
 321     // wxUniversal widgets draw the borders and scrollbars themselves 
 322 #ifndef __WXUNIVERSAL__ 
 328     if (GTK_WIDGET_NO_WINDOW (widget
)) 
 330         dx 
+= widget
->allocation
.x
; 
 331         dy 
+= widget
->allocation
.y
; 
 339     if (win
->m_hasScrolling
) 
 341         GetScrollbarWidth(widget
, dw
, dh
); 
 343         if (win
->GetLayoutDirection() == wxLayout_RightToLeft
) 
 345             // This is actually wrong for old GTK+ version 
 346             // which do not display the scrollbar on the 
 352     int w 
= widget
->allocation
.width
-dw
; 
 353     int h 
= widget
->allocation
.height
-dh
; 
 355     if (win
->HasFlag(wxRAISED_BORDER
)) 
 357         gtk_paint_shadow (widget
->style
, 
 361                           NULL
, NULL
, NULL
, // FIXME: No clipping? 
 366     if (win
->HasFlag(wxSUNKEN_BORDER
)) 
 368         gtk_paint_shadow (widget
->style
, 
 372                           NULL
, NULL
, NULL
, // FIXME: No clipping? 
 377     if (win
->HasFlag(wxSIMPLE_BORDER
)) 
 380         gc 
= gdk_gc_new( widget
->window 
); 
 381         gdk_gc_set_foreground( gc
, &widget
->style
->black 
); 
 382         gdk_draw_rectangle( widget
->window
, gc
, FALSE
, x
, y
, w
-1, h
-1 ); 
 386 #endif // __WXUNIVERSAL__ 
 389 //----------------------------------------------------------------------------- 
 390 // "expose_event" of m_widget 
 391 //----------------------------------------------------------------------------- 
 395 gtk_window_own_expose_callback( GtkWidget 
*widget
, 
 396                                 GdkEventExpose 
*gdk_event
, 
 399     if (gdk_event
->count 
== 0) 
 400         draw_frame(widget
, win
); 
 405 //----------------------------------------------------------------------------- 
 406 // "size_request" of m_widget 
 407 //----------------------------------------------------------------------------- 
 409 // make it extern because wxStaticText needs to disconnect this one 
 411 void wxgtk_window_size_request_callback(GtkWidget 
*widget
, 
 412                                         GtkRequisition 
*requisition
, 
 416     win
->GetSize( &w
, &h 
); 
 422     requisition
->height 
= h
; 
 423     requisition
->width 
= w
; 
 429 void wxgtk_combo_size_request_callback(GtkWidget 
*widget
, 
 430                                        GtkRequisition 
*requisition
, 
 433     // This callback is actually hooked into the text entry 
 434     // of the combo box, not the GtkHBox. 
 437     win
->GetSize( &w
, &h 
); 
 443     GtkCombo 
*gcombo 
= GTK_COMBO(win
->m_widget
); 
 445     GtkRequisition entry_req
; 
 447     entry_req
.height 
= 2; 
 448     (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->entry
) )->size_request 
) 
 449         (gcombo
->entry
, &entry_req 
); 
 451     GtkRequisition button_req
; 
 452     button_req
.width 
= 2; 
 453     button_req
.height 
= 2; 
 454     (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request 
) 
 455         (gcombo
->button
, &button_req 
); 
 457     requisition
->width 
= w 
- button_req
.width
; 
 458     requisition
->height 
= entry_req
.height
; 
 462 //----------------------------------------------------------------------------- 
 463 // "expose_event" of m_wxwindow 
 464 //----------------------------------------------------------------------------- 
 468 gtk_window_expose_callback( GtkWidget 
*widget
, 
 469                             GdkEventExpose 
*gdk_event
, 
 474     // This callback gets called in drawing-idle time under 
 475     // GTK 2.0, so we don't need to defer anything to idle 
 478     GtkPizza 
*pizza 
= GTK_PIZZA( widget 
); 
 479     if (gdk_event
->window 
!= pizza
->bin_window
) 
 481         // block expose events on GTK_WIDGET(pizza)->window, 
 482         //   all drawing is done on pizza->bin_window 
 490         wxPrintf( wxT("OnExpose from ") ); 
 491         if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName()) 
 492             wxPrintf( win
->GetClassInfo()->GetClassName() ); 
 493         wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
, 
 494                                          (int)gdk_event
->area
.y
, 
 495                                          (int)gdk_event
->area
.width
, 
 496                                          (int)gdk_event
->area
.height 
); 
 501         win
->m_wxwindow
->style
, 
 505         (GdkRectangle
*) NULL
, 
 507         (char *)"button", // const_cast 
 512     win
->GetUpdateRegion() = wxRegion( gdk_event
->region 
); 
 514     win
->GtkSendPaintEvents(); 
 516     // Let parent window draw window-less widgets 
 521 //----------------------------------------------------------------------------- 
 522 // "key_press_event" from any window 
 523 //----------------------------------------------------------------------------- 
 525 // These are used when transforming Ctrl-alpha to ascii values 1-26 
 526 inline bool wxIsLowerChar(int code
) 
 528     return (code 
>= 'a' && code 
<= 'z' ); 
 531 inline bool wxIsUpperChar(int code
) 
 533     return (code 
>= 'A' && code 
<= 'Z' ); 
 537 // set WXTRACE to this to see the key event codes on the console 
 538 #define TRACE_KEYS  _T("keyevent") 
 540 // translates an X key symbol to WXK_XXX value 
 542 // if isChar is true it means that the value returned will be used for EVT_CHAR 
 543 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide, 
 544 // for example, while if it is false it means that the value is going to be 
 545 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to 
 547 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
) 
 553         // Shift, Control and Alt don't generate the CHAR events at all 
 556             key_code 
= isChar 
? 0 : WXK_SHIFT
; 
 560             key_code 
= isChar 
? 0 : WXK_CONTROL
; 
 568             key_code 
= isChar 
? 0 : WXK_ALT
; 
 571         // neither do the toggle modifies 
 572         case GDK_Scroll_Lock
: 
 573             key_code 
= isChar 
? 0 : WXK_SCROLL
; 
 577             key_code 
= isChar 
? 0 : WXK_CAPITAL
; 
 581             key_code 
= isChar 
? 0 : WXK_NUMLOCK
; 
 585         // various other special keys 
 598         case GDK_ISO_Left_Tab
: 
 605             key_code 
= WXK_RETURN
; 
 609             key_code 
= WXK_CLEAR
; 
 613             key_code 
= WXK_PAUSE
; 
 617             key_code 
= WXK_SELECT
; 
 621             key_code 
= WXK_PRINT
; 
 625             key_code 
= WXK_EXECUTE
; 
 629             key_code 
= WXK_ESCAPE
; 
 632         // cursor and other extended keyboard keys 
 634             key_code 
= WXK_DELETE
; 
 650             key_code 
= WXK_RIGHT
; 
 657         case GDK_Prior
:     // == GDK_Page_Up 
 658             key_code 
= WXK_PAGEUP
; 
 661         case GDK_Next
:      // == GDK_Page_Down 
 662             key_code 
= WXK_PAGEDOWN
; 
 674             key_code 
= WXK_INSERT
; 
 689             key_code 
= (isChar 
? '0' : WXK_NUMPAD0
) + keysym 
- GDK_KP_0
; 
 693             key_code 
= isChar 
? ' ' : WXK_NUMPAD_SPACE
; 
 697             key_code 
= isChar 
? WXK_TAB 
: WXK_NUMPAD_TAB
; 
 701             key_code 
= isChar 
? WXK_RETURN 
: WXK_NUMPAD_ENTER
; 
 705             key_code 
= isChar 
? WXK_F1 
: WXK_NUMPAD_F1
; 
 709             key_code 
= isChar 
? WXK_F2 
: WXK_NUMPAD_F2
; 
 713             key_code 
= isChar 
? WXK_F3 
: WXK_NUMPAD_F3
; 
 717             key_code 
= isChar 
? WXK_F4 
: WXK_NUMPAD_F4
; 
 721             key_code 
= isChar 
? WXK_HOME 
: WXK_NUMPAD_HOME
; 
 725             key_code 
= isChar 
? WXK_LEFT 
: WXK_NUMPAD_LEFT
; 
 729             key_code 
= isChar 
? WXK_UP 
: WXK_NUMPAD_UP
; 
 733             key_code 
= isChar 
? WXK_RIGHT 
: WXK_NUMPAD_RIGHT
; 
 737             key_code 
= isChar 
? WXK_DOWN 
: WXK_NUMPAD_DOWN
; 
 740         case GDK_KP_Prior
: // == GDK_KP_Page_Up 
 741             key_code 
= isChar 
? WXK_PAGEUP 
: WXK_NUMPAD_PAGEUP
; 
 744         case GDK_KP_Next
: // == GDK_KP_Page_Down 
 745             key_code 
= isChar 
? WXK_PAGEDOWN 
: WXK_NUMPAD_PAGEDOWN
; 
 749             key_code 
= isChar 
? WXK_END 
: WXK_NUMPAD_END
; 
 753             key_code 
= isChar 
? WXK_HOME 
: WXK_NUMPAD_BEGIN
; 
 757             key_code 
= isChar 
? WXK_INSERT 
: WXK_NUMPAD_INSERT
; 
 761             key_code 
= isChar 
? WXK_DELETE 
: WXK_NUMPAD_DELETE
; 
 765             key_code 
= isChar 
? '=' : WXK_NUMPAD_EQUAL
; 
 768         case GDK_KP_Multiply
: 
 769             key_code 
= isChar 
? '*' : WXK_NUMPAD_MULTIPLY
; 
 773             key_code 
= isChar 
? '+' : WXK_NUMPAD_ADD
; 
 776         case GDK_KP_Separator
: 
 777             // FIXME: what is this? 
 778             key_code 
= isChar 
? '.' : WXK_NUMPAD_SEPARATOR
; 
 781         case GDK_KP_Subtract
: 
 782             key_code 
= isChar 
? '-' : WXK_NUMPAD_SUBTRACT
; 
 786             key_code 
= isChar 
? '.' : WXK_NUMPAD_DECIMAL
; 
 790             key_code 
= isChar 
? '/' : WXK_NUMPAD_DIVIDE
; 
 807             key_code 
= WXK_F1 
+ keysym 
- GDK_F1
; 
 817 static inline bool wxIsAsciiKeysym(KeySym ks
) 
 822 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
, 
 824                                       GdkEventKey 
*gdk_event
) 
 828     GdkModifierType state
; 
 829     if (gdk_event
->window
) 
 830         gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
 832     event
.SetTimestamp( gdk_event
->time 
); 
 833     event
.SetId(win
->GetId()); 
 834     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
) != 0; 
 835     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
) != 0; 
 836     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
) != 0; 
 837     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
) != 0; 
 838     event
.m_scanCode 
= gdk_event
->keyval
; 
 839     event
.m_rawCode 
= (wxUint32
) gdk_event
->keyval
; 
 840     event
.m_rawFlags 
= 0; 
 842     event
.m_uniChar 
= gdk_keyval_to_unicode(gdk_event
->keyval
); 
 844     wxGetMousePosition( &x
, &y 
); 
 845     win
->ScreenToClient( &x
, &y 
); 
 848     event
.SetEventObject( win 
); 
 853 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
, 
 855                            GdkEventKey 
*gdk_event
) 
 857     // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string 
 858     //     but only event->keyval which is quite useless to us, so remember 
 859     //     the last character from GDK_KEY_PRESS and reuse it as last resort 
 861     // NB: should be MT-safe as we're always called from the main thread only 
 866     } s_lastKeyPress 
= { 0, 0 }; 
 868     KeySym keysym 
= gdk_event
->keyval
; 
 870     wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"), 
 871                event
.GetEventType() == wxEVT_KEY_UP 
? _T("release") 
 875     long key_code 
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */); 
 879         // do we have the translation or is it a plain ASCII character? 
 880         if ( (gdk_event
->length 
== 1) || wxIsAsciiKeysym(keysym
) ) 
 882             // we should use keysym if it is ASCII as X does some translations 
 883             // like "I pressed while Control is down" => "Ctrl-I" == "TAB" 
 884             // which we don't want here (but which we do use for OnChar()) 
 885             if ( !wxIsAsciiKeysym(keysym
) ) 
 887                 keysym 
= (KeySym
)gdk_event
->string
[0]; 
 890             // we want to always get the same key code when the same key is 
 891             // pressed regardless of the state of the modifiers, i.e. on a 
 892             // standard US keyboard pressing '5' or '%' ('5' key with 
 893             // Shift) should result in the same key code in OnKeyDown(): 
 894             // '5' (although OnChar() will get either '5' or '%'). 
 896             // to do it we first translate keysym to keycode (== scan code) 
 897             // and then back but always using the lower register 
 898             Display 
*dpy 
= (Display 
*)wxGetDisplay(); 
 899             KeyCode keycode 
= XKeysymToKeycode(dpy
, keysym
); 
 901             wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
); 
 903             KeySym keysymNormalized 
= XKeycodeToKeysym(dpy
, keycode
, 0); 
 905             // use the normalized, i.e. lower register, keysym if we've 
 907             key_code 
= keysymNormalized 
? keysymNormalized 
: keysym
; 
 909             // as explained above, we want to have lower register key codes 
 910             // normally but for the letter keys we want to have the upper ones 
 912             // NB: don't use XConvertCase() here, we want to do it for letters 
 914             key_code 
= toupper(key_code
); 
 916         else // non ASCII key, what to do? 
 918             // by default, ignore it 
 921             // but if we have cached information from the last KEY_PRESS 
 922             if ( gdk_event
->type 
== GDK_KEY_RELEASE 
) 
 925                 if ( keysym 
== s_lastKeyPress
.keysym 
) 
 927                     key_code 
= s_lastKeyPress
.keycode
; 
 932         if ( gdk_event
->type 
== GDK_KEY_PRESS 
) 
 934             // remember it to be reused for KEY_UP event later 
 935             s_lastKeyPress
.keysym 
= keysym
; 
 936             s_lastKeyPress
.keycode 
= key_code
; 
 940     wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
); 
 942     // sending unknown key events doesn't really make sense 
 946     // now fill all the other fields 
 947     wxFillOtherKeyEventFields(event
, win
, gdk_event
); 
 949     event
.m_keyCode 
= key_code
; 
 951     if ( gdk_event
->type 
== GDK_KEY_PRESS 
||  gdk_event
->type 
== GDK_KEY_RELEASE 
) 
 953         event
.m_uniChar 
= key_code
; 
 963     GtkIMContext 
*context
; 
 964     GdkEventKey  
*lastKeyEvent
; 
 968         context 
= gtk_im_multicontext_new(); 
 973         g_object_unref (context
); 
 979 gtk_window_key_press_callback( GtkWidget 
*widget
, 
 980                                GdkEventKey 
*gdk_event
, 
 987     if (g_blockEventsOnDrag
) 
 991     wxKeyEvent 
event( wxEVT_KEY_DOWN 
); 
 993     bool return_after_IM 
= false; 
 995     if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) ) 
 997         // Emit KEY_DOWN event 
 998         ret 
= win
->GetEventHandler()->ProcessEvent( event 
); 
1002         // Return after IM processing as we cannot do 
1003         // anything with it anyhow. 
1004         return_after_IM 
= true; 
1007     // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw): 
1008     // When we get a key_press event here, it could be originate 
1009     // from the current widget or its child widgets.  However, only the widget 
1010     // with the INPUT FOCUS can generate the INITIAL key_press event.  That is, 
1011     // if the CURRENT widget doesn't have the FOCUS at all, this event definitely 
1012     // originated from its child widgets and shouldn't be passed to IM context. 
1013     // In fact, what a GTK+ IM should do is filtering keyEvents and convert them 
1014     // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS.  Besides, when current 
1015     // widgets has both IM context and input focus, the event should be filtered 
1016     // by gtk_im_context_filter_keypress(). 
1017     // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns. 
1018     if ((!ret
) && (win
->m_imData 
!= NULL
) && ( wxWindow::FindFocus() == win 
)) 
1020         // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API 
1021         // docs, if IM filter returns true, no further processing should be done. 
1022         // we should send the key_down event anyway. 
1023         bool intercepted_by_IM 
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
); 
1024         win
->m_imData
->lastKeyEvent 
= NULL
; 
1025         if (intercepted_by_IM
) 
1027             wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM")); 
1032     if (return_after_IM
) 
1038         wxWindowGTK 
*ancestor 
= win
; 
1041             int command 
= ancestor
->GetAcceleratorTable()->GetCommand( event 
); 
1044                 wxCommandEvent 
command_event( wxEVT_COMMAND_MENU_SELECTED
, command 
); 
1045                 ret 
= ancestor
->GetEventHandler()->ProcessEvent( command_event 
); 
1048             if (ancestor
->IsTopLevel()) 
1050             ancestor 
= ancestor
->GetParent(); 
1053 #endif // wxUSE_ACCEL 
1055     // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x 
1056     // will only be sent if it is not in an accelerator table. 
1060         KeySym keysym 
= gdk_event
->keyval
; 
1061         // Find key code for EVT_CHAR and EVT_CHAR_HOOK events 
1062         key_code 
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */); 
1065             if ( wxIsAsciiKeysym(keysym
) ) 
1068                 key_code 
= (unsigned char)keysym
; 
1070             // gdk_event->string is actually deprecated 
1071             else if ( gdk_event
->length 
== 1 ) 
1073                 key_code 
= (unsigned char)gdk_event
->string
[0]; 
1079             wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
); 
1081             event
.m_keyCode 
= key_code
; 
1083             // To conform to the docs we need to translate Ctrl-alpha 
1084             // characters to values in the range 1-26. 
1085             if ( event
.ControlDown() && 
1086                  ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) )) 
1088                 if ( wxIsLowerChar(key_code
) ) 
1089                     event
.m_keyCode 
= key_code 
- 'a' + 1; 
1090                 if ( wxIsUpperChar(key_code
) ) 
1091                     event
.m_keyCode 
= key_code 
- 'A' + 1; 
1093                 event
.m_uniChar 
= event
.m_keyCode
; 
1097             // Implement OnCharHook by checking ancestor top level windows 
1098             wxWindow 
*parent 
= win
; 
1099             while (parent 
&& !parent
->IsTopLevel()) 
1100                 parent 
= parent
->GetParent(); 
1103                 event
.SetEventType( wxEVT_CHAR_HOOK 
); 
1104                 ret 
= parent
->GetEventHandler()->ProcessEvent( event 
); 
1109                 event
.SetEventType(wxEVT_CHAR
); 
1110                 ret 
= win
->GetEventHandler()->ProcessEvent( event 
); 
1121 gtk_wxwindow_commit_cb (GtkIMContext 
*context
, 
1125     wxKeyEvent 
event( wxEVT_KEY_DOWN 
); 
1127     // take modifiers, cursor position, timestamp etc. from the last 
1128     // key_press_event that was fed into Input Method: 
1129     if (window
->m_imData
->lastKeyEvent
) 
1131         wxFillOtherKeyEventFields(event
, 
1132                                   window
, window
->m_imData
->lastKeyEvent
); 
1136         event
.SetEventObject( window 
); 
1139     const wxString 
data(wxGTK_CONV_BACK_SYS(str
)); 
1145     // Implement OnCharHook by checking ancestor top level windows 
1146     wxWindow 
*parent 
= window
; 
1147     while (parent 
&& !parent
->IsTopLevel()) 
1148         parent 
= parent
->GetParent(); 
1150     for( wxString::const_iterator pstr 
= data
.begin(); pstr 
!= data
.end(); ++pstr 
) 
1153         event
.m_uniChar 
= *pstr
; 
1154         // Backward compatible for ISO-8859-1 
1155         event
.m_keyCode 
= *pstr 
< 256 ? event
.m_uniChar 
: 0; 
1156         wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
); 
1158         event
.m_keyCode 
= (char)*pstr
; 
1159 #endif  // wxUSE_UNICODE 
1161         // To conform to the docs we need to translate Ctrl-alpha 
1162         // characters to values in the range 1-26. 
1163         if ( event
.ControlDown() && 
1164              ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) )) 
1166             if ( wxIsLowerChar(*pstr
) ) 
1167                 event
.m_keyCode 
= *pstr 
- 'a' + 1; 
1168             if ( wxIsUpperChar(*pstr
) ) 
1169                 event
.m_keyCode 
= *pstr 
- 'A' + 1; 
1171             event
.m_keyCode 
= *pstr 
- 'a' + 1; 
1173             event
.m_uniChar 
= event
.m_keyCode
; 
1179             event
.SetEventType( wxEVT_CHAR_HOOK 
); 
1180             ret 
= parent
->GetEventHandler()->ProcessEvent( event 
); 
1185             event
.SetEventType(wxEVT_CHAR
); 
1186             ret 
= window
->GetEventHandler()->ProcessEvent( event 
); 
1193 //----------------------------------------------------------------------------- 
1194 // "key_release_event" from any window 
1195 //----------------------------------------------------------------------------- 
1199 gtk_window_key_release_callback( GtkWidget 
*widget
, 
1200                                  GdkEventKey 
*gdk_event
, 
1208     if (g_blockEventsOnDrag
) 
1211     wxKeyEvent 
event( wxEVT_KEY_UP 
); 
1212     if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) ) 
1214         // unknown key pressed, ignore (the event would be useless anyhow) 
1218     return win
->GTKProcessEvent(event
); 
1222 // ============================================================================ 
1224 // ============================================================================ 
1226 // ---------------------------------------------------------------------------- 
1227 // mouse event processing helpers 
1228 // ---------------------------------------------------------------------------- 
1230 // init wxMouseEvent with the info from GdkEventXXX struct 
1231 template<typename T
> void InitMouseEvent(wxWindowGTK 
*win
, 
1232                                          wxMouseEvent
& event
, 
1235     event
.SetTimestamp( gdk_event
->time 
); 
1236     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
); 
1237     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
); 
1238     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
); 
1239     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
); 
1240     event
.m_leftDown 
= (gdk_event
->state 
& GDK_BUTTON1_MASK
); 
1241     event
.m_middleDown 
= (gdk_event
->state 
& GDK_BUTTON2_MASK
); 
1242     event
.m_rightDown 
= (gdk_event
->state 
& GDK_BUTTON3_MASK
); 
1244     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1245     event
.m_x 
= (wxCoord
)gdk_event
->x 
- pt
.x
; 
1246     event
.m_y 
= (wxCoord
)gdk_event
->y 
- pt
.y
; 
1248     if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
)) 
1250         // origin in the upper right corner 
1251         int window_width 
= gtk_pizza_get_rtl_offset( GTK_PIZZA(win
->m_wxwindow
) ); 
1252         event
.m_x 
= window_width 
- event
.m_x
; 
1255     event
.SetEventObject( win 
); 
1256     event
.SetId( win
->GetId() ); 
1257     event
.SetTimestamp( gdk_event
->time 
); 
1260 static void AdjustEventButtonState(wxMouseEvent
& event
) 
1262     // GDK reports the old state of the button for a button press event, but 
1263     // for compatibility with MSW and common sense we want m_leftDown be TRUE 
1264     // for a LEFT_DOWN event, not FALSE, so we will invert 
1265     // left/right/middleDown for the corresponding click events 
1267     if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) || 
1268         (event
.GetEventType() == wxEVT_LEFT_DCLICK
) || 
1269         (event
.GetEventType() == wxEVT_LEFT_UP
)) 
1271         event
.m_leftDown 
= !event
.m_leftDown
; 
1275     if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) || 
1276         (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) || 
1277         (event
.GetEventType() == wxEVT_MIDDLE_UP
)) 
1279         event
.m_middleDown 
= !event
.m_middleDown
; 
1283     if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) || 
1284         (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) || 
1285         (event
.GetEventType() == wxEVT_RIGHT_UP
)) 
1287         event
.m_rightDown 
= !event
.m_rightDown
; 
1292 // find the window to send the mouse event too 
1294 wxWindowGTK 
*FindWindowForMouseEvent(wxWindowGTK 
*win
, wxCoord
& x
, wxCoord
& y
) 
1299     if (win
->m_wxwindow
) 
1301         GtkPizza 
*pizza 
= GTK_PIZZA(win
->m_wxwindow
); 
1302         xx 
+= gtk_pizza_get_xoffset( pizza 
); 
1303         yy 
+= gtk_pizza_get_yoffset( pizza 
); 
1306     wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
1309         wxWindowGTK 
*child 
= node
->GetData(); 
1311         node 
= node
->GetNext(); 
1312         if (!child
->IsShown()) 
1315         if (child
->IsTransparentForMouse()) 
1317             // wxStaticBox is transparent in the box itself 
1318             int xx1 
= child
->m_x
; 
1319             int yy1 
= child
->m_y
; 
1320             int xx2 
= child
->m_x 
+ child
->m_width
; 
1321             int yy2 
= child
->m_y 
+ child
->m_height
; 
1324             if (((xx 
>= xx1
) && (xx 
<= xx1
+10) && (yy 
>= yy1
) && (yy 
<= yy2
)) || 
1326                 ((xx 
>= xx2
-10) && (xx 
<= xx2
) && (yy 
>= yy1
) && (yy 
<= yy2
)) || 
1328                 ((xx 
>= xx1
) && (xx 
<= xx2
) && (yy 
>= yy1
) && (yy 
<= yy1
+10)) || 
1330                 ((xx 
>= xx1
) && (xx 
<= xx2
) && (yy 
>= yy2
-1) && (yy 
<= yy2
))) 
1341             if ((child
->m_wxwindow 
== (GtkWidget
*) NULL
) && 
1342                 (child
->m_x 
<= xx
) && 
1343                 (child
->m_y 
<= yy
) && 
1344                 (child
->m_x
+child
->m_width  
>= xx
) && 
1345                 (child
->m_y
+child
->m_height 
>= yy
)) 
1358 // ---------------------------------------------------------------------------- 
1359 // common event handlers helpers 
1360 // ---------------------------------------------------------------------------- 
1362 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const 
1364     // nothing special at this level 
1365     return GetEventHandler()->ProcessEvent(event
); 
1368 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny 
*event
) const 
1374     if (g_blockEventsOnDrag
) 
1376     if (g_blockEventsOnScroll
) 
1379     if (!GTKIsOwnWindow(event
->window
)) 
1385 // overloads for all GDK event types we use here: we need to have this as 
1386 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact, 
1387 // derives from it in the sense that the structs have the same layout 
1388 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T)                                  \ 
1389     static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win)        \ 
1391         return win->GTKCallbackCommonPrologue((GdkEventAny *)event);          \ 
1394 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
) 
1395 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
) 
1396 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
) 
1398 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD 
1400 #define wxCOMMON_CALLBACK_PROLOGUE(event, win)                                \ 
1401     const int rc = wxGtkCallbackCommonPrologue(event, win);                   \ 
1405 // send the wxChildFocusEvent and wxFocusEvent, common code of 
1406 // gtk_window_focus_in_callback() and SetFocus() 
1407 static bool DoSendFocusEvents(wxWindow 
*win
) 
1409     // Notify the parent keeping track of focus for the kbd navigation 
1410     // purposes that we got it. 
1411     wxChildFocusEvent 
eventChildFocus(win
); 
1412     (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
); 
1414     wxFocusEvent 
eventFocus(wxEVT_SET_FOCUS
, win
->GetId()); 
1415     eventFocus
.SetEventObject(win
); 
1417     return win
->GetEventHandler()->ProcessEvent(eventFocus
); 
1420 // all event handlers must have C linkage as they're called from GTK+ C code 
1424 //----------------------------------------------------------------------------- 
1425 // "button_press_event" 
1426 //----------------------------------------------------------------------------- 
1429 gtk_window_button_press_callback( GtkWidget 
*widget
, 
1430                                   GdkEventButton 
*gdk_event
, 
1433     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1435     g_lastButtonNumber 
= gdk_event
->button
; 
1437     if (win
->m_wxwindow 
&& (g_focusWindow 
!= win
) && win
->CanAcceptFocus()) 
1439         gtk_widget_grab_focus( win
->m_wxwindow 
); 
1442     // GDK sends surplus button down events 
1443     // before a double click event. We 
1444     // need to filter these out. 
1445     if ((gdk_event
->type 
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
)) 
1447         GdkEvent 
*peek_event 
= gdk_event_peek(); 
1450             if ((peek_event
->type 
== GDK_2BUTTON_PRESS
) || 
1451                 (peek_event
->type 
== GDK_3BUTTON_PRESS
)) 
1453                 gdk_event_free( peek_event 
); 
1458                 gdk_event_free( peek_event 
); 
1463     wxEventType event_type 
= wxEVT_NULL
; 
1465     // GdkDisplay is a GTK+ 2.2.0 thing 
1466 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0) 
1467     if ( gdk_event
->type 
== GDK_2BUTTON_PRESS 
&& 
1468             !gtk_check_version(2,2,0) && 
1469             gdk_event
->button 
>= 1 && gdk_event
->button 
<= 3 ) 
1471         // Reset GDK internal timestamp variables in order to disable GDK 
1472         // triple click events. GDK will then next time believe no button has 
1473         // been clicked just before, and send a normal button click event. 
1474         GdkDisplay
* display 
= gtk_widget_get_display (widget
); 
1475         display
->button_click_time
[1] = 0; 
1476         display
->button_click_time
[0] = 0; 
1480     if (gdk_event
->button 
== 1) 
1482         // note that GDK generates triple click events which are not supported 
1483         // by wxWidgets but still have to be passed to the app as otherwise 
1484         // clicks would simply go missing 
1485         switch (gdk_event
->type
) 
1487             // we shouldn't get triple clicks at all for GTK2 because we 
1488             // suppress them artificially using the code above but we still 
1489             // should map them to something for GTK1 and not just ignore them 
1490             // as this would lose clicks 
1491             case GDK_3BUTTON_PRESS
:     // we could also map this to DCLICK... 
1492             case GDK_BUTTON_PRESS
: 
1493                 event_type 
= wxEVT_LEFT_DOWN
; 
1496             case GDK_2BUTTON_PRESS
: 
1497                 event_type 
= wxEVT_LEFT_DCLICK
; 
1501                 // just to silence gcc warnings 
1505     else if (gdk_event
->button 
== 2) 
1507         switch (gdk_event
->type
) 
1509             case GDK_3BUTTON_PRESS
: 
1510             case GDK_BUTTON_PRESS
: 
1511                 event_type 
= wxEVT_MIDDLE_DOWN
; 
1514             case GDK_2BUTTON_PRESS
: 
1515                 event_type 
= wxEVT_MIDDLE_DCLICK
; 
1522     else if (gdk_event
->button 
== 3) 
1524         switch (gdk_event
->type
) 
1526             case GDK_3BUTTON_PRESS
: 
1527             case GDK_BUTTON_PRESS
: 
1528                 event_type 
= wxEVT_RIGHT_DOWN
; 
1531             case GDK_2BUTTON_PRESS
: 
1532                 event_type 
= wxEVT_RIGHT_DCLICK
; 
1540     if ( event_type 
== wxEVT_NULL 
) 
1542         // unknown mouse button or click type 
1546     g_lastMouseEvent 
= (GdkEvent
*) gdk_event
; 
1548     wxMouseEvent 
event( event_type 
); 
1549     InitMouseEvent( win
, event
, gdk_event 
); 
1551     AdjustEventButtonState(event
); 
1553     // wxListBox actually gets mouse events from the item, so we need to give it 
1554     // a chance to correct this 
1555     win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
); 
1557     // find the correct window to send the event to: it may be a different one 
1558     // from the one which got it at GTK+ level because some controls don't have 
1559     // their own X window and thus cannot get any events. 
1560     if ( !g_captureWindow 
) 
1561         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1563     // reset the event object and id in case win changed. 
1564     event
.SetEventObject( win 
); 
1565     event
.SetId( win
->GetId() ); 
1567     bool ret 
= win
->GTKProcessEvent( event 
); 
1568     g_lastMouseEvent 
= NULL
; 
1572     if ((event_type 
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&  
1573         (g_focusWindow 
!= win
) && win
->CanAcceptFocus()) 
1575         gtk_widget_grab_focus( win
->m_wxwindow 
); 
1578     if (event_type 
== wxEVT_RIGHT_DOWN
) 
1580         // generate a "context menu" event: this is similar to right mouse 
1581         // click under many GUIs except that it is generated differently 
1582         // (right up under MSW, ctrl-click under Mac, right down here) and 
1584         // (a) it's a command event and so is propagated to the parent 
1585         // (b) under some ports it can be generated from kbd too 
1586         // (c) it uses screen coords (because of (a)) 
1587         wxContextMenuEvent 
evtCtx( 
1590             win
->ClientToScreen(event
.GetPosition())); 
1591         evtCtx
.SetEventObject(win
); 
1592         return win
->GTKProcessEvent(evtCtx
); 
1598 //----------------------------------------------------------------------------- 
1599 // "button_release_event" 
1600 //----------------------------------------------------------------------------- 
1603 gtk_window_button_release_callback( GtkWidget 
*widget
, 
1604                                     GdkEventButton 
*gdk_event
, 
1607     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1609     g_lastButtonNumber 
= 0; 
1611     wxEventType event_type 
= wxEVT_NULL
; 
1613     switch (gdk_event
->button
) 
1616             event_type 
= wxEVT_LEFT_UP
; 
1620             event_type 
= wxEVT_MIDDLE_UP
; 
1624             event_type 
= wxEVT_RIGHT_UP
; 
1628             // unknown button, don't process 
1632     g_lastMouseEvent 
= (GdkEvent
*) gdk_event
; 
1634     wxMouseEvent 
event( event_type 
); 
1635     InitMouseEvent( win
, event
, gdk_event 
); 
1637     AdjustEventButtonState(event
); 
1639     // same wxListBox hack as above 
1640     win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
); 
1642     if ( !g_captureWindow 
) 
1643         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1645     // reset the event object and id in case win changed. 
1646     event
.SetEventObject( win 
); 
1647     event
.SetId( win
->GetId() ); 
1649     bool ret 
= win
->GTKProcessEvent(event
); 
1651     g_lastMouseEvent 
= NULL
; 
1656 //----------------------------------------------------------------------------- 
1657 // "motion_notify_event" 
1658 //----------------------------------------------------------------------------- 
1661 gtk_window_motion_notify_callback( GtkWidget 
*widget
, 
1662                                    GdkEventMotion 
*gdk_event
, 
1665     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1667     if (gdk_event
->is_hint
) 
1671         GdkModifierType state
; 
1672         gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
1677     g_lastMouseEvent 
= (GdkEvent
*) gdk_event
; 
1679     wxMouseEvent 
event( wxEVT_MOTION 
); 
1680     InitMouseEvent(win
, event
, gdk_event
); 
1682     if ( g_captureWindow 
) 
1684         // synthesise a mouse enter or leave event if needed 
1685         GdkWindow 
*winUnderMouse 
= gdk_window_at_pointer(NULL
, NULL
); 
1686         // This seems to be necessary and actually been added to 
1687         // GDK itself in version 2.0.X 
1690         bool hasMouse 
= winUnderMouse 
== gdk_event
->window
; 
1691         if ( hasMouse 
!= g_captureWindowHasMouse 
) 
1693             // the mouse changed window 
1694             g_captureWindowHasMouse 
= hasMouse
; 
1696             wxMouseEvent 
eventM(g_captureWindowHasMouse 
? wxEVT_ENTER_WINDOW
 
1697                                                         : wxEVT_LEAVE_WINDOW
); 
1698             InitMouseEvent(win
, eventM
, gdk_event
); 
1699             eventM
.SetEventObject(win
); 
1700             win
->GTKProcessEvent(eventM
); 
1705         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1707         // reset the event object and id in case win changed. 
1708         event
.SetEventObject( win 
); 
1709         event
.SetId( win
->GetId() ); 
1712     if ( !g_captureWindow 
) 
1714         wxSetCursorEvent 
cevent( event
.m_x
, event
.m_y 
); 
1715         if (win
->GTKProcessEvent( cevent 
)) 
1717             win
->SetCursor( cevent
.GetCursor() ); 
1721     bool ret 
= win
->GTKProcessEvent(event
); 
1723     g_lastMouseEvent 
= NULL
; 
1728 //----------------------------------------------------------------------------- 
1729 // "scroll_event" (mouse wheel event) 
1730 //----------------------------------------------------------------------------- 
1733 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
) 
1737     if (gdk_event
->direction 
!= GDK_SCROLL_UP 
&& 
1738         gdk_event
->direction 
!= GDK_SCROLL_DOWN
) 
1743     wxMouseEvent 
event(wxEVT_MOUSEWHEEL
); 
1744     // Can't use InitMouse macro because scroll events don't have button 
1745     event
.SetTimestamp( gdk_event
->time 
); 
1746     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
); 
1747     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
); 
1748     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
); 
1749     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
); 
1750     event
.m_leftDown 
= (gdk_event
->state 
& GDK_BUTTON1_MASK
); 
1751     event
.m_middleDown 
= (gdk_event
->state 
& GDK_BUTTON2_MASK
); 
1752     event
.m_rightDown 
= (gdk_event
->state 
& GDK_BUTTON3_MASK
); 
1753     event
.m_linesPerAction 
= 3; 
1754     event
.m_wheelDelta 
= 120; 
1755     if (gdk_event
->direction 
== GDK_SCROLL_UP
) 
1756         event
.m_wheelRotation 
= 120; 
1758         event
.m_wheelRotation 
= -120; 
1760     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1761     event
.m_x 
= (wxCoord
)gdk_event
->x 
- pt
.x
; 
1762     event
.m_y 
= (wxCoord
)gdk_event
->y 
- pt
.y
; 
1764     event
.SetEventObject( win 
); 
1765     event
.SetId( win
->GetId() ); 
1766     event
.SetTimestamp( gdk_event
->time 
); 
1768     return win
->GTKProcessEvent(event
); 
1771 //----------------------------------------------------------------------------- 
1773 //----------------------------------------------------------------------------- 
1775 static gboolean 
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
) 
1777     wxContextMenuEvent 
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1)); 
1778     event
.SetEventObject(win
); 
1779     return win
->GTKProcessEvent(event
); 
1782 //----------------------------------------------------------------------------- 
1784 //----------------------------------------------------------------------------- 
1787 gtk_window_focus_in_callback( GtkWidget 
*widget
, 
1788                               GdkEventFocus 
*WXUNUSED(event
), 
1794         gtk_im_context_focus_in(win
->m_imData
->context
); 
1797     g_focusWindow 
= win
; 
1799     wxLogTrace(TRACE_FOCUS
, 
1800                _T("%s: focus in"), win
->GetName().c_str()); 
1803     // caret needs to be informed about focus change 
1804     wxCaret 
*caret 
= win
->GetCaret(); 
1807         caret
->OnSetFocus(); 
1809 #endif // wxUSE_CARET 
1811     gboolean ret 
= FALSE
; 
1813     // does the window itself think that it has the focus? 
1814     if ( !win
->m_hasFocus 
) 
1816         // not yet, notify it 
1817         win
->m_hasFocus 
= true; 
1819         (void)DoSendFocusEvents(win
); 
1824     // Disable default focus handling for custom windows 
1825     // since the default GTK+ handler issues a repaint 
1826     if (win
->m_wxwindow
) 
1832 //----------------------------------------------------------------------------- 
1833 // "focus_out_event" 
1834 //----------------------------------------------------------------------------- 
1837 gtk_window_focus_out_callback( GtkWidget 
*widget
, 
1838                                GdkEventFocus 
*gdk_event
, 
1844         gtk_im_context_focus_out(win
->m_imData
->context
); 
1846     wxLogTrace( TRACE_FOCUS
, 
1847                 _T("%s: focus out"), win
->GetName().c_str() ); 
1850     wxWindowGTK 
*winFocus 
= wxFindFocusedChild(win
); 
1854     g_focusWindow 
= (wxWindowGTK 
*)NULL
; 
1857     // caret needs to be informed about focus change 
1858     wxCaret 
*caret 
= win
->GetCaret(); 
1861         caret
->OnKillFocus(); 
1863 #endif // wxUSE_CARET 
1865     // don't send the window a kill focus event if it thinks that it doesn't 
1866     // have focus already 
1867     if ( win
->m_hasFocus 
) 
1869         // the event handler might delete the window when it loses focus, so 
1870         // check whether this is a custom window before calling it 
1871         const bool has_wxwindow 
= win
->m_wxwindow 
!= NULL
; 
1873         win
->m_hasFocus 
= false; 
1875         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, win
->GetId() ); 
1876         event
.SetEventObject( win 
); 
1878         (void)win
->GTKProcessEvent( event 
); 
1880         // Disable default focus handling for custom windows 
1881         // since the default GTK+ handler issues a repaint 
1886     // continue with normal processing 
1891 wx_window_focus_callback(GtkWidget 
*widget
, 
1892                          GtkDirectionType direction
, 
1895     // the default handler for focus signal in GtkPizza (or, rather, in 
1896     // GtkScrolledWindow from which GtkPizza inherits this behaviour) sets 
1897     // focus to the window itself even if it doesn't accept focus, i.e. has no 
1898     // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing 
1899     // the signal from reaching gtk_scrolled_window_focus() if we don't have 
1900     // any children which might accept focus (we know we don't accept the focus 
1901     // ourselves as this signal is only connected in this case) 
1902     if ( win
->GetChildren().empty() ) 
1903         g_signal_stop_emission_by_name(widget
, "focus"); 
1905     // we didn't change the focus 
1909 //----------------------------------------------------------------------------- 
1910 // "enter_notify_event" 
1911 //----------------------------------------------------------------------------- 
1914 gtk_window_enter_callback( GtkWidget 
*widget
, 
1915                            GdkEventCrossing 
*gdk_event
, 
1918     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1920     // Event was emitted after a grab 
1921     if (gdk_event
->mode 
!= GDK_CROSSING_NORMAL
) return FALSE
; 
1925     GdkModifierType state 
= (GdkModifierType
)0; 
1927     gdk_window_get_pointer( widget
->window
, &x
, &y
, &state 
); 
1929     wxMouseEvent 
event( wxEVT_ENTER_WINDOW 
); 
1930     InitMouseEvent(win
, event
, gdk_event
); 
1931     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1932     event
.m_x 
= x 
+ pt
.x
; 
1933     event
.m_y 
= y 
+ pt
.y
; 
1935     if ( !g_captureWindow 
) 
1937         wxSetCursorEvent 
cevent( event
.m_x
, event
.m_y 
); 
1938         if (win
->GTKProcessEvent( cevent 
)) 
1940             win
->SetCursor( cevent
.GetCursor() ); 
1944     return win
->GTKProcessEvent(event
); 
1947 //----------------------------------------------------------------------------- 
1948 // "leave_notify_event" 
1949 //----------------------------------------------------------------------------- 
1952 gtk_window_leave_callback( GtkWidget 
*widget
, 
1953                            GdkEventCrossing 
*gdk_event
, 
1956     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1958     // Event was emitted after an ungrab 
1959     if (gdk_event
->mode 
!= GDK_CROSSING_NORMAL
) return FALSE
; 
1961     wxMouseEvent 
event( wxEVT_LEAVE_WINDOW 
); 
1962     event
.SetTimestamp( gdk_event
->time 
); 
1963     event
.SetEventObject( win 
); 
1967     GdkModifierType state 
= (GdkModifierType
)0; 
1969     gdk_window_get_pointer( widget
->window
, &x
, &y
, &state 
); 
1971     event
.m_shiftDown 
= (state 
& GDK_SHIFT_MASK
) != 0; 
1972     event
.m_controlDown 
= (state 
& GDK_CONTROL_MASK
) != 0; 
1973     event
.m_altDown 
= (state 
& GDK_MOD1_MASK
) != 0; 
1974     event
.m_metaDown 
= (state 
& GDK_MOD2_MASK
) != 0; 
1975     event
.m_leftDown 
= (state 
& GDK_BUTTON1_MASK
) != 0; 
1976     event
.m_middleDown 
= (state 
& GDK_BUTTON2_MASK
) != 0; 
1977     event
.m_rightDown 
= (state 
& GDK_BUTTON3_MASK
) != 0; 
1979     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1980     event
.m_x 
= x 
+ pt
.x
; 
1981     event
.m_y 
= y 
+ pt
.y
; 
1983     return win
->GTKProcessEvent(event
); 
1986 //----------------------------------------------------------------------------- 
1987 // "value_changed" from scrollbar 
1988 //----------------------------------------------------------------------------- 
1991 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
) 
1993     wxEventType eventType 
= win
->GetScrollEventType(range
); 
1994     if (eventType 
!= wxEVT_NULL
) 
1996         // Convert scroll event type to scrollwin event type 
1997         eventType 
+= wxEVT_SCROLLWIN_TOP 
- wxEVT_SCROLL_TOP
; 
1999         // find the scrollbar which generated the event 
2000         wxWindowGTK::ScrollDir dir 
= win
->ScrollDirFromRange(range
); 
2002         // generate the corresponding wx event 
2003         const int orient 
= wxWindow::OrientFromScrollDir(dir
); 
2004         wxScrollWinEvent 
event(eventType
, win
->GetScrollPos(orient
), orient
); 
2005         event
.SetEventObject(win
); 
2007         win
->GTKProcessEvent(event
); 
2011 //----------------------------------------------------------------------------- 
2012 // "button_press_event" from scrollbar 
2013 //----------------------------------------------------------------------------- 
2016 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
) 
2020     g_blockEventsOnScroll 
= true; 
2021     win
->m_mouseButtonDown 
= true; 
2026 //----------------------------------------------------------------------------- 
2027 // "event_after" from scrollbar 
2028 //----------------------------------------------------------------------------- 
2031 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
) 
2033     if (event
->type 
== GDK_BUTTON_RELEASE
) 
2035         g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
); 
2037         const int orient 
= wxWindow::OrientFromScrollDir( 
2038                                         win
->ScrollDirFromRange(range
)); 
2039         wxScrollWinEvent 
event(wxEVT_SCROLLWIN_THUMBRELEASE
, win
->GetScrollPos(orient
), orient
); 
2040         event
.SetEventObject(win
); 
2041         win
->GTKProcessEvent(event
); 
2045 //----------------------------------------------------------------------------- 
2046 // "button_release_event" from scrollbar 
2047 //----------------------------------------------------------------------------- 
2050 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
) 
2054     g_blockEventsOnScroll 
= false; 
2055     win
->m_mouseButtonDown 
= false; 
2056     // If thumb tracking 
2057     if (win
->m_isScrolling
) 
2059         win
->m_isScrolling 
= false; 
2060         // Hook up handler to send thumb release event after this emission is finished. 
2061         // To allow setting scroll position from event handler, sending event must 
2062         // be deferred until after the GtkRange handler for this signal has run 
2063         g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
); 
2069 //----------------------------------------------------------------------------- 
2070 // "realize" from m_widget 
2071 //----------------------------------------------------------------------------- 
2074 gtk_window_realized_callback( GtkWidget 
*m_widget
, wxWindow 
*win 
) 
2080         GtkPizza 
*pizza 
= GTK_PIZZA( m_widget 
); 
2081         gtk_im_context_set_client_window( win
->m_imData
->context
, 
2082                                           pizza
->bin_window 
); 
2085     // We cannot set colours and fonts before the widget 
2086     // been realized, so we do this directly after realization 
2087     // or otherwise in idle time 
2089     if (win
->m_needsStyleChange
) 
2091         win
->SetBackgroundStyle(win
->GetBackgroundStyle()); 
2092         win
->m_needsStyleChange 
= false; 
2095     wxWindowCreateEvent 
event( win 
); 
2096     event
.SetEventObject( win 
); 
2097     win
->GTKProcessEvent( event 
); 
2100 //----------------------------------------------------------------------------- 
2102 //----------------------------------------------------------------------------- 
2105 void gtk_window_size_callback( GtkWidget 
*WXUNUSED(widget
), 
2106                                GtkAllocation 
*alloc
, 
2109     int client_width 
= 0; 
2110     int client_height 
= 0; 
2111     win
->GetClientSize( &client_width
, &client_height 
); 
2112     if ((client_width 
== win
->m_oldClientWidth
) && (client_height 
== win
->m_oldClientHeight
)) 
2115     if ( !client_width 
&& !client_height 
) 
2117         // the window is currently unmapped, don't generate size events 
2121     win
->m_oldClientWidth 
= client_width
; 
2122     win
->m_oldClientHeight 
= client_height
; 
2124     if (!win
->m_nativeSizeEvent
) 
2126         wxSizeEvent 
event( win
->GetSize(), win
->GetId() ); 
2127         event
.SetEventObject( win 
); 
2128         win
->GTKProcessEvent( event 
); 
2134 // ---------------------------------------------------------------------------- 
2135 // this wxWindowBase function is implemented here (in platform-specific file) 
2136 // because it is static and so couldn't be made virtual 
2137 // ---------------------------------------------------------------------------- 
2139 wxWindow 
*wxWindowBase::DoFindFocus() 
2141     // the cast is necessary when we compile in wxUniversal mode 
2142     return (wxWindow 
*)g_focusWindow
; 
2145 //----------------------------------------------------------------------------- 
2146 // InsertChild for wxWindowGTK. 
2147 //----------------------------------------------------------------------------- 
2149 /* Callback for wxWindowGTK. This very strange beast has to be used because 
2150  * C++ has no virtual methods in a constructor. We have to emulate a 
2151  * virtual function here as wxNotebook requires a different way to insert 
2152  * a child in it. I had opted for creating a wxNotebookPage window class 
2153  * which would have made this superfluous (such in the MDI window system), 
2154  * but no-one was listening to me... */ 
2156 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child 
) 
2158     /* the window might have been scrolled already, do we 
2159        have to adapt the position */ 
2160     GtkPizza 
*pizza 
= GTK_PIZZA(parent
->m_wxwindow
); 
2161     child
->m_x 
+= gtk_pizza_get_xoffset( pizza 
); 
2162     child
->m_y 
+= gtk_pizza_get_yoffset( pizza 
); 
2164     gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
), 
2172 //----------------------------------------------------------------------------- 
2174 //----------------------------------------------------------------------------- 
2176 wxWindow 
*wxGetActiveWindow() 
2178     return wxWindow::FindFocus(); 
2182 wxMouseState 
wxGetMouseState() 
2188     GdkModifierType mask
; 
2190     gdk_window_get_pointer(NULL
, &x
, &y
, &mask
); 
2194     ms
.SetLeftDown(mask 
& GDK_BUTTON1_MASK
); 
2195     ms
.SetMiddleDown(mask 
& GDK_BUTTON2_MASK
); 
2196     ms
.SetRightDown(mask 
& GDK_BUTTON3_MASK
); 
2198     ms
.SetControlDown(mask 
& GDK_CONTROL_MASK
); 
2199     ms
.SetShiftDown(mask 
& GDK_SHIFT_MASK
); 
2200     ms
.SetAltDown(mask 
& GDK_MOD1_MASK
); 
2201     ms
.SetMetaDown(mask 
& GDK_MOD2_MASK
); 
2206 //----------------------------------------------------------------------------- 
2208 //----------------------------------------------------------------------------- 
2210 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu() 
2212 #ifdef __WXUNIVERSAL__ 
2213     IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
) 
2215     IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
) 
2216 #endif // __WXUNIVERSAL__/__WXGTK__ 
2218 void wxWindowGTK::Init() 
2221     m_widget 
= (GtkWidget 
*) NULL
; 
2222     m_wxwindow 
= (GtkWidget 
*) NULL
; 
2223     m_focusWidget 
= (GtkWidget 
*) NULL
; 
2232     m_isBeingDeleted 
= false; 
2234     m_showOnIdle
= false; 
2237     m_nativeSizeEvent 
= false; 
2239     m_hasScrolling 
= false; 
2240     m_isScrolling 
= false; 
2241     m_mouseButtonDown 
= false; 
2242     m_blockScrollEvent 
= false; 
2244     // initialize scrolling stuff 
2245     for ( int dir 
= 0; dir 
< ScrollDir_Max
; dir
++ ) 
2247         m_scrollBar
[dir
] = NULL
; 
2248         m_scrollPos
[dir
] = 0; 
2252     m_oldClientHeight 
= 0; 
2256     m_insertCallback 
= wxInsertChildInWindow
; 
2260     m_clipPaintRegion 
= false; 
2262     m_needsStyleChange 
= false; 
2264     m_cursor 
= *wxSTANDARD_CURSOR
; 
2267     m_dirtyTabOrder 
= false; 
2270 wxWindowGTK::wxWindowGTK() 
2275 wxWindowGTK::wxWindowGTK( wxWindow 
*parent
, 
2280                           const wxString 
&name  
) 
2284     Create( parent
, id
, pos
, size
, style
, name 
); 
2287 bool wxWindowGTK::Create( wxWindow 
*parent
, 
2292                           const wxString 
&name  
) 
2294     if (!PreCreation( parent
, pos
, size 
) || 
2295         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
2297         wxFAIL_MSG( wxT("wxWindowGTK creation failed") ); 
2301     if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
)) 
2303         m_wxwindow 
= gtk_pizza_new_no_scroll(); 
2305 #ifndef __WXUNIVERSAL__ 
2306         if (HasFlag(wxSIMPLE_BORDER
)) 
2307             gtk_container_set_border_width((GtkContainer
*)m_wxwindow
, 1); 
2308         else if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
)) 
2309             gtk_container_set_border_width((GtkContainer
*)m_wxwindow
, 2); 
2310 #endif // __WXUNIVERSAL__ 
2312         m_widget 
= m_wxwindow
; 
2316         m_wxwindow 
= gtk_pizza_new(); 
2318 #ifndef __WXUNIVERSAL__ 
2319         if (HasFlag(wxSIMPLE_BORDER
)) 
2320             gtk_container_set_border_width((GtkContainer
*)m_wxwindow
, 1); 
2321         else if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
)) 
2322             gtk_container_set_border_width((GtkContainer
*)m_wxwindow
, 2); 
2323 #endif // __WXUNIVERSAL__ 
2325         m_widget 
= gtk_scrolled_window_new( (GtkAdjustment 
*) NULL
, (GtkAdjustment 
*) NULL 
); 
2327         GtkScrolledWindow 
*scrolledWindow 
= GTK_SCROLLED_WINDOW(m_widget
); 
2329         GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) ); 
2330         scroll_class
->scrollbar_spacing 
= 0; 
2332         // There is a conflict with default bindings at GTK+ 
2333         // level between scrolled windows and notebooks both of which want to use 
2334         // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal 
2335         // direction and notebooks for changing pages -- we decide that if we don't 
2336         // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it 
2337         // means we can get working keyboard navigation in notebooks 
2338         if ( !HasFlag(wxHSCROLL
) ) 
2341                 bindings 
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
)); 
2344                 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
); 
2345                 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
); 
2349         if (HasFlag(wxALWAYS_SHOW_SB
)) 
2351             gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS 
); 
2353             scrolledWindow
->hscrollbar_visible 
= TRUE
; 
2354             scrolledWindow
->vscrollbar_visible 
= TRUE
; 
2358             gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC 
); 
2361         m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
); 
2362         m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
); 
2363         if (GetLayoutDirection() == wxLayout_RightToLeft
) 
2364             gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE 
); 
2366         gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow 
); 
2368         // connect various scroll-related events 
2369         for ( int dir 
= 0; dir 
< ScrollDir_Max
; dir
++ ) 
2371             // these handlers block mouse events to any window during scrolling 
2372             // such as motion events and prevent GTK and wxWidgets from fighting 
2373             // over where the slider should be 
2374             g_signal_connect(m_scrollBar
[dir
], "button_press_event", 
2375                          G_CALLBACK(gtk_scrollbar_button_press_event
), this); 
2376             g_signal_connect(m_scrollBar
[dir
], "button_release_event", 
2377                          G_CALLBACK(gtk_scrollbar_button_release_event
), this); 
2379             gulong handler_id 
= g_signal_connect(m_scrollBar
[dir
], "event_after", 
2380                                 G_CALLBACK(gtk_scrollbar_event_after
), this); 
2381             g_signal_handler_block(m_scrollBar
[dir
], handler_id
); 
2383             // these handlers get notified when scrollbar slider moves 
2384             g_signal_connect_after(m_scrollBar
[dir
], "value_changed", 
2385                          G_CALLBACK(gtk_scrollbar_value_changed
), this); 
2388         gtk_widget_show( m_wxwindow 
); 
2392         m_parent
->DoAddChild( this ); 
2394     m_focusWidget 
= m_wxwindow
; 
2401 wxWindowGTK::~wxWindowGTK() 
2405     if (g_focusWindow 
== this) 
2406         g_focusWindow 
= NULL
; 
2408     if ( g_delayedFocus 
== this ) 
2409         g_delayedFocus 
= NULL
; 
2411     m_isBeingDeleted 
= true; 
2414     // destroy children before destroying this window itself 
2417     // unhook focus handlers to prevent stray events being 
2418     // propagated to this (soon to be) dead object 
2419     if (m_focusWidget 
!= NULL
) 
2421         g_signal_handlers_disconnect_by_func (m_focusWidget
, 
2422                                               (gpointer
) gtk_window_focus_in_callback
, 
2424         g_signal_handlers_disconnect_by_func (m_focusWidget
, 
2425                                               (gpointer
) gtk_window_focus_out_callback
, 
2432     // delete before the widgets to avoid a crash on solaris 
2435     if (m_wxwindow 
&& (m_wxwindow 
!= m_widget
)) 
2437         gtk_widget_destroy( m_wxwindow 
); 
2438         m_wxwindow 
= (GtkWidget
*) NULL
; 
2443         gtk_widget_destroy( m_widget 
); 
2444         m_widget 
= (GtkWidget
*) NULL
; 
2448 bool wxWindowGTK::PreCreation( wxWindowGTK 
*parent
, const wxPoint 
&pos
,  const wxSize 
&size 
) 
2450     if ( GTKNeedsParent() ) 
2452         wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") ); 
2455     // Use either the given size, or the default if -1 is given. 
2456     // See wxWindowBase for these functions. 
2457     m_width 
= WidthDefault(size
.x
) ; 
2458     m_height 
= HeightDefault(size
.y
); 
2466 void wxWindowGTK::PostCreation() 
2468     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2474             // these get reported to wxWidgets -> wxPaintEvent 
2476             g_signal_connect (m_wxwindow
, "expose_event", 
2477                               G_CALLBACK (gtk_window_expose_callback
), this); 
2479             if (GetLayoutDirection() == wxLayout_LeftToRight
) 
2480                 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE 
) ); 
2483         // Create input method handler 
2484         m_imData 
= new wxGtkIMData
; 
2486         // Cannot handle drawing preedited text yet 
2487         gtk_im_context_set_use_preedit( m_imData
->context
, FALSE 
); 
2489         g_signal_connect (m_imData
->context
, "commit", 
2490                           G_CALLBACK (gtk_wxwindow_commit_cb
), this); 
2492         // these are called when the "sunken" or "raised" borders are drawn 
2493         g_signal_connect (m_widget
, "expose_event", 
2494                           G_CALLBACK (gtk_window_own_expose_callback
), this); 
2499     if (!GTK_IS_WINDOW(m_widget
)) 
2501         if (m_focusWidget 
== NULL
) 
2502             m_focusWidget 
= m_widget
; 
2506             g_signal_connect (m_focusWidget
, "focus_in_event", 
2507                           G_CALLBACK (gtk_window_focus_in_callback
), this); 
2508             g_signal_connect (m_focusWidget
, "focus_out_event", 
2509                                 G_CALLBACK (gtk_window_focus_out_callback
), this); 
2513             g_signal_connect_after (m_focusWidget
, "focus_in_event", 
2514                           G_CALLBACK (gtk_window_focus_in_callback
), this); 
2515             g_signal_connect_after (m_focusWidget
, "focus_out_event", 
2516                                 G_CALLBACK (gtk_window_focus_out_callback
), this); 
2520     if ( !AcceptsFocusFromKeyboard() ) 
2524         g_signal_connect(m_widget
, "focus", 
2525                             G_CALLBACK(wx_window_focus_callback
), this); 
2528     // connect to the various key and mouse handlers 
2530     GtkWidget 
*connect_widget 
= GetConnectWidget(); 
2532     ConnectWidget( connect_widget 
); 
2534     /* We cannot set colours, fonts and cursors before the widget has 
2535        been realized, so we do this directly after realization */ 
2536     g_signal_connect (connect_widget
, "realize", 
2537                       G_CALLBACK (gtk_window_realized_callback
), this); 
2541         // Catch native resize events 
2542         g_signal_connect (m_wxwindow
, "size_allocate", 
2543                           G_CALLBACK (gtk_window_size_callback
), this); 
2546     if (GTK_IS_COMBO(m_widget
)) 
2548         GtkCombo 
*gcombo 
= GTK_COMBO(m_widget
); 
2550         g_signal_connect (gcombo
->entry
, "size_request", 
2551                           G_CALLBACK (wxgtk_combo_size_request_callback
), 
2554 #ifdef GTK_IS_FILE_CHOOSER_BUTTON 
2555     else if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget
)) 
2557         // If we connect to the "size_request" signal of a GtkFileChooserButton 
2558         // then that control won't be sized properly when placed inside sizers 
2559         // (this can be tested removing this elseif and running XRC or WIDGETS samples) 
2560         // FIXME: what should be done here ? 
2563     else if ( !IsTopLevel() ) // top level windows use their own callback 
2565         // This is needed if we want to add our windows into native 
2566         // GTK controls, such as the toolbar. With this callback, the 
2567         // toolbar gets to know the correct size (the one set by the 
2568         // programmer). Sadly, it misbehaves for wxComboBox. 
2569         g_signal_connect (m_widget
, "size_request", 
2570                           G_CALLBACK (wxgtk_window_size_request_callback
), 
2574     InheritAttributes(); 
2578     SetLayoutDirection(wxLayout_Default
); 
2580     // unless the window was created initially hidden (i.e. Hide() had been 
2581     // called before Create()), we should show it at GTK+ level as well 
2583         gtk_widget_show( m_widget 
); 
2586 void wxWindowGTK::ConnectWidget( GtkWidget 
*widget 
) 
2588     g_signal_connect (widget
, "key_press_event", 
2589                       G_CALLBACK (gtk_window_key_press_callback
), this); 
2590     g_signal_connect (widget
, "key_release_event", 
2591                       G_CALLBACK (gtk_window_key_release_callback
), this); 
2592     g_signal_connect (widget
, "button_press_event", 
2593                       G_CALLBACK (gtk_window_button_press_callback
), this); 
2594     g_signal_connect (widget
, "button_release_event", 
2595                       G_CALLBACK (gtk_window_button_release_callback
), this); 
2596     g_signal_connect (widget
, "motion_notify_event", 
2597                       G_CALLBACK (gtk_window_motion_notify_callback
), this); 
2598     g_signal_connect (widget
, "scroll_event", 
2599                       G_CALLBACK (window_scroll_event
), this); 
2600     g_signal_connect (widget
, "popup_menu", 
2601                      G_CALLBACK (wxgtk_window_popup_menu_callback
), this); 
2602     g_signal_connect (widget
, "enter_notify_event", 
2603                       G_CALLBACK (gtk_window_enter_callback
), this); 
2604     g_signal_connect (widget
, "leave_notify_event", 
2605                       G_CALLBACK (gtk_window_leave_callback
), this); 
2608 bool wxWindowGTK::Destroy() 
2610     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2614     return wxWindowBase::Destroy(); 
2617 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
) 
2619     // inform the parent to perform the move 
2620     gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height 
); 
2624 void wxWindowGTK::ConstrainSize() 
2627     // GPE's window manager doesn't like size hints at all, esp. when the user 
2628     // has to use the virtual keyboard, so don't constrain size there 
2632         const wxSize minSize 
= GetMinSize(); 
2633         const wxSize maxSize 
= GetMaxSize(); 
2634         if (minSize
.x 
> 0 && m_width  
< minSize
.x
) m_width  
= minSize
.x
; 
2635         if (minSize
.y 
> 0 && m_height 
< minSize
.y
) m_height 
= minSize
.y
; 
2636         if (maxSize
.x 
> 0 && m_width  
> maxSize
.x
) m_width  
= maxSize
.x
; 
2637         if (maxSize
.y 
> 0 && m_height 
> maxSize
.y
) m_height 
= maxSize
.y
; 
2641 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
2643     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2644     wxASSERT_MSG( (m_parent 
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") ); 
2646     if (m_resizing
) return; /* I don't like recursions */ 
2649     int currentX
, currentY
; 
2650     GetPosition(¤tX
, ¤tY
); 
2651     if (x 
== -1 && !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
2653     if (y 
== -1 && !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
2655     AdjustForParentClientOrigin(x
, y
, sizeFlags
); 
2657     // calculate the best size if we should auto size the window 
2658     if ( ((sizeFlags 
& wxSIZE_AUTO_WIDTH
) && width 
== -1) || 
2659          ((sizeFlags 
& wxSIZE_AUTO_HEIGHT
) && height 
== -1) ) 
2661         const wxSize sizeBest 
= GetBestSize(); 
2662         if ( (sizeFlags 
& wxSIZE_AUTO_WIDTH
) && width 
== -1 ) 
2664         if ( (sizeFlags 
& wxSIZE_AUTO_HEIGHT
) && height 
== -1 ) 
2665             height 
= sizeBest
.y
; 
2675 #if wxUSE_TOOLBAR_NATIVE 
2676     if (wxDynamicCast(GetParent(), wxToolBar
)) 
2678        // don't take the x,y values, they're wrong because toolbar sets them 
2679        GtkWidget  
*widget 
= m_widget
; 
2680        gtk_widget_set_size_request (widget
, m_width
, m_height
); 
2684     if (m_parent
->m_wxwindow 
== NULL
) // i.e. wxNotebook 
2686         // don't set the size for children of wxNotebook, just take the values. 
2694         GtkPizza 
*pizza 
= GTK_PIZZA(m_parent
->m_wxwindow
); 
2695         if ((sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
) == 0) 
2697             if (x 
!= -1) m_x 
= x 
+ gtk_pizza_get_xoffset( pizza 
); 
2698             if (y 
!= -1) m_y 
= y 
+ gtk_pizza_get_yoffset( pizza 
); 
2702             m_x 
= x 
+ gtk_pizza_get_xoffset( pizza 
); 
2703             m_y 
= y 
+ gtk_pizza_get_yoffset( pizza 
); 
2706         int left_border 
= 0; 
2707         int right_border 
= 0; 
2709         int bottom_border 
= 0; 
2711         /* the default button has a border around it */ 
2712         if (GTK_WIDGET_CAN_DEFAULT(m_widget
)) 
2714             GtkBorder 
*default_border 
= NULL
; 
2715             gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL 
); 
2718                 left_border 
+= default_border
->left
; 
2719                 right_border 
+= default_border
->right
; 
2720                 top_border 
+= default_border
->top
; 
2721                 bottom_border 
+= default_border
->bottom
; 
2722                 gtk_border_free( default_border 
); 
2726         DoMoveWindow( m_x 
- left_border
, 
2728                       m_width
+left_border
+right_border
, 
2729                       m_height
+top_border
+bottom_border 
); 
2734         /* Sometimes the client area changes size without the 
2735            whole windows's size changing, but if the whole 
2736            windows's size doesn't change, no wxSizeEvent will 
2737            normally be sent. Here we add an extra test if 
2738            the client test has been changed and this will 
2740         GetClientSize( &m_oldClientWidth
, &m_oldClientHeight 
); 
2744     wxPrintf( "OnSize sent from " ); 
2745     if (GetClassInfo() && GetClassInfo()->GetClassName()) 
2746         wxPrintf( GetClassInfo()->GetClassName() ); 
2747     wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height ); 
2750     if (!m_nativeSizeEvent
) 
2752         wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
2753         event
.SetEventObject( this ); 
2754         GetEventHandler()->ProcessEvent( event 
); 
2760 bool wxWindowGTK::GtkShowFromOnIdle() 
2762     if (IsShown() && m_showOnIdle 
&& !GTK_WIDGET_VISIBLE (m_widget
)) 
2764         GtkAllocation alloc
; 
2767         alloc
.width 
= m_width
; 
2768         alloc
.height 
= m_height
; 
2769         gtk_widget_size_allocate( m_widget
, &alloc 
); 
2770         gtk_widget_show( m_widget 
); 
2771         wxShowEvent 
eventShow(GetId(), true); 
2772         eventShow
.SetEventObject(this); 
2773         GetEventHandler()->ProcessEvent(eventShow
); 
2774         m_showOnIdle 
= false; 
2781 void wxWindowGTK::OnInternalIdle() 
2783     // Check if we have to show window now 
2784     if (GtkShowFromOnIdle()) return; 
2786     if ( m_dirtyTabOrder 
) 
2788         m_dirtyTabOrder 
= false; 
2792     // Update style if the window was not yet realized 
2793     // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called 
2794     if (m_needsStyleChange
) 
2796         SetBackgroundStyle(GetBackgroundStyle()); 
2797         m_needsStyleChange 
= false; 
2800     wxCursor cursor 
= m_cursor
; 
2801     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
2805         /* I now set the cursor anew in every OnInternalIdle call 
2806            as setting the cursor in a parent window also effects the 
2807            windows above so that checking for the current cursor is 
2810         if (m_wxwindow 
&& (m_wxwindow 
!= m_widget
)) 
2812             GdkWindow 
*window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
2814                 gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
2816             if (!g_globalCursor
.Ok()) 
2817                 cursor 
= *wxSTANDARD_CURSOR
; 
2819             window 
= m_widget
->window
; 
2820             if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
))) 
2821                 gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
2824         else if ( m_widget 
) 
2826             GdkWindow 
*window 
= m_widget
->window
; 
2827             if ( window 
&& !GTK_WIDGET_NO_WINDOW(m_widget
) ) 
2828                gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
2832     if (wxUpdateUIEvent::CanUpdate(this)) 
2833         UpdateWindowUI(wxUPDATE_UI_FROMIDLE
); 
2836 void wxWindowGTK::DoGetSize( int *width
, int *height 
) const 
2838     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2840     if (width
) (*width
) = m_width
; 
2841     if (height
) (*height
) = m_height
; 
2844 void wxWindowGTK::DoSetClientSize( int width
, int height 
) 
2846     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2848     const wxSize size 
= GetSize(); 
2849     const wxSize clientSize 
= GetClientSize(); 
2850     SetSize(width 
+ (size
.x 
- clientSize
.x
), height 
+ (size
.y 
- clientSize
.y
)); 
2853 void wxWindowGTK::DoGetClientSize( int *width
, int *height 
) const 
2855     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2866             GetScrollbarWidth(m_widget
, dw
, dh
); 
2868         const int border 
= GTK_CONTAINER(m_wxwindow
)->border_width
; 
2880     if (width
) *width 
= w
; 
2881     if (height
) *height 
= h
; 
2884 void wxWindowGTK::DoGetPosition( int *x
, int *y 
) const 
2886     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2890     if (m_parent 
&& m_parent
->m_wxwindow
) 
2892         GtkPizza 
*pizza 
= GTK_PIZZA(m_parent
->m_wxwindow
); 
2893         dx 
= gtk_pizza_get_xoffset( pizza 
); 
2894         dy 
= gtk_pizza_get_yoffset( pizza 
); 
2897     if (m_x 
== -1 && m_y 
== -1) 
2899         GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
2901             source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
2903             source 
= m_widget
->window
; 
2909             gdk_window_get_origin( source
, &org_x
, &org_y 
); 
2912                 m_parent
->ScreenToClient(&org_x
, &org_y
); 
2914             wx_const_cast(wxWindowGTK
*, this)->m_x 
= org_x
; 
2915             wx_const_cast(wxWindowGTK
*, this)->m_y 
= org_y
; 
2919     if (x
) (*x
) = m_x 
- dx
; 
2920     if (y
) (*y
) = m_y 
- dy
; 
2923 void wxWindowGTK::DoClientToScreen( int *x
, int *y 
) const 
2925     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2927     if (!m_widget
->window
) return; 
2929     GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
2931         source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
2933         source 
= m_widget
->window
; 
2937     gdk_window_get_origin( source
, &org_x
, &org_y 
); 
2941         if (GTK_WIDGET_NO_WINDOW (m_widget
)) 
2943             org_x 
+= m_widget
->allocation
.x
; 
2944             org_y 
+= m_widget
->allocation
.y
; 
2951         if (GetLayoutDirection() == wxLayout_RightToLeft
) 
2952             *x 
= (GetClientSize().x 
- *x
) + org_x
; 
2960 void wxWindowGTK::DoScreenToClient( int *x
, int *y 
) const 
2962     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2964     if (!m_widget
->window
) return; 
2966     GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
2968         source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
2970         source 
= m_widget
->window
; 
2974     gdk_window_get_origin( source
, &org_x
, &org_y 
); 
2978         if (GTK_WIDGET_NO_WINDOW (m_widget
)) 
2980             org_x 
+= m_widget
->allocation
.x
; 
2981             org_y 
+= m_widget
->allocation
.y
; 
2987         if (GetLayoutDirection() == wxLayout_RightToLeft
) 
2988             *x 
= (GetClientSize().x 
- *x
) - org_x
; 
2995 bool wxWindowGTK::Show( bool show 
) 
2997     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
2999     if (!wxWindowBase::Show(show
)) 
3009             gtk_widget_show( m_widget 
); 
3010             wxShowEvent 
eventShow(GetId(), show
); 
3011             eventShow
.SetEventObject(this); 
3012             GetEventHandler()->ProcessEvent(eventShow
); 
3017         gtk_widget_hide( m_widget 
); 
3018         wxShowEvent 
eventShow(GetId(), show
); 
3019         eventShow
.SetEventObject(this); 
3020         GetEventHandler()->ProcessEvent(eventShow
); 
3026 void wxWindowGTK::DoEnable( bool enable 
) 
3028     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3030     gtk_widget_set_sensitive( m_widget
, enable 
); 
3031     if (m_wxwindow 
&& (m_wxwindow 
!= m_widget
)) 
3032         gtk_widget_set_sensitive( m_wxwindow
, enable 
); 
3035 int wxWindowGTK::GetCharHeight() const 
3037     wxCHECK_MSG( (m_widget 
!= NULL
), 12, wxT("invalid window") ); 
3039     wxFont font 
= GetFont(); 
3040     wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") ); 
3042     PangoContext 
*context 
= NULL
; 
3044         context 
= gtk_widget_get_pango_context( m_widget 
); 
3049     PangoFontDescription 
*desc 
= font
.GetNativeFontInfo()->description
; 
3050     PangoLayout 
*layout 
= pango_layout_new(context
); 
3051     pango_layout_set_font_description(layout
, desc
); 
3052     pango_layout_set_text(layout
, "H", 1); 
3053     PangoLayoutLine 
*line 
= (PangoLayoutLine 
*)pango_layout_get_lines(layout
)->data
; 
3055     PangoRectangle rect
; 
3056     pango_layout_line_get_extents(line
, NULL
, &rect
); 
3058     g_object_unref (layout
); 
3060     return (int) PANGO_PIXELS(rect
.height
); 
3063 int wxWindowGTK::GetCharWidth() const 
3065     wxCHECK_MSG( (m_widget 
!= NULL
), 8, wxT("invalid window") ); 
3067     wxFont font 
= GetFont(); 
3068     wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") ); 
3070     PangoContext 
*context 
= NULL
; 
3072         context 
= gtk_widget_get_pango_context( m_widget 
); 
3077     PangoFontDescription 
*desc 
= font
.GetNativeFontInfo()->description
; 
3078     PangoLayout 
*layout 
= pango_layout_new(context
); 
3079     pango_layout_set_font_description(layout
, desc
); 
3080     pango_layout_set_text(layout
, "g", 1); 
3081     PangoLayoutLine 
*line 
= (PangoLayoutLine 
*)pango_layout_get_lines(layout
)->data
; 
3083     PangoRectangle rect
; 
3084     pango_layout_line_get_extents(line
, NULL
, &rect
); 
3086     g_object_unref (layout
); 
3088     return (int) PANGO_PIXELS(rect
.width
); 
3091 void wxWindowGTK::GetTextExtent( const wxString
& string
, 
3095                                  int *externalLeading
, 
3096                                  const wxFont 
*theFont 
) const 
3098     wxFont fontToUse 
= theFont 
? *theFont 
: GetFont(); 
3100     wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") ); 
3109     PangoContext 
*context 
= NULL
; 
3111         context 
= gtk_widget_get_pango_context( m_widget 
); 
3120     PangoFontDescription 
*desc 
= fontToUse
.GetNativeFontInfo()->description
; 
3121     PangoLayout 
*layout 
= pango_layout_new(context
); 
3122     pango_layout_set_font_description(layout
, desc
); 
3124         const wxCharBuffer data 
= wxGTK_CONV( string 
); 
3126             pango_layout_set_text(layout
, data
, strlen(data
)); 
3129     PangoRectangle rect
; 
3130     pango_layout_get_extents(layout
, NULL
, &rect
); 
3132     if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
); 
3133     if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
); 
3136         PangoLayoutIter 
*iter 
= pango_layout_get_iter(layout
); 
3137         int baseline 
= pango_layout_iter_get_baseline(iter
); 
3138         pango_layout_iter_free(iter
); 
3139         *descent 
= *y 
- PANGO_PIXELS(baseline
); 
3141     if (externalLeading
) (*externalLeading
) = 0;  // ?? 
3143     g_object_unref (layout
); 
3146 bool wxWindowGTK::GTKSetDelayedFocusIfNeeded() 
3148     if ( g_delayedFocus 
== this ) 
3150         if ( GTK_WIDGET_REALIZED(m_widget
) ) 
3152             gtk_widget_grab_focus(m_widget
); 
3153             g_delayedFocus 
= NULL
; 
3162 void wxWindowGTK::SetFocus() 
3164     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3167         // don't do anything if we already have focus 
3173         if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
)) 
3175             gtk_widget_grab_focus (m_wxwindow
); 
3180         if (GTK_IS_CONTAINER(m_widget
)) 
3182             if (IsKindOf(CLASSINFO(wxRadioButton
))) 
3184                 gtk_widget_grab_focus (m_widget
); 
3188             gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD 
); 
3191         if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) ) 
3194             if (!GTK_WIDGET_REALIZED(m_widget
)) 
3196                 // we can't set the focus to the widget now so we remember that 
3197                 // it should be focused and will do it later, during the idle 
3198                 // time, as soon as we can 
3199                 wxLogTrace(TRACE_FOCUS
, 
3200                            _T("Delaying setting focus to %s(%s)"), 
3201                            GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3203                 g_delayedFocus 
= this; 
3207                 wxLogTrace(TRACE_FOCUS
, 
3208                            _T("Setting focus to %s(%s)"), 
3209                            GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3211                 gtk_widget_grab_focus (m_widget
); 
3216            wxLogTrace(TRACE_FOCUS
, 
3217                       _T("Can't set focus to %s(%s)"), 
3218                       GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3223 void wxWindowGTK::SetCanFocus(bool canFocus
) 
3226         GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
); 
3228         GTK_WIDGET_UNSET_FLAGS(m_widget
, GTK_CAN_FOCUS
); 
3230     if ( m_wxwindow 
&& (m_widget 
!= m_wxwindow
) ) 
3233             GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
); 
3235             GTK_WIDGET_UNSET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
); 
3239 bool wxWindowGTK::Reparent( wxWindowBase 
*newParentBase 
) 
3241     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3243     wxWindowGTK 
*oldParent 
= m_parent
, 
3244              *newParent 
= (wxWindowGTK 
*)newParentBase
; 
3246     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3248     if ( !wxWindowBase::Reparent(newParent
) ) 
3251     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3253     /* prevent GTK from deleting the widget arbitrarily */ 
3254     gtk_widget_ref( m_widget 
); 
3258         gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget 
); 
3261     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3265         if (GTK_WIDGET_VISIBLE (newParent
->m_widget
)) 
3267             m_showOnIdle 
= true; 
3268             gtk_widget_hide( m_widget 
); 
3271         /* insert GTK representation */ 
3272         (*(newParent
->m_insertCallback
))(newParent
, this); 
3275     /* reverse: prevent GTK from deleting the widget arbitrarily */ 
3276     gtk_widget_unref( m_widget 
); 
3278     SetLayoutDirection(wxLayout_Default
); 
3283 void wxWindowGTK::DoAddChild(wxWindowGTK 
*child
) 
3285     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
3286     wxASSERT_MSG( (child 
!= NULL
), wxT("invalid child window") ); 
3291     /* insert GTK representation */ 
3292     (*m_insertCallback
)(this, child
); 
3295 void wxWindowGTK::AddChild(wxWindowBase 
*child
) 
3297     wxWindowBase::AddChild(child
); 
3298     m_dirtyTabOrder 
= true; 
3299     wxTheApp
->WakeUpIdle(); 
3302 void wxWindowGTK::RemoveChild(wxWindowBase 
*child
) 
3304     wxWindowBase::RemoveChild(child
); 
3305     m_dirtyTabOrder 
= true; 
3306     wxTheApp
->WakeUpIdle(); 
3310 wxLayoutDirection 
wxWindowGTK::GTKGetLayout(GtkWidget 
*widget
) 
3312     return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
 
3313                 ? wxLayout_RightToLeft
 
3314                 : wxLayout_LeftToRight
; 
3318 void wxWindowGTK::GTKSetLayout(GtkWidget 
*widget
, wxLayoutDirection dir
) 
3320     wxASSERT_MSG( dir 
!= wxLayout_Default
, _T("invalid layout direction") ); 
3322     gtk_widget_set_direction(widget
, 
3323                              dir 
== wxLayout_RightToLeft 
? GTK_TEXT_DIR_RTL
 
3324                                                          : GTK_TEXT_DIR_LTR
); 
3327 wxLayoutDirection 
wxWindowGTK::GetLayoutDirection() const 
3329     return GTKGetLayout(m_widget
); 
3332 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
) 
3334     if ( dir 
== wxLayout_Default 
) 
3336         const wxWindow 
*const parent 
= GetParent(); 
3339             // inherit layout from parent. 
3340             dir 
= parent
->GetLayoutDirection(); 
3342         else // no parent, use global default layout 
3344             dir 
= wxTheApp
->GetLayoutDirection(); 
3348     if ( dir 
== wxLayout_Default 
) 
3351     GTKSetLayout(m_widget
, dir
); 
3353     if (m_wxwindow 
&& (m_wxwindow 
!= m_widget
)) 
3354         GTKSetLayout(m_wxwindow
, dir
); 
3358 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
, 
3359                                       wxCoord 
WXUNUSED(width
), 
3360                                       wxCoord 
WXUNUSED(widthTotal
)) const 
3362     // We now mirrors the coordinates of RTL windows in GtkPizza 
3366 void wxWindowGTK::DoMoveInTabOrder(wxWindow 
*win
, MoveKind move
) 
3368     wxWindowBase::DoMoveInTabOrder(win
, move
); 
3369     m_dirtyTabOrder 
= true; 
3370     wxTheApp
->WakeUpIdle(); 
3373 bool wxWindowGTK::DoNavigateIn(int flags
) 
3375     if ( flags 
& wxNavigationKeyEvent::WinChange 
) 
3377         wxFAIL_MSG( _T("not implemented") ); 
3381     else // navigate inside the container 
3383         wxWindow 
*parent 
= wxGetTopLevelParent(this); 
3384         wxCHECK_MSG( parent
, false, _T("every window must have a TLW parent") ); 
3386         GtkDirectionType dir
; 
3387         dir 
= flags 
& wxNavigationKeyEvent::IsForward 
? GTK_DIR_TAB_FORWARD
 
3388                                                       : GTK_DIR_TAB_BACKWARD
; 
3391         g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
); 
3397 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const 
3399     // none needed by default 
3403 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
)) 
3405     // nothing to do by default since none is needed 
3408 void wxWindowGTK::RealizeTabOrder() 
3412         if ( !m_children
.empty() ) 
3414             // we don't only construct the correct focus chain but also use 
3415             // this opportunity to update the mnemonic widgets for the widgets 
3418             GList 
*chain 
= NULL
; 
3419             wxWindowGTK
* mnemonicWindow 
= NULL
; 
3421             for ( wxWindowList::const_iterator i 
= m_children
.begin(); 
3422                   i 
!= m_children
.end(); 
3425                 wxWindowGTK 
*win 
= *i
; 
3427                 if ( mnemonicWindow 
) 
3429                     if ( win
->AcceptsFocusFromKeyboard() ) 
3431                         // wxComboBox et al. needs to focus on on a different 
3432                         // widget than m_widget, so if the main widget isn't 
3433                         // focusable try the connect widget 
3434                         GtkWidget
* w 
= win
->m_widget
; 
3435                         if ( !GTK_WIDGET_CAN_FOCUS(w
) ) 
3437                             w 
= win
->GetConnectWidget(); 
3438                             if ( !GTK_WIDGET_CAN_FOCUS(w
) ) 
3444                             mnemonicWindow
->GTKWidgetDoSetMnemonic(w
); 
3445                             mnemonicWindow 
= NULL
; 
3449                 else if ( win
->GTKWidgetNeedsMnemonic() ) 
3451                     mnemonicWindow 
= win
; 
3454                 chain 
= g_list_prepend(chain
, win
->m_widget
); 
3457             chain 
= g_list_reverse(chain
); 
3459             gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
); 
3464             gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
)); 
3469 void wxWindowGTK::Raise() 
3471     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3473     if (m_wxwindow 
&& m_wxwindow
->window
) 
3475         gdk_window_raise( m_wxwindow
->window 
); 
3477     else if (m_widget
->window
) 
3479         gdk_window_raise( m_widget
->window 
); 
3483 void wxWindowGTK::Lower() 
3485     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3487     if (m_wxwindow 
&& m_wxwindow
->window
) 
3489         gdk_window_lower( m_wxwindow
->window 
); 
3491     else if (m_widget
->window
) 
3493         gdk_window_lower( m_widget
->window 
); 
3497 bool wxWindowGTK::SetCursor( const wxCursor 
&cursor 
) 
3499     if ( !wxWindowBase::SetCursor(cursor
.Ok() ? cursor 
: *wxSTANDARD_CURSOR
) ) 
3507 void wxWindowGTK::GTKUpdateCursor() 
3509     wxCursor 
cursor(g_globalCursor
.Ok() ? g_globalCursor 
: GetCursor()); 
3512         wxArrayGdkWindows windowsThis
; 
3513         GdkWindow 
* const winThis 
= GTKGetWindow(windowsThis
); 
3516             gdk_window_set_cursor(winThis
, cursor
.GetCursor()); 
3520             const size_t count 
= windowsThis
.size(); 
3521             for ( size_t n 
= 0; n 
< count
; n
++ ) 
3523                 GdkWindow 
*win 
= windowsThis
[n
]; 
3526                     wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?")); 
3530                 gdk_window_set_cursor(win
, cursor
.GetCursor()); 
3536 void wxWindowGTK::WarpPointer( int x
, int y 
) 
3538     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3540     // We provide this function ourselves as it is 
3541     // missing in GDK (top of this file). 
3543     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
3545         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3547         window 
= GetConnectWidget()->window
; 
3550         gdk_window_warp_pointer( window
, x
, y 
); 
3553 wxWindowGTK::ScrollDir 
wxWindowGTK::ScrollDirFromRange(GtkRange 
*range
) const 
3555     // find the scrollbar which generated the event 
3556     for ( int dir 
= 0; dir 
< ScrollDir_Max
; dir
++ ) 
3558         if ( range 
== m_scrollBar
[dir
] ) 
3559             return (ScrollDir
)dir
; 
3562     wxFAIL_MSG( _T("event from unknown scrollbar received") ); 
3564     return ScrollDir_Max
; 
3567 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
) 
3569     bool changed 
= false; 
3570     GtkRange
* range 
= m_scrollBar
[dir
]; 
3571     if ( range 
&& units 
) 
3573         GtkAdjustment
* adj 
= range
->adjustment
; 
3574         gdouble inc 
= unit 
== ScrollUnit_Line 
? adj
->step_increment
 
3575                                               : adj
->page_increment
; 
3577         const int posOld 
= int(adj
->value 
+ 0.5); 
3578         gtk_range_set_value(range
, posOld 
+ units
*inc
); 
3580         changed 
= int(adj
->value 
+ 0.5) != posOld
; 
3586 bool wxWindowGTK::ScrollLines(int lines
) 
3588     return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
); 
3591 bool wxWindowGTK::ScrollPages(int pages
) 
3593     return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
); 
3596 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect 
*rect 
) 
3600     if (!m_widget
->window
) 
3605         if (!GTK_PIZZA(m_wxwindow
)->bin_window
) return; 
3607         GdkRectangle gdk_rect
, 
3611             gdk_rect
.x 
= rect
->x
; 
3612             gdk_rect
.y 
= rect
->y
; 
3613             gdk_rect
.width 
= rect
->width
; 
3614             gdk_rect
.height 
= rect
->height
; 
3615             if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3616                 gdk_rect
.x 
= GetClientSize().x 
- gdk_rect
.x 
- gdk_rect
.width
; 
3620         else // invalidate everything 
3625         gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE 
); 
3629 void wxWindowGTK::Update() 
3633     // when we call Update() we really want to update the window immediately on 
3634     // screen, even if it means flushing the entire queue and hence slowing down 
3635     // everything -- but it should still be done, it's just that Update() should 
3636     // be called very rarely 
3640 void wxWindowGTK::GtkUpdate() 
3642     if (m_wxwindow 
&& GTK_PIZZA(m_wxwindow
)->bin_window
) 
3643         gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE 
); 
3644     if (m_widget 
&& m_widget
->window 
&& (m_wxwindow 
!= m_widget
)) 
3645         gdk_window_process_updates( m_widget
->window
, FALSE 
); 
3647     // for consistency with other platforms (and also because it's convenient 
3648     // to be able to update an entire TLW by calling Update() only once), we 
3649     // should also update all our children here 
3650     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
3652           node 
= node
->GetNext() ) 
3654         node
->GetData()->GtkUpdate(); 
3658 bool wxWindowGTK::DoIsExposed( int x
, int y 
) const 
3660     return m_updateRegion
.Contains(x
, y
) != wxOutRegion
; 
3664 bool wxWindowGTK::DoIsExposed( int x
, int y
, int w
, int h 
) const 
3666     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3667         return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
; 
3669         return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
; 
3672 void wxWindowGTK::GtkSendPaintEvents() 
3676         m_updateRegion
.Clear(); 
3680     // Clip to paint region in wxClientDC 
3681     m_clipPaintRegion 
= true; 
3683     m_nativeUpdateRegion 
= m_updateRegion
; 
3685     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3687         // Transform m_updateRegion under RTL 
3688         m_updateRegion
.Clear(); 
3691         gdk_window_get_geometry( GTK_PIZZA(m_wxwindow
)->bin_window
, 
3692                                  NULL
, NULL
, &width
, NULL
, NULL 
); 
3694         wxRegionIterator 
upd( m_nativeUpdateRegion 
); 
3698             rect
.x 
= upd
.GetX(); 
3699             rect
.y 
= upd
.GetY(); 
3700             rect
.width 
= upd
.GetWidth(); 
3701             rect
.height 
= upd
.GetHeight(); 
3703             rect
.x 
= width 
- rect
.x 
- rect
.width
; 
3704             m_updateRegion
.Union( rect 
); 
3710     // widget to draw on 
3711     GtkPizza 
*pizza 
= GTK_PIZZA (m_wxwindow
); 
3713     if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)) 
3715         // find ancestor from which to steal background 
3716         wxWindow 
*parent 
= wxGetTopLevelParent((wxWindow 
*)this); 
3718             parent 
= (wxWindow
*)this; 
3720         if (GTK_WIDGET_MAPPED(parent
->m_widget
)) 
3722             wxRegionIterator 
upd( m_nativeUpdateRegion 
); 
3726                 rect
.x 
= upd
.GetX(); 
3727                 rect
.y 
= upd
.GetY(); 
3728                 rect
.width 
= upd
.GetWidth(); 
3729                 rect
.height 
= upd
.GetHeight(); 
3731                 gtk_paint_flat_box( parent
->m_widget
->style
, 
3733                             (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
), 
3746         wxWindowDC 
dc( (wxWindow
*)this ); 
3747         dc
.SetClippingRegion( m_updateRegion 
); 
3749         wxEraseEvent 
erase_event( GetId(), &dc 
); 
3750         erase_event
.SetEventObject( this ); 
3752         GetEventHandler()->ProcessEvent(erase_event
); 
3755     wxNcPaintEvent 
nc_paint_event( GetId() ); 
3756     nc_paint_event
.SetEventObject( this ); 
3757     GetEventHandler()->ProcessEvent( nc_paint_event 
); 
3759     wxPaintEvent 
paint_event( GetId() ); 
3760     paint_event
.SetEventObject( this ); 
3761     GetEventHandler()->ProcessEvent( paint_event 
); 
3763     m_clipPaintRegion 
= false; 
3765     m_updateRegion
.Clear(); 
3766     m_nativeUpdateRegion
.Clear(); 
3769 void wxWindowGTK::SetDoubleBuffered( bool on 
) 
3771     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3774         gtk_widget_set_double_buffered( m_wxwindow
, on 
); 
3777 bool wxWindowGTK::IsDoubleBuffered() const 
3779     return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow 
); 
3782 void wxWindowGTK::ClearBackground() 
3784     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3788 void wxWindowGTK::DoSetToolTip( wxToolTip 
*tip 
) 
3790     wxWindowBase::DoSetToolTip(tip
); 
3793         m_tooltip
->Apply( (wxWindow 
*)this ); 
3796 void wxWindowGTK::ApplyToolTip( GtkTooltips 
*tips
, const gchar 
*tip 
) 
3798     gtk_tooltips_set_tip(tips
, GetConnectWidget(), tip
, NULL
); 
3800 #endif // wxUSE_TOOLTIPS 
3802 bool wxWindowGTK::SetBackgroundColour( const wxColour 
&colour 
) 
3804     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3806     if (!wxWindowBase::SetBackgroundColour(colour
)) 
3811         // We need the pixel value e.g. for background clearing. 
3812         m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
)); 
3815     // apply style change (forceStyle=true so that new style is applied 
3816     // even if the bg colour changed from valid to wxNullColour) 
3817     if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
) 
3818         ApplyWidgetStyle(true); 
3823 bool wxWindowGTK::SetForegroundColour( const wxColour 
&colour 
) 
3825     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3827     if (!wxWindowBase::SetForegroundColour(colour
)) 
3834         // We need the pixel value e.g. for background clearing. 
3835         m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
)); 
3838     // apply style change (forceStyle=true so that new style is applied 
3839     // even if the bg colour changed from valid to wxNullColour): 
3840     ApplyWidgetStyle(true); 
3845 PangoContext 
*wxWindowGTK::GtkGetPangoDefaultContext() 
3847     return gtk_widget_get_pango_context( m_widget 
); 
3850 GtkRcStyle 
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
) 
3852     // do we need to apply any changes at all? 
3855          !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() ) 
3860     GtkRcStyle 
*style 
= gtk_rc_style_new(); 
3865             pango_font_description_copy( m_font
.GetNativeFontInfo()->description 
); 
3868     int flagsNormal 
= 0, 
3871         flagsInsensitive 
= 0; 
3873     if ( m_foregroundColour
.Ok() ) 
3875         const GdkColor 
*fg 
= m_foregroundColour
.GetColor(); 
3877         style
->fg
[GTK_STATE_NORMAL
] = 
3878         style
->text
[GTK_STATE_NORMAL
] = *fg
; 
3879         flagsNormal 
|= GTK_RC_FG 
| GTK_RC_TEXT
; 
3881         style
->fg
[GTK_STATE_PRELIGHT
] = 
3882         style
->text
[GTK_STATE_PRELIGHT
] = *fg
; 
3883         flagsPrelight 
|= GTK_RC_FG 
| GTK_RC_TEXT
; 
3885         style
->fg
[GTK_STATE_ACTIVE
] = 
3886         style
->text
[GTK_STATE_ACTIVE
] = *fg
; 
3887         flagsActive 
|= GTK_RC_FG 
| GTK_RC_TEXT
; 
3890     if ( m_backgroundColour
.Ok() ) 
3892         const GdkColor 
*bg 
= m_backgroundColour
.GetColor(); 
3894         style
->bg
[GTK_STATE_NORMAL
] = 
3895         style
->base
[GTK_STATE_NORMAL
] = *bg
; 
3896         flagsNormal 
|= GTK_RC_BG 
| GTK_RC_BASE
; 
3898         style
->bg
[GTK_STATE_PRELIGHT
] = 
3899         style
->base
[GTK_STATE_PRELIGHT
] = *bg
; 
3900         flagsPrelight 
|= GTK_RC_BG 
| GTK_RC_BASE
; 
3902         style
->bg
[GTK_STATE_ACTIVE
] = 
3903         style
->base
[GTK_STATE_ACTIVE
] = *bg
; 
3904         flagsActive 
|= GTK_RC_BG 
| GTK_RC_BASE
; 
3906         style
->bg
[GTK_STATE_INSENSITIVE
] = 
3907         style
->base
[GTK_STATE_INSENSITIVE
] = *bg
; 
3908         flagsInsensitive 
|= GTK_RC_BG 
| GTK_RC_BASE
; 
3911     style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
; 
3912     style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
; 
3913     style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
; 
3914     style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
; 
3919 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
) 
3921     GtkRcStyle 
*style 
= CreateWidgetStyle(forceStyle
); 
3924         DoApplyWidgetStyle(style
); 
3925         gtk_rc_style_unref(style
); 
3928     // Style change may affect GTK+'s size calculation: 
3929     InvalidateBestSize(); 
3932 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
3935         gtk_widget_modify_style(m_wxwindow
, style
); 
3937         gtk_widget_modify_style(m_widget
, style
); 
3940 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
) 
3942     wxWindowBase::SetBackgroundStyle(style
); 
3944     if (style 
== wxBG_STYLE_CUSTOM
) 
3949             window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3953             GtkWidget 
* const w 
= GetConnectWidget(); 
3954             window 
= w 
? w
->window 
: NULL
; 
3959             // Make sure GDK/X11 doesn't refresh the window 
3961             gdk_window_set_back_pixmap( window
, None
, False 
); 
3963             Display
* display 
= GDK_WINDOW_DISPLAY(window
); 
3966             m_needsStyleChange 
= false; 
3968         else // window not realized yet 
3970             // Do in OnIdle, because the window is not yet available 
3971             m_needsStyleChange 
= true; 
3974         // Don't apply widget style, or we get a grey background 
3978         // apply style change (forceStyle=true so that new style is applied 
3979         // even if the bg colour changed from valid to wxNullColour): 
3980         ApplyWidgetStyle(true); 
3985 #if wxUSE_DRAG_AND_DROP 
3987 void wxWindowGTK::SetDropTarget( wxDropTarget 
*dropTarget 
) 
3989     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3991     GtkWidget 
*dnd_widget 
= GetConnectWidget(); 
3993     if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget 
); 
3995     if (m_dropTarget
) delete m_dropTarget
; 
3996     m_dropTarget 
= dropTarget
; 
3998     if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget 
); 
4001 #endif // wxUSE_DRAG_AND_DROP 
4003 GtkWidget
* wxWindowGTK::GetConnectWidget() 
4005     GtkWidget 
*connect_widget 
= m_widget
; 
4006     if (m_wxwindow
) connect_widget 
= m_wxwindow
; 
4008     return connect_widget
; 
4011 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow 
*window
) const 
4013     wxArrayGdkWindows windowsThis
; 
4014     GdkWindow 
* const winThis 
= GTKGetWindow(windowsThis
); 
4016     return winThis 
? window 
== winThis
 
4017                    : windowsThis
.Index(window
) != wxNOT_FOUND
; 
4020 GdkWindow 
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const 
4022     return m_wxwindow 
? GTK_PIZZA(m_wxwindow
)->bin_window 
: m_widget
->window
; 
4025 bool wxWindowGTK::SetFont( const wxFont 
&font 
) 
4027     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
4029     if (!wxWindowBase::SetFont(font
)) 
4032     // apply style change (forceStyle=true so that new style is applied 
4033     // even if the font changed from valid to wxNullFont): 
4034     ApplyWidgetStyle(true); 
4039 void wxWindowGTK::DoCaptureMouse() 
4041     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4043     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4045         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4047         window 
= GetConnectWidget()->window
; 
4049     wxCHECK_RET( window
, _T("CaptureMouse() failed") ); 
4051     const wxCursor
* cursor 
= &m_cursor
; 
4053         cursor 
= wxSTANDARD_CURSOR
; 
4055     gdk_pointer_grab( window
, FALSE
, 
4057                          (GDK_BUTTON_PRESS_MASK 
| 
4058                           GDK_BUTTON_RELEASE_MASK 
| 
4059                           GDK_POINTER_MOTION_HINT_MASK 
| 
4060                           GDK_POINTER_MOTION_MASK
), 
4062                       cursor
->GetCursor(), 
4063                       (guint32
)GDK_CURRENT_TIME 
); 
4064     g_captureWindow 
= this; 
4065     g_captureWindowHasMouse 
= true; 
4068 void wxWindowGTK::DoReleaseMouse() 
4070     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4072     wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") ); 
4074     g_captureWindow 
= (wxWindowGTK
*) NULL
; 
4076     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4078         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4080         window 
= GetConnectWidget()->window
; 
4085     gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME 
); 
4089 wxWindow 
*wxWindowBase::GetCapture() 
4091     return (wxWindow 
*)g_captureWindow
; 
4094 bool wxWindowGTK::IsRetained() const 
4099 void wxWindowGTK::BlockScrollEvent() 
4101     wxASSERT(!m_blockScrollEvent
); 
4102     m_blockScrollEvent 
= true; 
4105 void wxWindowGTK::UnblockScrollEvent() 
4107     wxASSERT(m_blockScrollEvent
); 
4108     m_blockScrollEvent 
= false; 
4111 void wxWindowGTK::SetScrollbar(int orient
, 
4115                                bool WXUNUSED(update
)) 
4117     GtkRange 
* const sb 
= m_scrollBar
[ScrollDirFromOrient(orient
)]; 
4118     wxCHECK_RET( sb
, _T("this window is not scrollable") ); 
4122         m_hasScrolling 
= true; 
4126         // GtkRange requires upper > lower 
4131     if (pos 
> range 
- thumbVisible
) 
4132         pos 
= range 
- thumbVisible
; 
4135     GtkAdjustment 
* const adj 
= sb
->adjustment
; 
4136     adj
->step_increment 
= 1; 
4137     adj
->page_increment 
= 
4138     adj
->page_size 
= thumbVisible
; 
4140     SetScrollPos(orient
, pos
); 
4141     gtk_adjustment_changed(adj
); 
4144 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
)) 
4146     const int dir 
= ScrollDirFromOrient(orient
); 
4147     GtkRange 
* const sb 
= m_scrollBar
[dir
]; 
4148     wxCHECK_RET( sb
, _T("this window is not scrollable") ); 
4150     // This check is more than an optimization. Without it, the slider 
4151     //   will not move smoothly while tracking when using wxScrollHelper. 
4152     if (GetScrollPos(orient
) != pos
) 
4154         GtkAdjustment
* adj 
= sb
->adjustment
; 
4155         const int max 
= int(adj
->upper 
- adj
->page_size
); 
4160         m_scrollPos
[dir
] = adj
->value 
= pos
; 
4162         g_signal_handlers_block_by_func(m_scrollBar
[dir
], 
4163             (gpointer
)gtk_scrollbar_value_changed
, this); 
4165         gtk_adjustment_value_changed(adj
); 
4167         g_signal_handlers_unblock_by_func(m_scrollBar
[dir
], 
4168             (gpointer
)gtk_scrollbar_value_changed
, this); 
4172 int wxWindowGTK::GetScrollThumb(int orient
) const 
4174     GtkRange 
* const sb 
= m_scrollBar
[ScrollDirFromOrient(orient
)]; 
4175     wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") ); 
4177     return int(sb
->adjustment
->page_size
); 
4180 int wxWindowGTK::GetScrollPos( int orient 
) const 
4182     GtkRange 
* const sb 
= m_scrollBar
[ScrollDirFromOrient(orient
)]; 
4183     wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") ); 
4185     return int(sb
->adjustment
->value 
+ 0.5); 
4188 int wxWindowGTK::GetScrollRange( int orient 
) const 
4190     GtkRange 
* const sb 
= m_scrollBar
[ScrollDirFromOrient(orient
)]; 
4191     wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") ); 
4193     return int(sb
->adjustment
->upper
); 
4196 // Determine if increment is the same as +/-x, allowing for some small 
4197 //   difference due to possible inexactness in floating point arithmetic 
4198 static inline bool IsScrollIncrement(double increment
, double x
) 
4200     wxASSERT(increment 
> 0); 
4201     const double tolerance 
= 1.0 / 1024; 
4202     return fabs(increment 
- fabs(x
)) < tolerance
; 
4205 wxEventType 
wxWindowGTK::GetScrollEventType(GtkRange
* range
) 
4209     wxASSERT(range 
== m_scrollBar
[0] || range 
== m_scrollBar
[1]); 
4211     const int barIndex 
= range 
== m_scrollBar
[1]; 
4212     GtkAdjustment
* adj 
= range
->adjustment
; 
4214     const int value 
= int(adj
->value 
+ 0.5); 
4216     // save previous position 
4217     const double oldPos 
= m_scrollPos
[barIndex
]; 
4218     // update current position 
4219     m_scrollPos
[barIndex
] = adj
->value
; 
4220     // If event should be ignored, or integral position has not changed 
4221     if (!m_hasVMT 
|| g_blockEventsOnDrag 
|| value 
== int(oldPos 
+ 0.5)) 
4226     wxEventType eventType 
= wxEVT_SCROLL_THUMBTRACK
; 
4229         // Difference from last change event 
4230         const double diff 
= adj
->value 
- oldPos
; 
4231         const bool isDown 
= diff 
> 0; 
4233         if (IsScrollIncrement(adj
->step_increment
, diff
)) 
4235             eventType 
= isDown 
? wxEVT_SCROLL_LINEDOWN 
: wxEVT_SCROLL_LINEUP
; 
4237         else if (IsScrollIncrement(adj
->page_increment
, diff
)) 
4239             eventType 
= isDown 
? wxEVT_SCROLL_PAGEDOWN 
: wxEVT_SCROLL_PAGEUP
; 
4241         else if (m_mouseButtonDown
) 
4243             // Assume track event 
4244             m_isScrolling 
= true; 
4250 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) ) 
4252     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4254     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4256     // No scrolling requested. 
4257     if ((dx 
== 0) && (dy 
== 0)) return; 
4259     m_clipPaintRegion 
= true; 
4261     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
4262         gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), dx
, -dy 
); 
4264         gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy 
); 
4266     m_clipPaintRegion 
= false; 
4269     bool restoreCaret 
= (GetCaret() != NULL 
&& GetCaret()->IsVisible()); 
4272         wxRect 
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize()); 
4274             caretRect
.width 
+= dx
; 
4277             caretRect
.x 
+= dx
; caretRect
.width 
-= dx
; 
4280             caretRect
.height 
+= dy
; 
4283             caretRect
.y 
+= dy
; caretRect
.height 
-= dy
; 
4286         RefreshRect(caretRect
); 
4288 #endif // wxUSE_CARET 
4291 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
) 
4293     //RN: Note that static controls usually have no border on gtk, so maybe 
4294     //it makes sense to treat that as simply no border at the wx level 
4296     if (!(wxstyle 
& wxNO_BORDER
) && !(wxstyle 
& wxBORDER_STATIC
)) 
4298         GtkShadowType gtkstyle
; 
4300         if(wxstyle 
& wxBORDER_RAISED
) 
4301             gtkstyle 
= GTK_SHADOW_OUT
; 
4302         else if (wxstyle 
& wxBORDER_SUNKEN
) 
4303             gtkstyle 
= GTK_SHADOW_IN
; 
4304         else if (wxstyle 
& wxBORDER_DOUBLE
) 
4305             gtkstyle 
= GTK_SHADOW_ETCHED_IN
; 
4307             gtkstyle 
= GTK_SHADOW_IN
; 
4309         gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
), 
4314 void wxWindowGTK::SetWindowStyleFlag( long style 
) 
4316     // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already 
4317     wxWindowBase::SetWindowStyleFlag(style
); 
4320 // Find the wxWindow at the current mouse position, also returning the mouse 
4322 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
) 
4324     pt 
= wxGetMousePosition(); 
4325     wxWindow
* found 
= wxFindWindowAtPoint(pt
); 
4329 // Get the current mouse position. 
4330 wxPoint 
wxGetMousePosition() 
4332   /* This crashes when used within wxHelpContext, 
4333      so we have to use the X-specific implementation below. 
4335     GdkModifierType *mask; 
4336     (void) gdk_window_get_pointer(NULL, &x, &y, mask); 
4338     return wxPoint(x, y); 
4342     GdkWindow
* windowAtPtr 
= gdk_window_at_pointer(& x
, & y
); 
4344     Display 
*display 
= windowAtPtr 
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY(); 
4345     Window rootWindow 
= RootWindowOfScreen (DefaultScreenOfDisplay(display
)); 
4346     Window rootReturn
, childReturn
; 
4347     int rootX
, rootY
, winX
, winY
; 
4348     unsigned int maskReturn
; 
4350     XQueryPointer (display
, 
4354                    &rootX
, &rootY
, &winX
, &winY
, &maskReturn
); 
4355     return wxPoint(rootX
, rootY
); 
4359 // Needed for implementing e.g. combobox on wxGTK within a modal dialog. 
4360 void wxAddGrab(wxWindow
* window
) 
4362     gtk_grab_add( (GtkWidget
*) window
->GetHandle() ); 
4365 void wxRemoveGrab(wxWindow
* window
) 
4367     gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );