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" 
  25     #include "wx/dcclient.h" 
  27     #include "wx/dialog.h" 
  28     #include "wx/settings.h" 
  29     #include "wx/msgdlg.h" 
  30     #include "wx/textctrl.h" 
  31     #include "wx/toolbar.h" 
  32     #include "wx/combobox.h" 
  33     #include "wx/layout.h" 
  34     #include "wx/statusbr.h" 
  36     #include "wx/module.h" 
  39 #if wxUSE_DRAG_AND_DROP 
  44     #include "wx/tooltip.h" 
  51 #include "wx/fontutil.h" 
  54     #include "wx/thread.h" 
  59 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0 
  60 #include <gtk/gtkversion.h> 
  61 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0) 
  62 #undef GTK_DISABLE_DEPRECATED 
  65 #include "wx/gtk/private.h" 
  66 #include <gdk/gdkprivate.h> 
  67 #include <gdk/gdkkeysyms.h> 
  71 #include <gtk/gtkprivate.h> 
  73 #include "wx/gtk/win_gtk.h" 
  75 #include <pango/pangox.h> 
  81 extern GtkContainerClass 
*pizza_parent_class
; 
  83 //----------------------------------------------------------------------------- 
  84 // documentation on internals 
  85 //----------------------------------------------------------------------------- 
  88    I have been asked several times about writing some documentation about 
  89    the GTK port of wxWidgets, especially its internal structures. Obviously, 
  90    you cannot understand wxGTK without knowing a little about the GTK, but 
  91    some more information about what the wxWindow, which is the base class 
  92    for all other window classes, does seems required as well. 
  96    What does wxWindow do? It contains the common interface for the following 
  97    jobs of its descendants: 
  99    1) Define the rudimentary behaviour common to all window classes, such as 
 100    resizing, intercepting user input (so as to make it possible to use these 
 101    events for special purposes in a derived class), window names etc. 
 103    2) Provide the possibility to contain and manage children, if the derived 
 104    class is allowed to contain children, which holds true for those window 
 105    classes which do not display a native GTK widget. To name them, these 
 106    classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame- 
 107    work classes are a special case and are handled a bit differently from 
 108    the rest. The same holds true for the wxNotebook class. 
 110    3) Provide the possibility to draw into a client area of a window. This, 
 111    too, only holds true for classes that do not display a native GTK widget 
 114    4) Provide the entire mechanism for scrolling widgets. This actual inter- 
 115    face for this is usually in wxScrolledWindow, but the GTK implementation 
 118    5) A multitude of helper or extra methods for special purposes, such as 
 119    Drag'n'Drop, managing validators etc. 
 121    6) Display a border (sunken, raised, simple or none). 
 123    Normally one might expect, that one wxWidgets window would always correspond 
 124    to one GTK widget. Under GTK, there is no such all-round widget that has all 
 125    the functionality. Moreover, the GTK defines a client area as a different 
 126    widget from the actual widget you are handling. Last but not least some 
 127    special classes (e.g. wxFrame) handle different categories of widgets and 
 128    still have the possibility to draw something in the client area. 
 129    It was therefore required to write a special purpose GTK widget, that would 
 130    represent a client area in the sense of wxWidgets capable to do the jobs 
 131    2), 3) and 4). I have written this class and it resides in win_gtk.c of 
 134    All windows must have a widget, with which they interact with other under- 
 135    lying GTK widgets. It is this widget, e.g. that has to be resized etc and 
 136    the wxWindow class has a member variable called m_widget which holds a 
 137    pointer to this widget. When the window class represents a GTK native widget, 
 138    this is (in most cases) the only GTK widget the class manages. E.g. the 
 139    wxStaticText class handles only a GtkLabel widget a pointer to which you 
 140    can find in m_widget (defined in wxWindow) 
 142    When the class has a client area for drawing into and for containing children 
 143    it has to handle the client area widget (of the type GtkPizza, defined in 
 144    win_gtk.c), but there could be any number of widgets, handled by a class 
 145    The common rule for all windows is only, that the widget that interacts with 
 146    the rest of GTK must be referenced in m_widget and all other widgets must be 
 147    children of this widget on the GTK level. The top-most widget, which also 
 148    represents the client area, must be in the m_wxwindow field and must be of 
 151    As I said, the window classes that display a GTK native widget only have 
 152    one widget, so in the case of e.g. the wxButton class m_widget holds a 
 153    pointer to a GtkButton widget. But windows with client areas (for drawing 
 154    and children) have a m_widget field that is a pointer to a GtkScrolled- 
 155    Window and a m_wxwindow field that is pointer to a GtkPizza and this 
 156    one is (in the GTK sense) a child of the GtkScrolledWindow. 
 158    If the m_wxwindow field is set, then all input to this widget is inter- 
 159    cepted and sent to the wxWidgets class. If not, all input to the widget 
 160    that gets pointed to by m_widget gets intercepted and sent to the class. 
 164    The design of scrolling in wxWidgets is markedly different from that offered 
 165    by the GTK itself and therefore we cannot simply take it as it is. In GTK, 
 166    clicking on a scrollbar belonging to scrolled window will inevitably move 
 167    the window. In wxWidgets, the scrollbar will only emit an event, send this 
 168    to (normally) a wxScrolledWindow and that class will call ScrollWindow() 
 169    which actually moves the window and its sub-windows. Note that GtkPizza 
 170    memorizes how much it has been scrolled but that wxWidgets forgets this 
 171    so that the two coordinates systems have to be kept in synch. This is done 
 172    in various places using the pizza->xoffset and pizza->yoffset values. 
 176    Singularly the most broken code in GTK is the code that is supposed to 
 177    inform subwindows (child windows) about new positions. Very often, duplicate 
 178    events are sent without changes in size or position, equally often no 
 179    events are sent at all (All this is due to a bug in the GtkContainer code 
 180    which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores 
 181    GTK's own system and it simply waits for size events for toplevel windows 
 182    and then iterates down the respective size events to all window. This has 
 183    the disadvantage that windows might get size events before the GTK widget 
 184    actually has the reported size. This doesn't normally pose any problem, but 
 185    the OpenGL drawing routines rely on correct behaviour. Therefore, I have 
 186    added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas, 
 187    i.e. the wxGLCanvas will emit a size event, when (and not before) the X11 
 188    window that is used for OpenGL output really has that size (as reported by 
 193    If someone at some point of time feels the immense desire to have a look at, 
 194    change or attempt to optimise the Refresh() logic, this person will need an 
 195    intimate understanding of what "draw" and "expose" events are and what 
 196    they are used for, in particular when used in connection with GTK's 
 197    own windowless widgets. Beware. 
 201    Cursors, too, have been a constant source of pleasure. The main difficulty 
 202    is that a GdkWindow inherits a cursor if the programmer sets a new cursor 
 203    for the parent. To prevent this from doing too much harm, I use idle time 
 204    to set the cursor over and over again, starting from the toplevel windows 
 205    and ending with the youngest generation (speaking of parent and child windows). 
 206    Also don't forget that cursors (like much else) are connected to GdkWindows, 
 207    not GtkWidgets and that the "window" field of a GtkWidget might very well 
 208    point to the GdkWindow of the parent widget (-> "window-less widget") and 
 209    that the two obviously have very different meanings. 
 213 //----------------------------------------------------------------------------- 
 215 //----------------------------------------------------------------------------- 
 217 extern bool       g_blockEventsOnDrag
; 
 218 extern bool       g_blockEventsOnScroll
; 
 219 extern wxCursor   g_globalCursor
; 
 221 // mouse capture state: the window which has it and if the mouse is currently 
 223 static wxWindowGTK  
*g_captureWindow 
= (wxWindowGTK
*) NULL
; 
 224 static bool g_captureWindowHasMouse 
= false; 
 226 wxWindowGTK  
*g_focusWindow 
= (wxWindowGTK
*) NULL
; 
 228 // the last window which had the focus - this is normally never NULL (except 
 229 // if we never had focus at all) as even when g_focusWindow is NULL it still 
 230 // keeps its previous value 
 231 wxWindowGTK 
*g_focusWindowLast 
= (wxWindowGTK
*) NULL
; 
 233 // If a window get the focus set but has not been realized 
 234 // yet, defer setting the focus to idle time. 
 235 wxWindowGTK 
*g_delayedFocus 
= (wxWindowGTK
*) NULL
; 
 237 extern bool g_mainThreadLocked
; 
 239 //----------------------------------------------------------------------------- 
 241 //----------------------------------------------------------------------------- 
 246 #   define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance"); 
 248 #   define DEBUG_MAIN_THREAD 
 251 #define DEBUG_MAIN_THREAD 
 254 // the trace mask used for the focus debugging messages 
 255 #define TRACE_FOCUS _T("focus") 
 257 //----------------------------------------------------------------------------- 
 258 // missing gdk functions 
 259 //----------------------------------------------------------------------------- 
 262 gdk_window_warp_pointer (GdkWindow      
*window
, 
 267     window 
= gdk_get_default_root_window(); 
 269   if (!GDK_WINDOW_DESTROYED(window
)) 
 271       XWarpPointer (GDK_WINDOW_XDISPLAY(window
), 
 272                     None
,              /* not source window -> move from anywhere */ 
 273                     GDK_WINDOW_XID(window
),  /* dest window */ 
 274                     0, 0, 0, 0,        /* not source window -> move from anywhere */ 
 279 //----------------------------------------------------------------------------- 
 280 // local code (see below) 
 281 //----------------------------------------------------------------------------- 
 283 // returns the child of win which currently has focus or NULL if not found 
 285 // Note: can't be static, needed by textctrl.cpp. 
 286 wxWindow 
*wxFindFocusedChild(wxWindowGTK 
*win
) 
 288     wxWindow 
*winFocus 
= wxWindowGTK::FindFocus(); 
 290         return (wxWindow 
*)NULL
; 
 292     if ( winFocus 
== win 
) 
 293         return (wxWindow 
*)win
; 
 295     for ( wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
 297           node 
= node
->GetNext() ) 
 299         wxWindow 
*child 
= wxFindFocusedChild(node
->GetData()); 
 304     return (wxWindow 
*)NULL
; 
 307 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
) 
 309     GtkScrolledWindow
* scroll_window 
= GTK_SCROLLED_WINDOW(widget
); 
 310     GtkScrolledWindowClass
* scroll_class 
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
)); 
 311     GtkRequisition scroll_req
; 
 314     if (scroll_window
->vscrollbar_visible
) 
 316         scroll_req
.width 
= 2; 
 317         scroll_req
.height 
= 2; 
 318         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request 
) 
 319             (scroll_window
->vscrollbar
, &scroll_req 
); 
 320         w 
= scroll_req
.width 
+ 
 321             scroll_class
->scrollbar_spacing
; 
 325     if (scroll_window
->hscrollbar_visible
) 
 327         scroll_req
.width 
= 2; 
 328         scroll_req
.height 
= 2; 
 329         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request 
) 
 330             (scroll_window
->hscrollbar
, &scroll_req 
); 
 331         h 
= scroll_req
.height 
+ 
 332             scroll_class
->scrollbar_spacing
; 
 336 static void draw_frame( GtkWidget 
*widget
, wxWindowGTK 
*win 
) 
 338     // wxUniversal widgets draw the borders and scrollbars themselves 
 339 #ifndef __WXUNIVERSAL__ 
 346     if (win
->m_hasScrolling
) 
 348         GetScrollbarWidth(widget
, dw
, dh
); 
 353     if (GTK_WIDGET_NO_WINDOW (widget
)) 
 355         dx 
+= widget
->allocation
.x
; 
 356         dy 
+= widget
->allocation
.y
; 
 359     if (win
->HasFlag(wxRAISED_BORDER
)) 
 361         gtk_paint_shadow (widget
->style
, 
 365                           NULL
, NULL
, NULL
, // FIXME: No clipping? 
 367                           widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh 
); 
 371     if (win
->HasFlag(wxSUNKEN_BORDER
)) 
 373         gtk_paint_shadow (widget
->style
, 
 377                           NULL
, NULL
, NULL
, // FIXME: No clipping? 
 379                           widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh 
); 
 383     if (win
->HasFlag(wxSIMPLE_BORDER
)) 
 386         gc 
= gdk_gc_new( widget
->window 
); 
 387         gdk_gc_set_foreground( gc
, &widget
->style
->black 
); 
 388         gdk_draw_rectangle( widget
->window
, gc
, FALSE
, 
 390                          widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 ); 
 394 #endif // __WXUNIVERSAL__ 
 397 //----------------------------------------------------------------------------- 
 398 // "expose_event" of m_widget 
 399 //----------------------------------------------------------------------------- 
 403 gtk_window_own_expose_callback( GtkWidget 
*widget
, 
 404                                 GdkEventExpose 
*gdk_event
, 
 407     if (gdk_event
->count 
> 0) return FALSE
; 
 409     draw_frame( widget
, win 
); 
 411     (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
); 
 417 //----------------------------------------------------------------------------- 
 418 // "size_request" of m_widget 
 419 //----------------------------------------------------------------------------- 
 421 // make it extern because wxStaticText needs to disconnect this one 
 423 void wxgtk_window_size_request_callback(GtkWidget 
*widget
, 
 424                                         GtkRequisition 
*requisition
, 
 428     win
->GetSize( &w
, &h 
); 
 434     requisition
->height 
= h
; 
 435     requisition
->width 
= w
; 
 441 void wxgtk_combo_size_request_callback(GtkWidget 
*widget
, 
 442                                        GtkRequisition 
*requisition
, 
 445     // This callback is actually hooked into the text entry 
 446     // of the combo box, not the GtkHBox. 
 449     win
->GetSize( &w
, &h 
); 
 455     GtkCombo 
*gcombo 
= GTK_COMBO(win
->m_widget
); 
 457     GtkRequisition entry_req
; 
 459     entry_req
.height 
= 2; 
 460     (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request 
) 
 461         (gcombo
->button
, &entry_req 
); 
 463     requisition
->width 
= w 
- entry_req
.width
; 
 464     requisition
->height 
= entry_req
.height
; 
 468 //----------------------------------------------------------------------------- 
 469 // "expose_event" of m_wxwindow 
 470 //----------------------------------------------------------------------------- 
 474 gtk_window_expose_callback( GtkWidget 
*widget
, 
 475                             GdkEventExpose 
*gdk_event
, 
 480     // don't need to install idle handler, its done from "event" signal 
 482     // This callback gets called in drawing-idle time under 
 483     // GTK 2.0, so we don't need to defer anything to idle 
 486     GtkPizza 
*pizza 
= GTK_PIZZA( widget 
); 
 487     if (gdk_event
->window 
!= pizza
->bin_window
) return FALSE
; 
 493         wxPrintf( wxT("OnExpose from ") ); 
 494         if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName()) 
 495             wxPrintf( win
->GetClassInfo()->GetClassName() ); 
 496         wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
, 
 497                                          (int)gdk_event
->area
.y
, 
 498                                          (int)gdk_event
->area
.width
, 
 499                                          (int)gdk_event
->area
.height 
); 
 504         win
->m_wxwindow
->style
, 
 508         (GdkRectangle
*) NULL
, 
 510         (char *)"button", // const_cast 
 515     win
->GetUpdateRegion() = wxRegion( gdk_event
->region 
); 
 517     win
->GtkSendPaintEvents(); 
 519     // Let parent window draw window-less widgets 
 520     (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
); 
 526 //----------------------------------------------------------------------------- 
 527 // "key_press_event" from any window 
 528 //----------------------------------------------------------------------------- 
 530 // These are used when transforming Ctrl-alpha to ascii values 1-26 
 531 inline bool wxIsLowerChar(int code
) 
 533     return (code 
>= 'a' && code 
<= 'z' ); 
 536 inline bool wxIsUpperChar(int code
) 
 538     return (code 
>= 'A' && code 
<= 'Z' ); 
 542 // set WXTRACE to this to see the key event codes on the console 
 543 #define TRACE_KEYS  _T("keyevent") 
 545 // translates an X key symbol to WXK_XXX value 
 547 // if isChar is true it means that the value returned will be used for EVT_CHAR 
 548 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide, 
 549 // for example, while if it is false it means that the value is going to be 
 550 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to 
 552 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
) 
 558         // Shift, Control and Alt don't generate the CHAR events at all 
 561             key_code 
= isChar 
? 0 : WXK_SHIFT
; 
 565             key_code 
= isChar 
? 0 : WXK_CONTROL
; 
 573             key_code 
= isChar 
? 0 : WXK_ALT
; 
 576         // neither do the toggle modifies 
 577         case GDK_Scroll_Lock
: 
 578             key_code 
= isChar 
? 0 : WXK_SCROLL
; 
 582             key_code 
= isChar 
? 0 : WXK_CAPITAL
; 
 586             key_code 
= isChar 
? 0 : WXK_NUMLOCK
; 
 590         // various other special keys 
 603         case GDK_ISO_Left_Tab
: 
 610             key_code 
= WXK_RETURN
; 
 614             key_code 
= WXK_CLEAR
; 
 618             key_code 
= WXK_PAUSE
; 
 622             key_code 
= WXK_SELECT
; 
 626             key_code 
= WXK_PRINT
; 
 630             key_code 
= WXK_EXECUTE
; 
 634             key_code 
= WXK_ESCAPE
; 
 637         // cursor and other extended keyboard keys 
 639             key_code 
= WXK_DELETE
; 
 655             key_code 
= WXK_RIGHT
; 
 662         case GDK_Prior
:     // == GDK_Page_Up 
 663             key_code 
= WXK_PAGEUP
; 
 666         case GDK_Next
:      // == GDK_Page_Down 
 667             key_code 
= WXK_PAGEDOWN
; 
 679             key_code 
= WXK_INSERT
; 
 694             key_code 
= (isChar 
? '0' : WXK_NUMPAD0
) + keysym 
- GDK_KP_0
; 
 698             key_code 
= isChar 
? ' ' : WXK_NUMPAD_SPACE
; 
 702             key_code 
= isChar 
? WXK_TAB 
: WXK_NUMPAD_TAB
; 
 706             key_code 
= isChar 
? WXK_RETURN 
: WXK_NUMPAD_ENTER
; 
 710             key_code 
= isChar 
? WXK_F1 
: WXK_NUMPAD_F1
; 
 714             key_code 
= isChar 
? WXK_F2 
: WXK_NUMPAD_F2
; 
 718             key_code 
= isChar 
? WXK_F3 
: WXK_NUMPAD_F3
; 
 722             key_code 
= isChar 
? WXK_F4 
: WXK_NUMPAD_F4
; 
 726             key_code 
= isChar 
? WXK_HOME 
: WXK_NUMPAD_HOME
; 
 730             key_code 
= isChar 
? WXK_LEFT 
: WXK_NUMPAD_LEFT
; 
 734             key_code 
= isChar 
? WXK_UP 
: WXK_NUMPAD_UP
; 
 738             key_code 
= isChar 
? WXK_RIGHT 
: WXK_NUMPAD_RIGHT
; 
 742             key_code 
= isChar 
? WXK_DOWN 
: WXK_NUMPAD_DOWN
; 
 745         case GDK_KP_Prior
: // == GDK_KP_Page_Up 
 746             key_code 
= isChar 
? WXK_PAGEUP 
: WXK_NUMPAD_PAGEUP
; 
 749         case GDK_KP_Next
: // == GDK_KP_Page_Down 
 750             key_code 
= isChar 
? WXK_PAGEDOWN 
: WXK_NUMPAD_PAGEDOWN
; 
 754             key_code 
= isChar 
? WXK_END 
: WXK_NUMPAD_END
; 
 758             key_code 
= isChar 
? WXK_HOME 
: WXK_NUMPAD_BEGIN
; 
 762             key_code 
= isChar 
? WXK_INSERT 
: WXK_NUMPAD_INSERT
; 
 766             key_code 
= isChar 
? WXK_DELETE 
: WXK_NUMPAD_DELETE
; 
 770             key_code 
= isChar 
? '=' : WXK_NUMPAD_EQUAL
; 
 773         case GDK_KP_Multiply
: 
 774             key_code 
= isChar 
? '*' : WXK_NUMPAD_MULTIPLY
; 
 778             key_code 
= isChar 
? '+' : WXK_NUMPAD_ADD
; 
 781         case GDK_KP_Separator
: 
 782             // FIXME: what is this? 
 783             key_code 
= isChar 
? '.' : WXK_NUMPAD_SEPARATOR
; 
 786         case GDK_KP_Subtract
: 
 787             key_code 
= isChar 
? '-' : WXK_NUMPAD_SUBTRACT
; 
 791             key_code 
= isChar 
? '.' : WXK_NUMPAD_DECIMAL
; 
 795             key_code 
= isChar 
? '/' : WXK_NUMPAD_DIVIDE
; 
 812             key_code 
= WXK_F1 
+ keysym 
- GDK_F1
; 
 822 static inline bool wxIsAsciiKeysym(KeySym ks
) 
 827 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
, 
 829                                       GdkEventKey 
*gdk_event
) 
 833     GdkModifierType state
; 
 834     if (gdk_event
->window
) 
 835         gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
 837     event
.SetTimestamp( gdk_event
->time 
); 
 838     event
.SetId(win
->GetId()); 
 839     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
) != 0; 
 840     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
) != 0; 
 841     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
) != 0; 
 842     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
) != 0; 
 843     event
.m_scanCode 
= gdk_event
->keyval
; 
 844     event
.m_rawCode 
= (wxUint32
) gdk_event
->keyval
; 
 845     event
.m_rawFlags 
= 0; 
 847     event
.m_uniChar 
= gdk_keyval_to_unicode(gdk_event
->keyval
); 
 849     wxGetMousePosition( &x
, &y 
); 
 850     win
->ScreenToClient( &x
, &y 
); 
 853     event
.SetEventObject( win 
); 
 858 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
, 
 860                            GdkEventKey 
*gdk_event
) 
 862     // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string 
 863     //     but only event->keyval which is quite useless to us, so remember 
 864     //     the last character from GDK_KEY_PRESS and reuse it as last resort 
 866     // NB: should be MT-safe as we're always called from the main thread only 
 871     } s_lastKeyPress 
= { 0, 0 }; 
 873     KeySym keysym 
= gdk_event
->keyval
; 
 875     wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"), 
 876                event
.GetEventType() == wxEVT_KEY_UP 
? _T("release") 
 880     long key_code 
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */); 
 884         // do we have the translation or is it a plain ASCII character? 
 885         if ( (gdk_event
->length 
== 1) || wxIsAsciiKeysym(keysym
) ) 
 887             // we should use keysym if it is ASCII as X does some translations 
 888             // like "I pressed while Control is down" => "Ctrl-I" == "TAB" 
 889             // which we don't want here (but which we do use for OnChar()) 
 890             if ( !wxIsAsciiKeysym(keysym
) ) 
 892                 keysym 
= (KeySym
)gdk_event
->string
[0]; 
 895             // we want to always get the same key code when the same key is 
 896             // pressed regardless of the state of the modifiers, i.e. on a 
 897             // standard US keyboard pressing '5' or '%' ('5' key with 
 898             // Shift) should result in the same key code in OnKeyDown(): 
 899             // '5' (although OnChar() will get either '5' or '%'). 
 901             // to do it we first translate keysym to keycode (== scan code) 
 902             // and then back but always using the lower register 
 903             Display 
*dpy 
= (Display 
*)wxGetDisplay(); 
 904             KeyCode keycode 
= XKeysymToKeycode(dpy
, keysym
); 
 906             wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
); 
 908             KeySym keysymNormalized 
= XKeycodeToKeysym(dpy
, keycode
, 0); 
 910             // use the normalized, i.e. lower register, keysym if we've 
 912             key_code 
= keysymNormalized 
? keysymNormalized 
: keysym
; 
 914             // as explained above, we want to have lower register key codes 
 915             // normally but for the letter keys we want to have the upper ones 
 917             // NB: don't use XConvertCase() here, we want to do it for letters 
 919             key_code 
= toupper(key_code
); 
 921         else // non ASCII key, what to do? 
 923             // by default, ignore it 
 926             // but if we have cached information from the last KEY_PRESS 
 927             if ( gdk_event
->type 
== GDK_KEY_RELEASE 
) 
 930                 if ( keysym 
== s_lastKeyPress
.keysym 
) 
 932                     key_code 
= s_lastKeyPress
.keycode
; 
 937         if ( gdk_event
->type 
== GDK_KEY_PRESS 
) 
 939             // remember it to be reused for KEY_UP event later 
 940             s_lastKeyPress
.keysym 
= keysym
; 
 941             s_lastKeyPress
.keycode 
= key_code
; 
 945     wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
); 
 947     // sending unknown key events doesn't really make sense 
 951     // now fill all the other fields 
 952     wxFillOtherKeyEventFields(event
, win
, gdk_event
); 
 954     event
.m_keyCode 
= key_code
; 
 956     if ( gdk_event
->type 
== GDK_KEY_PRESS 
||  gdk_event
->type 
== GDK_KEY_RELEASE 
) 
 958         event
.m_uniChar 
= key_code
; 
 968     GtkIMContext 
*context
; 
 969     GdkEventKey  
*lastKeyEvent
; 
 973         context 
= gtk_im_multicontext_new(); 
 978         g_object_unref (context
); 
 984 gtk_window_key_press_callback( GtkWidget 
*widget
, 
 985                                GdkEventKey 
*gdk_event
, 
 990     // don't need to install idle handler, its done from "event" signal 
 994     if (g_blockEventsOnDrag
) 
 998     wxKeyEvent 
event( wxEVT_KEY_DOWN 
); 
1000     bool return_after_IM 
= false; 
1002     if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) ) 
1004         // Emit KEY_DOWN event 
1005         ret 
= win
->GetEventHandler()->ProcessEvent( event 
); 
1009         // Return after IM processing as we cannot do 
1010         // anything with it anyhow. 
1011         return_after_IM 
= true; 
1014     // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw): 
1015     // When we get a key_press event here, it could be originate 
1016     // from the current widget or its child widgets.  However, only the widget 
1017     // with the INPUT FOCUS can generate the INITIAL key_press event.  That is, 
1018     // if the CURRENT widget doesn't have the FOCUS at all, this event definitely 
1019     // originated from its child widgets and shouldn't be passed to IM context. 
1020     // In fact, what a GTK+ IM should do is filtering keyEvents and convert them 
1021     // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS.  Besides, when current 
1022     // widgets has both IM context and input focus, the event should be filtered 
1023     // by gtk_im_context_filter_keypress(). 
1024     // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns. 
1025     if ((!ret
) && (win
->m_imData 
!= NULL
) && ( wxWindow::FindFocus() == win 
)) 
1027         // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API 
1028         // docs, if IM filter returns true, no further processing should be done. 
1029         // we should send the key_down event anyway. 
1030         bool intercepted_by_IM 
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
); 
1031         win
->m_imData
->lastKeyEvent 
= NULL
; 
1032         if (intercepted_by_IM
) 
1034             wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM")); 
1039     if (return_after_IM
) 
1045         wxWindowGTK 
*ancestor 
= win
; 
1048             int command 
= ancestor
->GetAcceleratorTable()->GetCommand( event 
); 
1051                 wxCommandEvent 
command_event( wxEVT_COMMAND_MENU_SELECTED
, command 
); 
1052                 ret 
= ancestor
->GetEventHandler()->ProcessEvent( command_event 
); 
1055             if (ancestor
->IsTopLevel()) 
1057             ancestor 
= ancestor
->GetParent(); 
1060 #endif // wxUSE_ACCEL 
1062     // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x 
1063     // will only be sent if it is not in an accelerator table. 
1067         KeySym keysym 
= gdk_event
->keyval
; 
1068         // Find key code for EVT_CHAR and EVT_CHAR_HOOK events 
1069         key_code 
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */); 
1072             if ( wxIsAsciiKeysym(keysym
) ) 
1075                 key_code 
= (unsigned char)keysym
; 
1077             // gdk_event->string is actually deprecated 
1078             else if ( gdk_event
->length 
== 1 ) 
1080                 key_code 
= (unsigned char)gdk_event
->string
[0]; 
1086             wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
); 
1088             event
.m_keyCode 
= key_code
; 
1090             // To conform to the docs we need to translate Ctrl-alpha 
1091             // characters to values in the range 1-26. 
1092             if ( event
.ControlDown() && 
1093                  ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) )) 
1095                 if ( wxIsLowerChar(key_code
) ) 
1096                     event
.m_keyCode 
= key_code 
- 'a' + 1; 
1097                 if ( wxIsUpperChar(key_code
) ) 
1098                     event
.m_keyCode 
= key_code 
- 'A' + 1; 
1100                 event
.m_uniChar 
= event
.m_keyCode
; 
1104             // Implement OnCharHook by checking ancestor top level windows 
1105             wxWindow 
*parent 
= win
; 
1106             while (parent 
&& !parent
->IsTopLevel()) 
1107                 parent 
= parent
->GetParent(); 
1110                 event
.SetEventType( wxEVT_CHAR_HOOK 
); 
1111                 ret 
= parent
->GetEventHandler()->ProcessEvent( event 
); 
1116                 event
.SetEventType(wxEVT_CHAR
); 
1117                 ret 
= win
->GetEventHandler()->ProcessEvent( event 
); 
1122     // win is a control: tab can be propagated up 
1124          ((gdk_event
->keyval 
== GDK_Tab
) || (gdk_event
->keyval 
== GDK_ISO_Left_Tab
)) && 
1125 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may 
1126 //     have this style, yet choose not to process this particular TAB in which 
1127 //     case TAB must still work as a navigational character 
1128 // JS: enabling again to make consistent with other platforms 
1129 //     (with wxTE_PROCESS_TAB you have to call Navigate to get default 
1130 //     navigation behaviour) 
1132          (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) && 
1134          win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) ) 
1136         wxNavigationKeyEvent new_event
; 
1137         new_event
.SetEventObject( win
->GetParent() ); 
1138         // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB 
1139         new_event
.SetDirection( (gdk_event
->keyval 
== GDK_Tab
) ); 
1140         // CTRL-TAB changes the (parent) window, i.e. switch notebook page 
1141         new_event
.SetWindowChange( (gdk_event
->state 
& GDK_CONTROL_MASK
) ); 
1142         new_event
.SetCurrentFocus( win 
); 
1143         ret 
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event 
); 
1152 gtk_wxwindow_commit_cb (GtkIMContext 
*context
, 
1156     wxKeyEvent 
event( wxEVT_KEY_DOWN 
); 
1158     // take modifiers, cursor position, timestamp etc. from the last 
1159     // key_press_event that was fed into Input Method: 
1160     if (window
->m_imData
->lastKeyEvent
) 
1162         wxFillOtherKeyEventFields(event
, 
1163                                   window
, window
->m_imData
->lastKeyEvent
); 
1166     const wxWxCharBuffer 
data(wxGTK_CONV_BACK(str
)); 
1172     // Implement OnCharHook by checking ancestor top level windows 
1173     wxWindow 
*parent 
= window
; 
1174     while (parent 
&& !parent
->IsTopLevel()) 
1175         parent 
= parent
->GetParent(); 
1177     for( const wxChar
* pstr 
= data
; *pstr
; pstr
++ ) 
1180         event
.m_uniChar 
= *pstr
; 
1181         // Backward compatible for ISO-8859-1 
1182         event
.m_keyCode 
= *pstr 
< 256 ? event
.m_uniChar 
: 0; 
1183         wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
); 
1185         event
.m_keyCode 
= *pstr
; 
1186 #endif  // wxUSE_UNICODE 
1188         // To conform to the docs we need to translate Ctrl-alpha 
1189         // characters to values in the range 1-26. 
1190         if ( event
.ControlDown() && 
1191              ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) )) 
1193             if ( wxIsLowerChar(*pstr
) ) 
1194                 event
.m_keyCode 
= *pstr 
- 'a' + 1; 
1195             if ( wxIsUpperChar(*pstr
) ) 
1196                 event
.m_keyCode 
= *pstr 
- 'A' + 1; 
1198             event
.m_keyCode 
= *pstr 
- 'a' + 1; 
1200             event
.m_uniChar 
= event
.m_keyCode
; 
1206             event
.SetEventType( wxEVT_CHAR_HOOK 
); 
1207             ret 
= parent
->GetEventHandler()->ProcessEvent( event 
); 
1212             event
.SetEventType(wxEVT_CHAR
); 
1213             ret 
= window
->GetEventHandler()->ProcessEvent( event 
); 
1220 //----------------------------------------------------------------------------- 
1221 // "key_release_event" from any window 
1222 //----------------------------------------------------------------------------- 
1226 gtk_window_key_release_callback( GtkWidget 
*widget
, 
1227                                  GdkEventKey 
*gdk_event
, 
1232     // don't need to install idle handler, its done from "event" signal 
1237     if (g_blockEventsOnDrag
) 
1240     wxKeyEvent 
event( wxEVT_KEY_UP 
); 
1241     if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) ) 
1243         // unknown key pressed, ignore (the event would be useless anyhow) 
1247     return win
->GTKProcessEvent(event
); 
1251 // ============================================================================ 
1253 // ============================================================================ 
1255 // ---------------------------------------------------------------------------- 
1256 // mouse event processing helpers 
1257 // ---------------------------------------------------------------------------- 
1259 // init wxMouseEvent with the info from GdkEventXXX struct 
1260 template<typename T
> void InitMouseEvent(wxWindowGTK 
*win
, 
1261                                          wxMouseEvent
& event
, 
1264     event
.SetTimestamp( gdk_event
->time 
); 
1265     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
); 
1266     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
); 
1267     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
); 
1268     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
); 
1269     event
.m_leftDown 
= (gdk_event
->state 
& GDK_BUTTON1_MASK
); 
1270     event
.m_middleDown 
= (gdk_event
->state 
& GDK_BUTTON2_MASK
); 
1271     event
.m_rightDown 
= (gdk_event
->state 
& GDK_BUTTON3_MASK
); 
1272     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
1274        event
.m_linesPerAction 
= 3; 
1275        event
.m_wheelDelta 
= 120; 
1276        if (((GdkEventButton
*)gdk_event
)->button 
== 4) 
1277            event
.m_wheelRotation 
= 120; 
1278        else if (((GdkEventButton
*)gdk_event
)->button 
== 5) 
1279            event
.m_wheelRotation 
= -120; 
1282     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1283     event
.m_x 
= (wxCoord
)gdk_event
->x 
- pt
.x
; 
1284     event
.m_y 
= (wxCoord
)gdk_event
->y 
- pt
.y
; 
1286     if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
)) 
1288         // origin in the upper right corner 
1289         int virtual_width 
= win
->GetVirtualSize().x
; 
1290         int window_width 
= gtk_pizza_get_rtl_offset( GTK_PIZZA(win
->m_wxwindow
) ); 
1291         event
.m_x 
= wxMax( virtual_width
, window_width 
) - event
.m_x
; 
1294     event
.SetEventObject( win 
); 
1295     event
.SetId( win
->GetId() ); 
1296     event
.SetTimestamp( gdk_event
->time 
); 
1299 static void AdjustEventButtonState(wxMouseEvent
& event
) 
1301     // GDK reports the old state of the button for a button press event, but 
1302     // for compatibility with MSW and common sense we want m_leftDown be TRUE 
1303     // for a LEFT_DOWN event, not FALSE, so we will invert 
1304     // left/right/middleDown for the corresponding click events 
1306     if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) || 
1307         (event
.GetEventType() == wxEVT_LEFT_DCLICK
) || 
1308         (event
.GetEventType() == wxEVT_LEFT_UP
)) 
1310         event
.m_leftDown 
= !event
.m_leftDown
; 
1314     if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) || 
1315         (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) || 
1316         (event
.GetEventType() == wxEVT_MIDDLE_UP
)) 
1318         event
.m_middleDown 
= !event
.m_middleDown
; 
1322     if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) || 
1323         (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) || 
1324         (event
.GetEventType() == wxEVT_RIGHT_UP
)) 
1326         event
.m_rightDown 
= !event
.m_rightDown
; 
1331 // find the window to send the mouse event too 
1333 wxWindowGTK 
*FindWindowForMouseEvent(wxWindowGTK 
*win
, wxCoord
& x
, wxCoord
& y
) 
1338     if (win
->m_wxwindow
) 
1340         GtkPizza 
*pizza 
= GTK_PIZZA(win
->m_wxwindow
); 
1341         xx 
+= gtk_pizza_get_xoffset( pizza 
); 
1342         yy 
+= gtk_pizza_get_yoffset( pizza 
); 
1345     wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
1348         wxWindowGTK 
*child 
= node
->GetData(); 
1350         node 
= node
->GetNext(); 
1351         if (!child
->IsShown()) 
1354         if (child
->IsTransparentForMouse()) 
1356             // wxStaticBox is transparent in the box itself 
1357             int xx1 
= child
->m_x
; 
1358             int yy1 
= child
->m_y
; 
1359             int xx2 
= child
->m_x 
+ child
->m_width
; 
1360             int yy2 
= child
->m_y 
+ child
->m_height
; 
1363             if (((xx 
>= xx1
) && (xx 
<= xx1
+10) && (yy 
>= yy1
) && (yy 
<= yy2
)) || 
1365                 ((xx 
>= xx2
-10) && (xx 
<= xx2
) && (yy 
>= yy1
) && (yy 
<= yy2
)) || 
1367                 ((xx 
>= xx1
) && (xx 
<= xx2
) && (yy 
>= yy1
) && (yy 
<= yy1
+10)) || 
1369                 ((xx 
>= xx1
) && (xx 
<= xx2
) && (yy 
>= yy2
-1) && (yy 
<= yy2
))) 
1380             if ((child
->m_wxwindow 
== (GtkWidget
*) NULL
) && 
1381                 (child
->m_x 
<= xx
) && 
1382                 (child
->m_y 
<= yy
) && 
1383                 (child
->m_x
+child
->m_width  
>= xx
) && 
1384                 (child
->m_y
+child
->m_height 
>= yy
)) 
1397 // ---------------------------------------------------------------------------- 
1398 // common event handlers helpers 
1399 // ---------------------------------------------------------------------------- 
1401 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const 
1403     // nothing special at this level 
1404     return GetEventHandler()->ProcessEvent(event
); 
1407 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny 
*event
) const 
1411     // don't need to install idle handler, its done from "event" signal 
1415     if (g_blockEventsOnDrag
) 
1417     if (g_blockEventsOnScroll
) 
1420     if (!GTKIsOwnWindow(event
->window
)) 
1426 // overloads for all GDK event types we use here: we need to have this as 
1427 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact, 
1428 // derives from it in the sense that the structs have the same layout 
1429 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T)                                  \ 
1430     static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win)        \ 
1432         return win->GTKCallbackCommonPrologue((GdkEventAny *)event);          \ 
1435 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
) 
1436 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
) 
1437 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
) 
1439 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD 
1441 #define wxCOMMON_CALLBACK_PROLOGUE(event, win)                                \ 
1442     const int rc = wxGtkCallbackCommonPrologue(event, win);                   \ 
1446 // send the wxChildFocusEvent and wxFocusEvent, common code of 
1447 // gtk_window_focus_in_callback() and SetFocus() 
1448 static bool DoSendFocusEvents(wxWindow 
*win
) 
1450     // Notify the parent keeping track of focus for the kbd navigation 
1451     // purposes that we got it. 
1452     wxChildFocusEvent 
eventChildFocus(win
); 
1453     (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
); 
1455     wxFocusEvent 
eventFocus(wxEVT_SET_FOCUS
, win
->GetId()); 
1456     eventFocus
.SetEventObject(win
); 
1458     return win
->GetEventHandler()->ProcessEvent(eventFocus
); 
1461 // all event handlers must have C linkage as they're called from GTK+ C code 
1465 //----------------------------------------------------------------------------- 
1466 // "button_press_event" 
1467 //----------------------------------------------------------------------------- 
1470 gtk_window_button_press_callback( GtkWidget 
*widget
, 
1471                                   GdkEventButton 
*gdk_event
, 
1474     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1476     if (win
->m_wxwindow 
&& (g_focusWindow 
!= win
) && win
->AcceptsFocus()) 
1478         gtk_widget_grab_focus( win
->m_wxwindow 
); 
1481     // GDK sends surplus button down events 
1482     // before a double click event. We 
1483     // need to filter these out. 
1484     if (gdk_event
->type 
== GDK_BUTTON_PRESS
) 
1486         GdkEvent 
*peek_event 
= gdk_event_peek(); 
1489             if ((peek_event
->type 
== GDK_2BUTTON_PRESS
) || 
1490                 (peek_event
->type 
== GDK_3BUTTON_PRESS
)) 
1492                 gdk_event_free( peek_event 
); 
1497                 gdk_event_free( peek_event 
); 
1502     wxEventType event_type 
= wxEVT_NULL
; 
1504     // GdkDisplay is a GTK+ 2.2.0 thing 
1505 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0) 
1506     if ( gdk_event
->type 
== GDK_2BUTTON_PRESS 
&& 
1507             !gtk_check_version(2,2,0) && 
1508             gdk_event
->button 
>= 1 && gdk_event
->button 
<= 3 ) 
1510         // Reset GDK internal timestamp variables in order to disable GDK 
1511         // triple click events. GDK will then next time believe no button has 
1512         // been clicked just before, and send a normal button click event. 
1513         GdkDisplay
* display 
= gtk_widget_get_display (widget
); 
1514         display
->button_click_time
[1] = 0; 
1515         display
->button_click_time
[0] = 0; 
1519     if (gdk_event
->button 
== 1) 
1521         // note that GDK generates triple click events which are not supported 
1522         // by wxWidgets but still have to be passed to the app as otherwise 
1523         // clicks would simply go missing 
1524         switch (gdk_event
->type
) 
1526             // we shouldn't get triple clicks at all for GTK2 because we 
1527             // suppress them artificially using the code above but we still 
1528             // should map them to something for GTK1 and not just ignore them 
1529             // as this would lose clicks 
1530             case GDK_3BUTTON_PRESS
:     // we could also map this to DCLICK... 
1531             case GDK_BUTTON_PRESS
: 
1532                 event_type 
= wxEVT_LEFT_DOWN
; 
1535             case GDK_2BUTTON_PRESS
: 
1536                 event_type 
= wxEVT_LEFT_DCLICK
; 
1540                 // just to silence gcc warnings 
1544     else if (gdk_event
->button 
== 2) 
1546         switch (gdk_event
->type
) 
1548             case GDK_3BUTTON_PRESS
: 
1549             case GDK_BUTTON_PRESS
: 
1550                 event_type 
= wxEVT_MIDDLE_DOWN
; 
1553             case GDK_2BUTTON_PRESS
: 
1554                 event_type 
= wxEVT_MIDDLE_DCLICK
; 
1561     else if (gdk_event
->button 
== 3) 
1563         switch (gdk_event
->type
) 
1565             case GDK_3BUTTON_PRESS
: 
1566             case GDK_BUTTON_PRESS
: 
1567                 event_type 
= wxEVT_RIGHT_DOWN
; 
1570             case GDK_2BUTTON_PRESS
: 
1571                 event_type 
= wxEVT_RIGHT_DCLICK
; 
1578     else if (gdk_event
->button 
== 4 || gdk_event
->button 
== 5) 
1580         if (gdk_event
->type 
== GDK_BUTTON_PRESS 
) 
1582             event_type 
= wxEVT_MOUSEWHEEL
; 
1586     if ( event_type 
== wxEVT_NULL 
) 
1588         // unknown mouse button or click type 
1592     wxMouseEvent 
event( event_type 
); 
1593     InitMouseEvent( win
, event
, gdk_event 
); 
1595     AdjustEventButtonState(event
); 
1597     // wxListBox actually gets mouse events from the item, so we need to give it 
1598     // a chance to correct this 
1599     win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
); 
1601     // find the correct window to send the event to: it may be a different one 
1602     // from the one which got it at GTK+ level because some controls don't have 
1603     // their own X window and thus cannot get any events. 
1604     if ( !g_captureWindow 
) 
1605         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1607     // reset the event object and id in case win changed. 
1608     event
.SetEventObject( win 
); 
1609     event
.SetId( win
->GetId() ); 
1611     if (win
->GTKProcessEvent( event 
)) 
1616     if (event_type 
== wxEVT_RIGHT_DOWN
) 
1618         // generate a "context menu" event: this is similar to right mouse 
1619         // click under many GUIs except that it is generated differently 
1620         // (right up under MSW, ctrl-click under Mac, right down here) and 
1622         // (a) it's a command event and so is propagated to the parent 
1623         // (b) under some ports it can be generated from kbd too 
1624         // (c) it uses screen coords (because of (a)) 
1625         wxContextMenuEvent 
evtCtx( 
1628             win
->ClientToScreen(event
.GetPosition())); 
1629         evtCtx
.SetEventObject(win
); 
1630         return win
->GTKProcessEvent(evtCtx
); 
1636 //----------------------------------------------------------------------------- 
1637 // "button_release_event" 
1638 //----------------------------------------------------------------------------- 
1641 gtk_window_button_release_callback( GtkWidget 
*widget
, 
1642                                     GdkEventButton 
*gdk_event
, 
1645     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1647     wxEventType event_type 
= wxEVT_NULL
; 
1649     switch (gdk_event
->button
) 
1652             event_type 
= wxEVT_LEFT_UP
; 
1656             event_type 
= wxEVT_MIDDLE_UP
; 
1660             event_type 
= wxEVT_RIGHT_UP
; 
1664             // unknown button, don't process 
1668     wxMouseEvent 
event( event_type 
); 
1669     InitMouseEvent( win
, event
, gdk_event 
); 
1671     AdjustEventButtonState(event
); 
1673     // same wxListBox hack as above 
1674     win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
); 
1676     if ( !g_captureWindow 
) 
1677         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1679     // reset the event object and id in case win changed. 
1680     event
.SetEventObject( win 
); 
1681     event
.SetId( win
->GetId() ); 
1683     return win
->GTKProcessEvent(event
); 
1686 //----------------------------------------------------------------------------- 
1687 // "motion_notify_event" 
1688 //----------------------------------------------------------------------------- 
1691 gtk_window_motion_notify_callback( GtkWidget 
*widget
, 
1692                                    GdkEventMotion 
*gdk_event
, 
1695     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1697     if (gdk_event
->is_hint
) 
1701         GdkModifierType state
; 
1702         gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
1707     wxMouseEvent 
event( wxEVT_MOTION 
); 
1708     InitMouseEvent(win
, event
, gdk_event
); 
1710     if ( g_captureWindow 
) 
1712         // synthesise a mouse enter or leave event if needed 
1713         GdkWindow 
*winUnderMouse 
= gdk_window_at_pointer(NULL
, NULL
); 
1714         // This seems to be necessary and actually been added to 
1715         // GDK itself in version 2.0.X 
1718         bool hasMouse 
= winUnderMouse 
== gdk_event
->window
; 
1719         if ( hasMouse 
!= g_captureWindowHasMouse 
) 
1721             // the mouse changed window 
1722             g_captureWindowHasMouse 
= hasMouse
; 
1724             wxMouseEvent 
eventM(g_captureWindowHasMouse 
? wxEVT_ENTER_WINDOW
 
1725                                                         : wxEVT_LEAVE_WINDOW
); 
1726             InitMouseEvent(win
, eventM
, gdk_event
); 
1727             eventM
.SetEventObject(win
); 
1728             win
->GTKProcessEvent(eventM
); 
1733         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1735         // reset the event object and id in case win changed. 
1736         event
.SetEventObject( win 
); 
1737         event
.SetId( win
->GetId() ); 
1740     if ( !g_captureWindow 
) 
1742         wxSetCursorEvent 
cevent( event
.m_x
, event
.m_y 
); 
1743         if (win
->GTKProcessEvent( cevent 
)) 
1745             win
->SetCursor( cevent
.GetCursor() ); 
1749     return win
->GTKProcessEvent(event
); 
1752 //----------------------------------------------------------------------------- 
1753 // "scroll_event", (mouse wheel event) 
1754 //----------------------------------------------------------------------------- 
1757 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
) 
1761     // don't need to install idle handler, its done from "event" signal 
1763     if (gdk_event
->direction 
!= GDK_SCROLL_UP 
&& 
1764         gdk_event
->direction 
!= GDK_SCROLL_DOWN
) 
1769     wxMouseEvent 
event(wxEVT_MOUSEWHEEL
); 
1770     // Can't use InitMouse macro because scroll events don't have button 
1771     event
.SetTimestamp( gdk_event
->time 
); 
1772     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
); 
1773     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
); 
1774     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
); 
1775     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
); 
1776     event
.m_leftDown 
= (gdk_event
->state 
& GDK_BUTTON1_MASK
); 
1777     event
.m_middleDown 
= (gdk_event
->state 
& GDK_BUTTON2_MASK
); 
1778     event
.m_rightDown 
= (gdk_event
->state 
& GDK_BUTTON3_MASK
); 
1779     event
.m_linesPerAction 
= 3; 
1780     event
.m_wheelDelta 
= 120; 
1781     if (gdk_event
->direction 
== GDK_SCROLL_UP
) 
1782         event
.m_wheelRotation 
= 120; 
1784         event
.m_wheelRotation 
= -120; 
1786     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1787     event
.m_x 
= (wxCoord
)gdk_event
->x 
- pt
.x
; 
1788     event
.m_y 
= (wxCoord
)gdk_event
->y 
- pt
.y
; 
1790     event
.SetEventObject( win 
); 
1791     event
.SetId( win
->GetId() ); 
1792     event
.SetTimestamp( gdk_event
->time 
); 
1794     return win
->GTKProcessEvent(event
); 
1797 //----------------------------------------------------------------------------- 
1799 //----------------------------------------------------------------------------- 
1801 static gboolean 
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
) 
1803     wxContextMenuEvent 
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1)); 
1804     event
.SetEventObject(win
); 
1805     return win
->GTKProcessEvent(event
); 
1808 //----------------------------------------------------------------------------- 
1810 //----------------------------------------------------------------------------- 
1813 gtk_window_focus_in_callback( GtkWidget 
*widget
, 
1814                               GdkEventFocus 
*WXUNUSED(event
), 
1819     // don't need to install idle handler, its done from "event" signal 
1822         gtk_im_context_focus_in(win
->m_imData
->context
); 
1825     g_focusWindow 
= win
; 
1827     wxLogTrace(TRACE_FOCUS
, 
1828                _T("%s: focus in"), win
->GetName().c_str()); 
1832         gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
); 
1836     // caret needs to be informed about focus change 
1837     wxCaret 
*caret 
= win
->GetCaret(); 
1840         caret
->OnSetFocus(); 
1842 #endif // wxUSE_CARET 
1844     gboolean ret 
= FALSE
; 
1846     // does the window itself think that it has the focus? 
1847     if ( !win
->m_hasFocus 
) 
1849         // not yet, notify it 
1850         win
->m_hasFocus 
= true; 
1852         (void)DoSendFocusEvents(win
); 
1857     // Disable default focus handling for custom windows 
1858     // since the default GTK+ handler issues a repaint 
1859     if (win
->m_wxwindow
) 
1865 //----------------------------------------------------------------------------- 
1866 // "focus_out_event" 
1867 //----------------------------------------------------------------------------- 
1870 gtk_window_focus_out_callback( GtkWidget 
*widget
, 
1871                                GdkEventFocus 
*gdk_event
, 
1876     // don't need to install idle handler, its done from "event" signal 
1879         gtk_im_context_focus_out(win
->m_imData
->context
); 
1881     wxLogTrace( TRACE_FOCUS
, 
1882                 _T("%s: focus out"), win
->GetName().c_str() ); 
1885     wxWindowGTK 
*winFocus 
= wxFindFocusedChild(win
); 
1889     g_focusWindow 
= (wxWindowGTK 
*)NULL
; 
1897     // caret needs to be informed about focus change 
1898     wxCaret 
*caret 
= win
->GetCaret(); 
1901         caret
->OnKillFocus(); 
1903 #endif // wxUSE_CARET 
1905     gboolean ret 
= FALSE
; 
1907     // don't send the window a kill focus event if it thinks that it doesn't 
1908     // have focus already 
1909     if ( win
->m_hasFocus 
) 
1911         win
->m_hasFocus 
= false; 
1913         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, win
->GetId() ); 
1914         event
.SetEventObject( win 
); 
1916         (void)win
->GTKProcessEvent( event 
); 
1921     // Disable default focus handling for custom windows 
1922     // since the default GTK+ handler issues a repaint 
1923     if (win
->m_wxwindow
) 
1929 //----------------------------------------------------------------------------- 
1930 // "enter_notify_event" 
1931 //----------------------------------------------------------------------------- 
1934 gtk_window_enter_callback( GtkWidget 
*widget
, 
1935                            GdkEventCrossing 
*gdk_event
, 
1938     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1940     // Event was emitted after a grab 
1941     if (gdk_event
->mode 
!= GDK_CROSSING_NORMAL
) return FALSE
; 
1945     GdkModifierType state 
= (GdkModifierType
)0; 
1947     gdk_window_get_pointer( widget
->window
, &x
, &y
, &state 
); 
1949     wxMouseEvent 
event( wxEVT_ENTER_WINDOW 
); 
1950     InitMouseEvent(win
, event
, gdk_event
); 
1951     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1952     event
.m_x 
= x 
+ pt
.x
; 
1953     event
.m_y 
= y 
+ pt
.y
; 
1955     if ( !g_captureWindow 
) 
1957         wxSetCursorEvent 
cevent( event
.m_x
, event
.m_y 
); 
1958         if (win
->GTKProcessEvent( cevent 
)) 
1960             win
->SetCursor( cevent
.GetCursor() ); 
1964     return win
->GTKProcessEvent(event
); 
1967 //----------------------------------------------------------------------------- 
1968 // "leave_notify_event" 
1969 //----------------------------------------------------------------------------- 
1972 gtk_window_leave_callback( GtkWidget 
*widget
, 
1973                            GdkEventCrossing 
*gdk_event
, 
1976     wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
); 
1978     // Event was emitted after an ungrab 
1979     if (gdk_event
->mode 
!= GDK_CROSSING_NORMAL
) return FALSE
; 
1981     wxMouseEvent 
event( wxEVT_LEAVE_WINDOW 
); 
1982     event
.SetTimestamp( gdk_event
->time 
); 
1983     event
.SetEventObject( win 
); 
1987     GdkModifierType state 
= (GdkModifierType
)0; 
1989     gdk_window_get_pointer( widget
->window
, &x
, &y
, &state 
); 
1991     event
.m_shiftDown 
= (state 
& GDK_SHIFT_MASK
) != 0; 
1992     event
.m_controlDown 
= (state 
& GDK_CONTROL_MASK
) != 0; 
1993     event
.m_altDown 
= (state 
& GDK_MOD1_MASK
) != 0; 
1994     event
.m_metaDown 
= (state 
& GDK_MOD2_MASK
) != 0; 
1995     event
.m_leftDown 
= (state 
& GDK_BUTTON1_MASK
) != 0; 
1996     event
.m_middleDown 
= (state 
& GDK_BUTTON2_MASK
) != 0; 
1997     event
.m_rightDown 
= (state 
& GDK_BUTTON3_MASK
) != 0; 
1999     wxPoint pt 
= win
->GetClientAreaOrigin(); 
2000     event
.m_x 
= x 
+ pt
.x
; 
2001     event
.m_y 
= y 
+ pt
.y
; 
2003     return win
->GTKProcessEvent(event
); 
2006 //----------------------------------------------------------------------------- 
2007 // "value_changed" from scrollbar 
2008 //----------------------------------------------------------------------------- 
2011 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
) 
2013     wxEventType eventType 
= win
->GetScrollEventType(range
); 
2014     if (eventType 
!= wxEVT_NULL
) 
2016         // Convert scroll event type to scrollwin event type 
2017         eventType 
+= wxEVT_SCROLLWIN_TOP 
- wxEVT_SCROLL_TOP
; 
2019         // find the scrollbar which generated the event 
2020         wxWindowGTK::ScrollDir dir 
= win
->ScrollDirFromRange(range
); 
2022         // generate the corresponding wx event 
2023         const int orient 
= win
->OrientFromScrollDir(dir
); 
2024         wxScrollWinEvent 
event(eventType
, win
->GetScrollPos(orient
), orient
); 
2025         event
.SetEventObject(win
); 
2027         win
->m_blockValueChanged
[dir
] = true; 
2028         win
->GTKProcessEvent(event
); 
2029         win
->m_blockValueChanged
[dir
] = false; 
2033 //----------------------------------------------------------------------------- 
2034 // "button_press_event" from scrollbar 
2035 //----------------------------------------------------------------------------- 
2038 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
) 
2042     // don't need to install idle handler, its done from "event" signal 
2044     g_blockEventsOnScroll 
= true; 
2045     win
->m_mouseButtonDown 
= true; 
2050 //----------------------------------------------------------------------------- 
2051 // "event_after" from scrollbar 
2052 //----------------------------------------------------------------------------- 
2055 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
) 
2057     if (event
->type 
== GDK_BUTTON_RELEASE
) 
2059         g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
); 
2061         const int orient 
= win
->OrientFromScrollDir( 
2062                                         win
->ScrollDirFromRange(range
)); 
2063         wxScrollWinEvent 
event(wxEVT_SCROLLWIN_THUMBRELEASE
, win
->GetScrollPos(orient
), orient
); 
2064         event
.SetEventObject(win
); 
2065         win
->GTKProcessEvent(event
); 
2069 //----------------------------------------------------------------------------- 
2070 // "button_release_event" from scrollbar 
2071 //----------------------------------------------------------------------------- 
2074 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
) 
2078     g_blockEventsOnScroll 
= false; 
2079     win
->m_mouseButtonDown 
= false; 
2080     // If thumb tracking 
2081     if (win
->m_isScrolling
) 
2083         win
->m_isScrolling 
= false; 
2084         // Hook up handler to send thumb release event after this emission is finished. 
2085         // To allow setting scroll position from event handler, sending event must 
2086         // be deferred until after the GtkRange handler for this signal has run 
2087         g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
); 
2093 //----------------------------------------------------------------------------- 
2094 // "realize" from m_widget 
2095 //----------------------------------------------------------------------------- 
2097 /* We cannot set colours and fonts before the widget has 
2098    been realized, so we do this directly after realization. */ 
2101 gtk_window_realized_callback( GtkWidget 
*m_widget
, wxWindow 
*win 
) 
2106         wxapp_install_idle_handler(); 
2110         GtkPizza 
*pizza 
= GTK_PIZZA( m_widget 
); 
2111         gtk_im_context_set_client_window( win
->m_imData
->context
, 
2112                                           pizza
->bin_window 
); 
2115     wxWindowCreateEvent 
event( win 
); 
2116     event
.SetEventObject( win 
); 
2117     win
->GTKProcessEvent( event 
); 
2120 //----------------------------------------------------------------------------- 
2122 //----------------------------------------------------------------------------- 
2125 void gtk_window_size_callback( GtkWidget 
*WXUNUSED(widget
), 
2126                                GtkAllocation 
*alloc
, 
2130         wxapp_install_idle_handler(); 
2132     int client_width 
= 0; 
2133     int client_height 
= 0; 
2134     win
->GetClientSize( &client_width
, &client_height 
); 
2135     if ((client_width 
== win
->m_oldClientWidth
) && (client_height 
== win
->m_oldClientHeight
)) 
2139         wxPrintf( wxT("size_allocate ") ); 
2140         if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName()) 
2141             wxPrintf( win
->GetClassInfo()->GetClassName() ); 
2142         wxPrintf( wxT(" %d %d %d %d\n"), 
2149     GTK_PIZZA(win
->m_wxwindow
)->m_width 
= alloc
->width
; 
2151     win
->m_oldClientWidth 
= client_width
; 
2152     win
->m_oldClientHeight 
= client_height
; 
2154     if (!win
->m_nativeSizeEvent
) 
2156         wxSizeEvent 
event( win
->GetSize(), win
->GetId() ); 
2157         event
.SetEventObject( win 
); 
2158         win
->GTKProcessEvent( event 
); 
2164     #define WXUNUSED_UNLESS_XIM(param)  param 
2166     #define WXUNUSED_UNLESS_XIM(param)  WXUNUSED(param) 
2169 /* Resize XIM window */ 
2171 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
), 
2172                                  GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
), 
2173                                  wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) ) 
2176         wxapp_install_idle_handler(); 
2182     if  (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
) 
2186         gdk_drawable_get_size (widget
->window
, &width
, &height
); 
2187         win
->m_icattr
->preedit_area
.width 
= width
; 
2188         win
->m_icattr
->preedit_area
.height 
= height
; 
2189         gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
); 
2194 //----------------------------------------------------------------------------- 
2195 // "realize" from m_wxwindow 
2196 //----------------------------------------------------------------------------- 
2198 /* Initialize XIM support */ 
2201 gtk_wxwindow_realized_callback( GtkWidget 
* WXUNUSED_UNLESS_XIM(widget
), 
2202                                 wxWindowGTK 
* WXUNUSED_UNLESS_XIM(win
) ) 
2205         wxapp_install_idle_handler(); 
2208     if (win
->m_ic
) return; 
2209     if (!widget
) return; 
2210     if (!gdk_im_ready()) return; 
2212     win
->m_icattr 
= gdk_ic_attr_new(); 
2213     if (!win
->m_icattr
) return; 
2217     GdkColormap 
*colormap
; 
2218     GdkICAttr 
*attr 
= win
->m_icattr
; 
2219     unsigned attrmask 
= GDK_IC_ALL_REQ
; 
2221     GdkIMStyle supported_style 
= (GdkIMStyle
) 
2222                                   (GDK_IM_PREEDIT_NONE 
| 
2223                                    GDK_IM_PREEDIT_NOTHING 
| 
2224                                    GDK_IM_PREEDIT_POSITION 
| 
2225                                    GDK_IM_STATUS_NONE 
| 
2226                                    GDK_IM_STATUS_NOTHING
); 
2228     if (widget
->style 
&& widget
->style
->font
->type 
!= GDK_FONT_FONTSET
) 
2229         supported_style 
= (GdkIMStyle
)(supported_style 
& ~GDK_IM_PREEDIT_POSITION
); 
2231     attr
->style 
= style 
= gdk_im_decide_style (supported_style
); 
2232     attr
->client_window 
= widget
->window
; 
2234     if ((colormap 
= gtk_widget_get_colormap (widget
)) != 
2235             gtk_widget_get_default_colormap ()) 
2237         attrmask 
|= GDK_IC_PREEDIT_COLORMAP
; 
2238         attr
->preedit_colormap 
= colormap
; 
2241     attrmask 
|= GDK_IC_PREEDIT_FOREGROUND
; 
2242     attrmask 
|= GDK_IC_PREEDIT_BACKGROUND
; 
2243     attr
->preedit_foreground 
= widget
->style
->fg
[GTK_STATE_NORMAL
]; 
2244     attr
->preedit_background 
= widget
->style
->base
[GTK_STATE_NORMAL
]; 
2246     switch (style 
& GDK_IM_PREEDIT_MASK
) 
2248         case GDK_IM_PREEDIT_POSITION
: 
2249             if (widget
->style 
&& widget
->style
->font
->type 
!= GDK_FONT_FONTSET
) 
2251                 g_warning ("over-the-spot style requires fontset"); 
2255             gdk_drawable_get_size (widget
->window
, &width
, &height
); 
2257             attrmask 
|= GDK_IC_PREEDIT_POSITION_REQ
; 
2258             attr
->spot_location
.x 
= 0; 
2259             attr
->spot_location
.y 
= height
; 
2260             attr
->preedit_area
.x 
= 0; 
2261             attr
->preedit_area
.y 
= 0; 
2262             attr
->preedit_area
.width 
= width
; 
2263             attr
->preedit_area
.height 
= height
; 
2264             attr
->preedit_fontset 
= widget
->style
->font
; 
2269       win
->m_ic 
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
); 
2271       if (win
->m_ic 
== NULL
) 
2272           g_warning ("Can't create input context."); 
2275           mask 
= gdk_window_get_events (widget
->window
); 
2276           mask 
= (GdkEventMask
)(mask 
| gdk_ic_get_events (win
->m_ic
)); 
2277           gdk_window_set_events (widget
->window
, mask
); 
2279           if (GTK_WIDGET_HAS_FOCUS(widget
)) 
2280               gdk_im_begin (win
->m_ic
, widget
->window
); 
2287 // ---------------------------------------------------------------------------- 
2288 // this wxWindowBase function is implemented here (in platform-specific file) 
2289 // because it is static and so couldn't be made virtual 
2290 // ---------------------------------------------------------------------------- 
2292 wxWindow 
*wxWindowBase::DoFindFocus() 
2294     // the cast is necessary when we compile in wxUniversal mode 
2295     return (wxWindow 
*)g_focusWindow
; 
2298 //----------------------------------------------------------------------------- 
2299 // InsertChild for wxWindowGTK. 
2300 //----------------------------------------------------------------------------- 
2302 /* Callback for wxWindowGTK. This very strange beast has to be used because 
2303  * C++ has no virtual methods in a constructor. We have to emulate a 
2304  * virtual function here as wxNotebook requires a different way to insert 
2305  * a child in it. I had opted for creating a wxNotebookPage window class 
2306  * which would have made this superfluous (such in the MDI window system), 
2307  * but no-one was listening to me... */ 
2309 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child 
) 
2311     /* the window might have been scrolled already, do we 
2312        have to adapt the position */ 
2313     GtkPizza 
*pizza 
= GTK_PIZZA(parent
->m_wxwindow
); 
2314     child
->m_x 
+= gtk_pizza_get_xoffset( pizza 
); 
2315     child
->m_y 
+= gtk_pizza_get_yoffset( pizza 
); 
2317     gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
), 
2318                      GTK_WIDGET(child
->m_widget
), 
2325 //----------------------------------------------------------------------------- 
2327 //----------------------------------------------------------------------------- 
2329 wxWindow 
*wxGetActiveWindow() 
2331     return wxWindow::FindFocus(); 
2335 wxMouseState 
wxGetMouseState() 
2341     GdkModifierType mask
; 
2343     gdk_window_get_pointer(NULL
, &x
, &y
, &mask
); 
2347     ms
.SetLeftDown(mask 
& GDK_BUTTON1_MASK
); 
2348     ms
.SetMiddleDown(mask 
& GDK_BUTTON2_MASK
); 
2349     ms
.SetRightDown(mask 
& GDK_BUTTON3_MASK
); 
2351     ms
.SetControlDown(mask 
& GDK_CONTROL_MASK
); 
2352     ms
.SetShiftDown(mask 
& GDK_SHIFT_MASK
); 
2353     ms
.SetAltDown(mask 
& GDK_MOD1_MASK
); 
2354     ms
.SetMetaDown(mask 
& GDK_MOD2_MASK
); 
2359 //----------------------------------------------------------------------------- 
2361 //----------------------------------------------------------------------------- 
2363 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu() 
2365 #ifdef __WXUNIVERSAL__ 
2366     IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
) 
2368     IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
) 
2369 #endif // __WXUNIVERSAL__/__WXGTK__ 
2371 void wxWindowGTK::Init() 
2374     m_widget 
= (GtkWidget 
*) NULL
; 
2375     m_wxwindow 
= (GtkWidget 
*) NULL
; 
2376     m_focusWidget 
= (GtkWidget 
*) NULL
; 
2386     m_needParent 
= true; 
2387     m_isBeingDeleted 
= false; 
2389     m_showOnIdle
= false; 
2392     m_nativeSizeEvent 
= false; 
2394     m_hasScrolling 
= false; 
2395     m_isScrolling 
= false; 
2396     m_mouseButtonDown 
= false; 
2397     m_blockScrollEvent 
= false; 
2399     // initialize scrolling stuff 
2400     for ( int dir 
= 0; dir 
< ScrollDir_Max
; dir
++ ) 
2402         m_scrollBar
[dir
] = NULL
; 
2403         m_scrollPos
[dir
] = 0; 
2404         m_blockValueChanged
[dir
] = false; 
2408     m_oldClientHeight 
= 0; 
2412     m_insertCallback 
= (wxInsertChildFunction
) NULL
; 
2414     m_acceptsFocus 
= false; 
2417     m_clipPaintRegion 
= false; 
2419     m_needsStyleChange 
= false; 
2421     m_cursor 
= *wxSTANDARD_CURSOR
; 
2424     m_dirtyTabOrder 
= false; 
2427 wxWindowGTK::wxWindowGTK() 
2432 wxWindowGTK::wxWindowGTK( wxWindow 
*parent
, 
2437                           const wxString 
&name  
) 
2441     Create( parent
, id
, pos
, size
, style
, name 
); 
2444 bool wxWindowGTK::Create( wxWindow 
*parent
, 
2449                           const wxString 
&name  
) 
2451     if (!PreCreation( parent
, pos
, size 
) || 
2452         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
2454         wxFAIL_MSG( wxT("wxWindowGTK creation failed") ); 
2458     m_insertCallback 
= wxInsertChildInWindow
; 
2460     m_widget 
= gtk_scrolled_window_new( (GtkAdjustment 
*) NULL
, (GtkAdjustment 
*) NULL 
); 
2461     GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
2463     GtkScrolledWindow 
*scrolledWindow 
= GTK_SCROLLED_WINDOW(m_widget
); 
2465     GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) ); 
2466     scroll_class
->scrollbar_spacing 
= 0; 
2468     gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC 
); 
2470     m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
); 
2471     m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
); 
2473     m_wxwindow 
= gtk_pizza_new(); 
2475 #ifndef __WXUNIVERSAL__ 
2476     GtkPizza 
*pizza 
= GTK_PIZZA(m_wxwindow
); 
2478     if (HasFlag(wxRAISED_BORDER
)) 
2480         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT 
); 
2482     else if (HasFlag(wxSUNKEN_BORDER
)) 
2484         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN 
); 
2486     else if (HasFlag(wxSIMPLE_BORDER
)) 
2488         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN 
); 
2492         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE 
); 
2494 #endif // __WXUNIVERSAL__ 
2496     gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow 
); 
2498     GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS 
); 
2499     m_acceptsFocus 
= true; 
2501     // connect various scroll-related events 
2502     for ( int dir 
= 0; dir 
< ScrollDir_Max
; dir
++ ) 
2504         // these handlers block mouse events to any window during scrolling 
2505         // such as motion events and prevent GTK and wxWidgets from fighting 
2506         // over where the slider should be 
2507         g_signal_connect(m_scrollBar
[dir
], "button_press_event", 
2508                          G_CALLBACK(gtk_scrollbar_button_press_event
), this); 
2509         g_signal_connect(m_scrollBar
[dir
], "button_release_event", 
2510                          G_CALLBACK(gtk_scrollbar_button_release_event
), this); 
2512         gulong handler_id 
= g_signal_connect(m_scrollBar
[dir
], "event_after", 
2513                                 G_CALLBACK(gtk_scrollbar_event_after
), this); 
2514         g_signal_handler_block(m_scrollBar
[dir
], handler_id
); 
2516         // these handlers get notified when scrollbar slider moves 
2517         g_signal_connect(m_scrollBar
[dir
], "value_changed", 
2518                          G_CALLBACK(gtk_scrollbar_value_changed
), this); 
2521     gtk_widget_show( m_wxwindow 
); 
2524         m_parent
->DoAddChild( this ); 
2526     m_focusWidget 
= m_wxwindow
; 
2533 wxWindowGTK::~wxWindowGTK() 
2537     if (g_focusWindow 
== this) 
2538         g_focusWindow 
= NULL
; 
2540     if ( g_delayedFocus 
== this ) 
2541         g_delayedFocus 
= NULL
; 
2543     m_isBeingDeleted 
= true; 
2546     // destroy children before destroying this window itself 
2549     // unhook focus handlers to prevent stray events being 
2550     // propagated to this (soon to be) dead object 
2551     if (m_focusWidget 
!= NULL
) 
2553         g_signal_handlers_disconnect_by_func (m_focusWidget
, 
2554                                               (gpointer
) gtk_window_focus_in_callback
, 
2556         g_signal_handlers_disconnect_by_func (m_focusWidget
, 
2557                                               (gpointer
) gtk_window_focus_out_callback
, 
2566         gdk_ic_destroy (m_ic
); 
2568         gdk_ic_attr_destroy (m_icattr
); 
2571     // delete before the widgets to avoid a crash on solaris 
2576         gtk_widget_destroy( m_wxwindow 
); 
2577         m_wxwindow 
= (GtkWidget
*) NULL
; 
2582         gtk_widget_destroy( m_widget 
); 
2583         m_widget 
= (GtkWidget
*) NULL
; 
2587 bool wxWindowGTK::PreCreation( wxWindowGTK 
*parent
, const wxPoint 
&pos
,  const wxSize 
&size 
) 
2589     wxCHECK_MSG( !m_needParent 
|| parent
, false, wxT("Need complete parent.") ); 
2591     // Use either the given size, or the default if -1 is given. 
2592     // See wxWindowBase for these functions. 
2593     m_width 
= WidthDefault(size
.x
) ; 
2594     m_height 
= HeightDefault(size
.y
); 
2602 void wxWindowGTK::PostCreation() 
2604     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2610             // these get reported to wxWidgets -> wxPaintEvent 
2612             gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE 
); 
2614             g_signal_connect (m_wxwindow
, "expose_event", 
2615                               G_CALLBACK (gtk_window_expose_callback
), this); 
2617             if (GetLayoutDirection() == wxLayout_LeftToRight
) 
2618                 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE 
) ); 
2621         // Create input method handler 
2622         m_imData 
= new wxGtkIMData
; 
2624         // Cannot handle drawing preedited text yet 
2625         gtk_im_context_set_use_preedit( m_imData
->context
, FALSE 
); 
2627         g_signal_connect (m_imData
->context
, "commit", 
2628                           G_CALLBACK (gtk_wxwindow_commit_cb
), this); 
2630         // these are called when the "sunken" or "raised" borders are drawn 
2631         g_signal_connect (m_widget
, "expose_event", 
2632                           G_CALLBACK (gtk_window_own_expose_callback
), this); 
2637     if (!GTK_IS_WINDOW(m_widget
)) 
2639         if (m_focusWidget 
== NULL
) 
2640             m_focusWidget 
= m_widget
; 
2644             g_signal_connect (m_focusWidget
, "focus_in_event", 
2645                           G_CALLBACK (gtk_window_focus_in_callback
), this); 
2646             g_signal_connect (m_focusWidget
, "focus_out_event", 
2647                                 G_CALLBACK (gtk_window_focus_out_callback
), this); 
2651             g_signal_connect_after (m_focusWidget
, "focus_in_event", 
2652                           G_CALLBACK (gtk_window_focus_in_callback
), this); 
2653             g_signal_connect_after (m_focusWidget
, "focus_out_event", 
2654                                 G_CALLBACK (gtk_window_focus_out_callback
), this); 
2658     // connect to the various key and mouse handlers 
2660     GtkWidget 
*connect_widget 
= GetConnectWidget(); 
2662     ConnectWidget( connect_widget 
); 
2664     /* We cannot set colours, fonts and cursors before the widget has 
2665        been realized, so we do this directly after realization */ 
2666     g_signal_connect (connect_widget
, "realize", 
2667                       G_CALLBACK (gtk_window_realized_callback
), this); 
2671         // Catch native resize events 
2672         g_signal_connect (m_wxwindow
, "size_allocate", 
2673                           G_CALLBACK (gtk_window_size_callback
), this); 
2675         // Initialize XIM support 
2676         g_signal_connect (m_wxwindow
, "realize", 
2677                           G_CALLBACK (gtk_wxwindow_realized_callback
), this); 
2679         // And resize XIM window 
2680         g_signal_connect (m_wxwindow
, "size_allocate", 
2681                           G_CALLBACK (gtk_wxwindow_size_callback
), this); 
2684     if (GTK_IS_COMBO(m_widget
)) 
2686         GtkCombo 
*gcombo 
= GTK_COMBO(m_widget
); 
2688         g_signal_connect (gcombo
->entry
, "size_request", 
2689                           G_CALLBACK (wxgtk_combo_size_request_callback
), 
2692 #ifdef GTK_IS_FILE_CHOOSER_BUTTON 
2693     else if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget
)) 
2695         // If we connect to the "size_request" signal of a GtkFileChooserButton 
2696         // then that control won't be sized properly when placed inside sizers 
2697         // (this can be tested removing this elseif and running XRC or WIDGETS samples) 
2698         // FIXME: what should be done here ? 
2703         // This is needed if we want to add our windows into native 
2704         // GTK controls, such as the toolbar. With this callback, the 
2705         // toolbar gets to know the correct size (the one set by the 
2706         // programmer). Sadly, it misbehaves for wxComboBox. 
2707         g_signal_connect (m_widget
, "size_request", 
2708                           G_CALLBACK (wxgtk_window_size_request_callback
), 
2712     InheritAttributes(); 
2716     SetLayoutDirection(wxLayout_Default
); 
2718     // unless the window was created initially hidden (i.e. Hide() had been 
2719     // called before Create()), we should show it at GTK+ level as well 
2721         gtk_widget_show( m_widget 
); 
2724 void wxWindowGTK::ConnectWidget( GtkWidget 
*widget 
) 
2726     g_signal_connect (widget
, "key_press_event", 
2727                       G_CALLBACK (gtk_window_key_press_callback
), this); 
2728     g_signal_connect (widget
, "key_release_event", 
2729                       G_CALLBACK (gtk_window_key_release_callback
), this); 
2730     g_signal_connect (widget
, "button_press_event", 
2731                       G_CALLBACK (gtk_window_button_press_callback
), this); 
2732     g_signal_connect (widget
, "button_release_event", 
2733                       G_CALLBACK (gtk_window_button_release_callback
), this); 
2734     g_signal_connect (widget
, "motion_notify_event", 
2735                       G_CALLBACK (gtk_window_motion_notify_callback
), this); 
2736     g_signal_connect (widget
, "scroll_event", 
2737                       G_CALLBACK (window_scroll_event
), this); 
2738     g_signal_connect (widget
, "popup_menu", 
2739                      G_CALLBACK (wxgtk_window_popup_menu_callback
), this); 
2740     g_signal_connect (widget
, "enter_notify_event", 
2741                       G_CALLBACK (gtk_window_enter_callback
), this); 
2742     g_signal_connect (widget
, "leave_notify_event", 
2743                       G_CALLBACK (gtk_window_leave_callback
), this); 
2746 bool wxWindowGTK::Destroy() 
2748     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2752     return wxWindowBase::Destroy(); 
2755 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
) 
2757     // inform the parent to perform the move 
2758     gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height 
); 
2762 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
2764     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2765     wxASSERT_MSG( (m_parent 
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") ); 
2768     printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height ); 
2771     if (m_resizing
) return; /* I don't like recursions */ 
2774     int currentX
, currentY
; 
2775     GetPosition(¤tX
, ¤tY
); 
2776     if (x 
== -1 && !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
2778     if (y 
== -1 && !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
2780     AdjustForParentClientOrigin(x
, y
, sizeFlags
); 
2782     // calculate the best size if we should auto size the window 
2783     if ( ((sizeFlags 
& wxSIZE_AUTO_WIDTH
) && width 
== -1) || 
2784          ((sizeFlags 
& wxSIZE_AUTO_HEIGHT
) && height 
== -1) ) 
2786         const wxSize sizeBest 
= GetBestSize(); 
2787         if ( (sizeFlags 
& wxSIZE_AUTO_WIDTH
) && width 
== -1 ) 
2789         if ( (sizeFlags 
& wxSIZE_AUTO_HEIGHT
) && height 
== -1 ) 
2790             height 
= sizeBest
.y
; 
2798     int minWidth  
= GetMinWidth(), 
2799         minHeight 
= GetMinHeight(), 
2800         maxWidth  
= GetMaxWidth(), 
2801         maxHeight 
= GetMaxHeight(); 
2803     if ((minWidth  
!= -1) && (m_width  
< minWidth 
)) m_width  
= minWidth
; 
2804     if ((minHeight 
!= -1) && (m_height 
< minHeight
)) m_height 
= minHeight
; 
2805     if ((maxWidth  
!= -1) && (m_width  
> maxWidth 
)) m_width  
= maxWidth
; 
2806     if ((maxHeight 
!= -1) && (m_height 
> maxHeight
)) m_height 
= maxHeight
; 
2808 #if wxUSE_TOOLBAR_NATIVE 
2809     if (wxDynamicCast(GetParent(), wxToolBar
)) 
2811        // don't take the x,y values, they're wrong because toolbar sets them 
2812        GtkWidget  
*widget 
= GTK_WIDGET(m_widget
); 
2813        gtk_widget_set_size_request (widget
, m_width
, m_height
); 
2817     if (m_parent
->m_wxwindow 
== NULL
) // i.e. wxNotebook 
2819         // don't set the size for children of wxNotebook, just take the values. 
2827         GtkPizza 
*pizza 
= GTK_PIZZA(m_parent
->m_wxwindow
); 
2828         if ((sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
) == 0) 
2830             if (x 
!= -1) m_x 
= x 
+ gtk_pizza_get_xoffset( pizza 
); 
2831             if (y 
!= -1) m_y 
= y 
+ gtk_pizza_get_yoffset( pizza 
); 
2835             m_x 
= x 
+ gtk_pizza_get_xoffset( pizza 
); 
2836             m_y 
= y 
+ gtk_pizza_get_yoffset( pizza 
); 
2839         int left_border 
= 0; 
2840         int right_border 
= 0; 
2842         int bottom_border 
= 0; 
2844         /* the default button has a border around it */ 
2845         if (GTK_WIDGET_CAN_DEFAULT(m_widget
)) 
2847             GtkBorder 
*default_border 
= NULL
; 
2848             gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL 
); 
2851                 left_border 
+= default_border
->left
; 
2852                 right_border 
+= default_border
->right
; 
2853                 top_border 
+= default_border
->top
; 
2854                 bottom_border 
+= default_border
->bottom
; 
2855                 g_free( default_border 
); 
2859         DoMoveWindow( m_x
-top_border
, 
2861                       m_width
+left_border
+right_border
, 
2862                       m_height
+top_border
+bottom_border 
); 
2867         /* Sometimes the client area changes size without the 
2868            whole windows's size changing, but if the whole 
2869            windows's size doesn't change, no wxSizeEvent will 
2870            normally be sent. Here we add an extra test if 
2871            the client test has been changed and this will 
2873         GetClientSize( &m_oldClientWidth
, &m_oldClientHeight 
); 
2877     wxPrintf( "OnSize sent from " ); 
2878     if (GetClassInfo() && GetClassInfo()->GetClassName()) 
2879         wxPrintf( GetClassInfo()->GetClassName() ); 
2880     wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height ); 
2883     if (!m_nativeSizeEvent
) 
2885         wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
2886         event
.SetEventObject( this ); 
2887         GetEventHandler()->ProcessEvent( event 
); 
2893 bool wxWindowGTK::GtkShowFromOnIdle() 
2895     if (IsShown() && m_showOnIdle 
&& !GTK_WIDGET_VISIBLE (m_widget
)) 
2897         GtkAllocation alloc
; 
2900         alloc
.width 
= m_width
; 
2901         alloc
.height 
= m_height
; 
2902         gtk_widget_size_allocate( m_widget
, &alloc 
); 
2903         gtk_widget_show( m_widget 
); 
2904         wxShowEvent 
eventShow(GetId(), true); 
2905         eventShow
.SetEventObject(this); 
2906         GetEventHandler()->ProcessEvent(eventShow
); 
2907         m_showOnIdle 
= false; 
2914 void wxWindowGTK::OnInternalIdle() 
2916     // Check if we have to show window now 
2917     if (GtkShowFromOnIdle()) return; 
2919     if ( m_dirtyTabOrder 
) 
2921         m_dirtyTabOrder 
= false; 
2925     // Update style if the window was not yet realized 
2926     // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called 
2927     if (m_needsStyleChange
) 
2929         SetBackgroundStyle(GetBackgroundStyle()); 
2930         m_needsStyleChange 
= false; 
2933     wxCursor cursor 
= m_cursor
; 
2934     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
2938         /* I now set the cursor anew in every OnInternalIdle call 
2939            as setting the cursor in a parent window also effects the 
2940            windows above so that checking for the current cursor is 
2945             GdkWindow 
*window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
2947                 gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
2949             if (!g_globalCursor
.Ok()) 
2950                 cursor 
= *wxSTANDARD_CURSOR
; 
2952             window 
= m_widget
->window
; 
2953             if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
))) 
2954                 gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
2957         else if ( m_widget 
) 
2959             GdkWindow 
*window 
= m_widget
->window
; 
2960             if ( window 
&& !GTK_WIDGET_NO_WINDOW(m_widget
) ) 
2961                gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
2965     if (wxUpdateUIEvent::CanUpdate(this)) 
2966         UpdateWindowUI(wxUPDATE_UI_FROMIDLE
); 
2969 void wxWindowGTK::DoGetSize( int *width
, int *height 
) const 
2971     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2973     if (width
) (*width
) = m_width
; 
2974     if (height
) (*height
) = m_height
; 
2977 void wxWindowGTK::DoSetClientSize( int width
, int height 
) 
2979     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
2988             GetScrollbarWidth(m_widget
, dw
, dh
); 
2991 #ifndef __WXUNIVERSAL__ 
2992         if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
)) 
2994             // shadow border size is 2 
2998         if (HasFlag(wxSIMPLE_BORDER
)) 
3000             // simple border size is 1 
3004 #endif // __WXUNIVERSAL__ 
3010     SetSize(width
, height
); 
3013 void wxWindowGTK::DoGetClientSize( int *width
, int *height 
) const 
3015     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3027             GetScrollbarWidth(m_widget
, dw
, dh
); 
3030 #ifndef __WXUNIVERSAL__ 
3031         if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
)) 
3033             // shadow border size is 2 
3037         if (HasFlag(wxSIMPLE_BORDER
)) 
3039             // simple border size is 1 
3043 #endif // __WXUNIVERSAL__ 
3053     if (width
) *width 
= w
; 
3054     if (height
) *height 
= h
; 
3057 void wxWindowGTK::DoGetPosition( int *x
, int *y 
) const 
3059     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3063     if (m_parent 
&& m_parent
->m_wxwindow
) 
3065         GtkPizza 
*pizza 
= GTK_PIZZA(m_parent
->m_wxwindow
); 
3066         dx 
= gtk_pizza_get_xoffset( pizza 
); 
3067         dy 
= gtk_pizza_get_yoffset( pizza 
); 
3070     if (x
) (*x
) = m_x 
- dx
; 
3071     if (y
) (*y
) = m_y 
- dy
; 
3074 void wxWindowGTK::DoClientToScreen( int *x
, int *y 
) const 
3076     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3078     if (!m_widget
->window
) return; 
3080     GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
3082         source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3084         source 
= m_widget
->window
; 
3088     gdk_window_get_origin( source
, &org_x
, &org_y 
); 
3092         if (GTK_WIDGET_NO_WINDOW (m_widget
)) 
3094             org_x 
+= m_widget
->allocation
.x
; 
3095             org_y 
+= m_widget
->allocation
.y
; 
3103 void wxWindowGTK::DoScreenToClient( int *x
, int *y 
) const 
3105     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3107     if (!m_widget
->window
) return; 
3109     GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
3111         source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3113         source 
= m_widget
->window
; 
3117     gdk_window_get_origin( source
, &org_x
, &org_y 
); 
3121         if (GTK_WIDGET_NO_WINDOW (m_widget
)) 
3123             org_x 
+= m_widget
->allocation
.x
; 
3124             org_y 
+= m_widget
->allocation
.y
; 
3132 bool wxWindowGTK::Show( bool show 
) 
3134     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3136     if (!wxWindowBase::Show(show
)) 
3146             gtk_widget_show( m_widget 
); 
3147             wxShowEvent 
eventShow(GetId(), show
); 
3148             eventShow
.SetEventObject(this); 
3149             GetEventHandler()->ProcessEvent(eventShow
); 
3154         gtk_widget_hide( m_widget 
); 
3155         wxShowEvent 
eventShow(GetId(), show
); 
3156         eventShow
.SetEventObject(this); 
3157         GetEventHandler()->ProcessEvent(eventShow
); 
3163 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
) 
3165     win
->OnParentEnable(enable
); 
3167     // Recurse, so that children have the opportunity to Do The Right Thing 
3168     // and reset colours that have been messed up by a parent's (really ancestor's) 
3170     for ( wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
3172           node 
= node
->GetNext() ) 
3174         wxWindow 
*child 
= node
->GetData(); 
3175         if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
))) 
3176             wxWindowNotifyEnable(child
, enable
); 
3180 bool wxWindowGTK::Enable( bool enable 
) 
3182     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3184     if (!wxWindowBase::Enable(enable
)) 
3190     gtk_widget_set_sensitive( m_widget
, enable 
); 
3192         gtk_widget_set_sensitive( m_wxwindow
, enable 
); 
3194     wxWindowNotifyEnable(this, enable
); 
3199 int wxWindowGTK::GetCharHeight() const 
3201     wxCHECK_MSG( (m_widget 
!= NULL
), 12, wxT("invalid window") ); 
3203     wxFont font 
= GetFont(); 
3204     wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") ); 
3206     PangoContext 
*context 
= NULL
; 
3208         context 
= gtk_widget_get_pango_context( m_widget 
); 
3213     PangoFontDescription 
*desc 
= font
.GetNativeFontInfo()->description
; 
3214     PangoLayout 
*layout 
= pango_layout_new(context
); 
3215     pango_layout_set_font_description(layout
, desc
); 
3216     pango_layout_set_text(layout
, "H", 1); 
3217     PangoLayoutLine 
*line 
= (PangoLayoutLine 
*)pango_layout_get_lines(layout
)->data
; 
3219     PangoRectangle rect
; 
3220     pango_layout_line_get_extents(line
, NULL
, &rect
); 
3222     g_object_unref (layout
); 
3224     return (int) PANGO_PIXELS(rect
.height
); 
3227 int wxWindowGTK::GetCharWidth() const 
3229     wxCHECK_MSG( (m_widget 
!= NULL
), 8, wxT("invalid window") ); 
3231     wxFont font 
= GetFont(); 
3232     wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") ); 
3234     PangoContext 
*context 
= NULL
; 
3236         context 
= gtk_widget_get_pango_context( m_widget 
); 
3241     PangoFontDescription 
*desc 
= font
.GetNativeFontInfo()->description
; 
3242     PangoLayout 
*layout 
= pango_layout_new(context
); 
3243     pango_layout_set_font_description(layout
, desc
); 
3244     pango_layout_set_text(layout
, "g", 1); 
3245     PangoLayoutLine 
*line 
= (PangoLayoutLine 
*)pango_layout_get_lines(layout
)->data
; 
3247     PangoRectangle rect
; 
3248     pango_layout_line_get_extents(line
, NULL
, &rect
); 
3250     g_object_unref (layout
); 
3252     return (int) PANGO_PIXELS(rect
.width
); 
3255 void wxWindowGTK::GetTextExtent( const wxString
& string
, 
3259                                  int *externalLeading
, 
3260                                  const wxFont 
*theFont 
) const 
3262     wxFont fontToUse 
= theFont 
? *theFont 
: GetFont(); 
3264     wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") ); 
3273     PangoContext 
*context 
= NULL
; 
3275         context 
= gtk_widget_get_pango_context( m_widget 
); 
3284     PangoFontDescription 
*desc 
= fontToUse
.GetNativeFontInfo()->description
; 
3285     PangoLayout 
*layout 
= pango_layout_new(context
); 
3286     pango_layout_set_font_description(layout
, desc
); 
3288         const wxCharBuffer data 
= wxGTK_CONV( string 
); 
3290             pango_layout_set_text(layout
, data
, strlen(data
)); 
3293     PangoRectangle rect
; 
3294     pango_layout_get_extents(layout
, NULL
, &rect
); 
3296     if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
); 
3297     if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
); 
3300         PangoLayoutIter 
*iter 
= pango_layout_get_iter(layout
); 
3301         int baseline 
= pango_layout_iter_get_baseline(iter
); 
3302         pango_layout_iter_free(iter
); 
3303         *descent 
= *y 
- PANGO_PIXELS(baseline
); 
3305     if (externalLeading
) (*externalLeading
) = 0;  // ?? 
3307     g_object_unref (layout
); 
3310 bool wxWindowGTK::GTKSetDelayedFocusIfNeeded() 
3312     if ( g_delayedFocus 
== this ) 
3314         if ( GTK_WIDGET_REALIZED(m_widget
) ) 
3316             gtk_widget_grab_focus(m_widget
); 
3317             g_delayedFocus 
= NULL
; 
3326 void wxWindowGTK::SetFocus() 
3328     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3331         // don't do anything if we already have focus 
3337         if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
)) 
3339             gtk_widget_grab_focus (m_wxwindow
); 
3344         if (GTK_IS_CONTAINER(m_widget
)) 
3346             gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD 
); 
3349         if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) ) 
3352             if (!GTK_WIDGET_REALIZED(m_widget
)) 
3354                 // we can't set the focus to the widget now so we remember that 
3355                 // it should be focused and will do it later, during the idle 
3356                 // time, as soon as we can 
3357                 wxLogTrace(TRACE_FOCUS
, 
3358                            _T("Delaying setting focus to %s(%s)"), 
3359                            GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3361                 g_delayedFocus 
= this; 
3365                 wxLogTrace(TRACE_FOCUS
, 
3366                            _T("Setting focus to %s(%s)"), 
3367                            GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3369                 gtk_widget_grab_focus (m_widget
); 
3374            wxLogTrace(TRACE_FOCUS
, 
3375                       _T("Can't set focus to %s(%s)"), 
3376                       GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3381 bool wxWindowGTK::AcceptsFocus() const 
3383     return m_acceptsFocus 
&& wxWindowBase::AcceptsFocus(); 
3386 bool wxWindowGTK::Reparent( wxWindowBase 
*newParentBase 
) 
3388     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3390     wxWindowGTK 
*oldParent 
= m_parent
, 
3391              *newParent 
= (wxWindowGTK 
*)newParentBase
; 
3393     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3395     if ( !wxWindowBase::Reparent(newParent
) ) 
3398     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3400     /* prevent GTK from deleting the widget arbitrarily */ 
3401     gtk_widget_ref( m_widget 
); 
3405         gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget 
); 
3408     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3412         if (GTK_WIDGET_VISIBLE (newParent
->m_widget
)) 
3414             m_showOnIdle 
= true; 
3415             gtk_widget_hide( m_widget 
); 
3418         /* insert GTK representation */ 
3419         (*(newParent
->m_insertCallback
))(newParent
, this); 
3422     /* reverse: prevent GTK from deleting the widget arbitrarily */ 
3423     gtk_widget_unref( m_widget 
); 
3425     SetLayoutDirection(wxLayout_Default
); 
3430 void wxWindowGTK::DoAddChild(wxWindowGTK 
*child
) 
3432     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
3434     wxASSERT_MSG( (child 
!= NULL
), wxT("invalid child window") ); 
3436     wxASSERT_MSG( (m_insertCallback 
!= NULL
), wxT("invalid child insertion function") ); 
3441     /* insert GTK representation */ 
3442     (*m_insertCallback
)(this, child
); 
3445 void wxWindowGTK::AddChild(wxWindowBase 
*child
) 
3447     wxWindowBase::AddChild(child
); 
3448     m_dirtyTabOrder 
= true; 
3450         wxapp_install_idle_handler(); 
3453 void wxWindowGTK::RemoveChild(wxWindowBase 
*child
) 
3455     wxWindowBase::RemoveChild(child
); 
3456     m_dirtyTabOrder 
= true; 
3458         wxapp_install_idle_handler(); 
3462 wxLayoutDirection 
wxWindowGTK::GTKGetLayout(GtkWidget 
*widget
) 
3464     return gtk_widget_get_direction(GTK_WIDGET(widget
)) == GTK_TEXT_DIR_RTL
 
3465                 ? wxLayout_RightToLeft
 
3466                 : wxLayout_LeftToRight
; 
3470 void wxWindowGTK::GTKSetLayout(GtkWidget 
*widget
, wxLayoutDirection dir
) 
3472     wxASSERT_MSG( dir 
!= wxLayout_Default
, _T("invalid layout direction") ); 
3474     gtk_widget_set_direction(GTK_WIDGET(widget
), 
3475                              dir 
== wxLayout_RightToLeft 
? GTK_TEXT_DIR_RTL
 
3476                                                          : GTK_TEXT_DIR_LTR
); 
3479 wxLayoutDirection 
wxWindowGTK::GetLayoutDirection() const 
3481     return GTKGetLayout(m_widget
); 
3484 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
) 
3486     if ( dir 
== wxLayout_Default 
) 
3488         const wxWindow 
*const parent 
= GetParent(); 
3491             // inherit layout from parent. 
3492             dir 
= parent
->GetLayoutDirection(); 
3494         else // no parent, use global default layout 
3496             dir 
= wxTheApp
->GetLayoutDirection(); 
3500     if ( dir 
== wxLayout_Default 
) 
3503     GTKSetLayout(m_widget
, dir
); 
3506         GTKSetLayout(m_wxwindow
, dir
); 
3510 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
, 
3511                                       wxCoord 
WXUNUSED(width
), 
3512                                       wxCoord 
WXUNUSED(widthTotal
)) const 
3514     // We now mirrors the coordinates of RTL windows in GtkPizza 
3518 void wxWindowGTK::DoMoveInTabOrder(wxWindow 
*win
, MoveKind move
) 
3520     wxWindowBase::DoMoveInTabOrder(win
, move
); 
3521     m_dirtyTabOrder 
= true; 
3523         wxapp_install_idle_handler(); 
3526 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const 
3528     // none needed by default 
3532 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
)) 
3534     // nothing to do by default since none is needed 
3537 void wxWindowGTK::RealizeTabOrder() 
3541         if ( !m_children
.empty() ) 
3543             // we don't only construct the correct focus chain but also use 
3544             // this opportunity to update the mnemonic widgets for the widgets 
3547             GList 
*chain 
= NULL
; 
3548             wxWindowGTK
* mnemonicWindow 
= NULL
; 
3550             for ( wxWindowList::const_iterator i 
= m_children
.begin(); 
3551                   i 
!= m_children
.end(); 
3554                 wxWindowGTK 
*win 
= *i
; 
3556                 if ( mnemonicWindow 
) 
3558                     if ( win
->AcceptsFocusFromKeyboard() ) 
3560                         // wxComboBox et al. needs to focus on on a different 
3561                         // widget than m_widget, so if the main widget isn't 
3562                         // focusable try the connect widget 
3563                         GtkWidget
* w 
= win
->m_widget
; 
3564                         if ( !GTK_WIDGET_CAN_FOCUS(w
) ) 
3566                             w 
= win
->GetConnectWidget(); 
3567                             if ( !GTK_WIDGET_CAN_FOCUS(w
) ) 
3573                             mnemonicWindow
->GTKWidgetDoSetMnemonic(w
); 
3574                             mnemonicWindow 
= NULL
; 
3578                 else if ( win
->GTKWidgetNeedsMnemonic() ) 
3580                     mnemonicWindow 
= win
; 
3583                 chain 
= g_list_prepend(chain
, win
->m_widget
); 
3586             chain 
= g_list_reverse(chain
); 
3588             gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
); 
3593             gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
)); 
3598 void wxWindowGTK::Raise() 
3600     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3602     if (m_wxwindow 
&& m_wxwindow
->window
) 
3604         gdk_window_raise( m_wxwindow
->window 
); 
3606     else if (m_widget
->window
) 
3608         gdk_window_raise( m_widget
->window 
); 
3612 void wxWindowGTK::Lower() 
3614     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3616     if (m_wxwindow 
&& m_wxwindow
->window
) 
3618         gdk_window_lower( m_wxwindow
->window 
); 
3620     else if (m_widget
->window
) 
3622         gdk_window_lower( m_widget
->window 
); 
3626 bool wxWindowGTK::SetCursor( const wxCursor 
&cursor 
) 
3628     if ( !wxWindowBase::SetCursor(cursor
.Ok() ? cursor 
: *wxSTANDARD_CURSOR
) ) 
3636 void wxWindowGTK::GTKUpdateCursor() 
3638     wxCursor 
cursor(g_globalCursor
.Ok() ? g_globalCursor 
: GetCursor()); 
3641         wxArrayGdkWindows windowsThis
; 
3642         GdkWindow 
* const winThis 
= GTKGetWindow(windowsThis
); 
3645             gdk_window_set_cursor(winThis
, cursor
.GetCursor()); 
3649             const size_t count 
= windowsThis
.size(); 
3650             for ( size_t n 
= 0; n 
< count
; n
++ ) 
3652                 GdkWindow 
*win 
= windowsThis
[n
]; 
3655                     wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?")); 
3659                 gdk_window_set_cursor(win
, cursor
.GetCursor()); 
3665 void wxWindowGTK::WarpPointer( int x
, int y 
) 
3667     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3669     // We provide this function ourselves as it is 
3670     // missing in GDK (top of this file). 
3672     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
3674         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3676         window 
= GetConnectWidget()->window
; 
3679         gdk_window_warp_pointer( window
, x
, y 
); 
3682 wxWindowGTK::ScrollDir 
wxWindowGTK::ScrollDirFromRange(GtkRange 
*range
) const 
3684     // find the scrollbar which generated the event 
3685     for ( int dir 
= 0; dir 
< ScrollDir_Max
; dir
++ ) 
3687         if ( range 
== m_scrollBar
[dir
] ) 
3688             return (ScrollDir
)dir
; 
3691     wxFAIL_MSG( _T("event from unknown scrollbar received") ); 
3693     return ScrollDir_Max
; 
3696 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
) 
3698     bool changed 
= false; 
3699     GtkRange
* range 
= m_scrollBar
[dir
]; 
3700     if ( range 
&& units 
) 
3702         GtkAdjustment
* adj 
= range
->adjustment
; 
3703         gdouble inc 
= unit 
== ScrollUnit_Line 
? adj
->step_increment
 
3704                                               : adj
->page_increment
; 
3706         const int posOld 
= int(adj
->value 
+ 0.5); 
3707         gtk_range_set_value(range
, posOld 
+ units
*inc
); 
3709         changed 
= int(adj
->value 
+ 0.5) != posOld
; 
3715 bool wxWindowGTK::ScrollLines(int lines
) 
3717     return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
); 
3720 bool wxWindowGTK::ScrollPages(int pages
) 
3722     return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
); 
3725 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect 
*rect 
) 
3729     if (!m_widget
->window
) 
3734         if (!GTK_PIZZA(m_wxwindow
)->bin_window
) return; 
3736         GdkRectangle gdk_rect
, 
3740             gdk_rect
.x 
= rect
->x
; 
3741             gdk_rect
.y 
= rect
->y
; 
3742             gdk_rect
.width 
= rect
->width
; 
3743             gdk_rect
.height 
= rect
->height
; 
3746         else // invalidate everything 
3753         gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE 
); 
3757 void wxWindowGTK::Update() 
3761     // when we call Update() we really want to update the window immediately on 
3762     // screen, even if it means flushing the entire queue and hence slowing down 
3763     // everything -- but it should still be done, it's just that Update() should 
3764     // be called very rarely 
3768 void wxWindowGTK::GtkUpdate() 
3770     if (m_wxwindow 
&& GTK_PIZZA(m_wxwindow
)->bin_window
) 
3771         gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE 
); 
3772     if (m_widget 
&& m_widget
->window
) 
3773         gdk_window_process_updates( m_widget
->window
, FALSE 
); 
3775     // for consistency with other platforms (and also because it's convenient 
3776     // to be able to update an entire TLW by calling Update() only once), we 
3777     // should also update all our children here 
3778     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
3780           node 
= node
->GetNext() ) 
3782         node
->GetData()->GtkUpdate(); 
3786 bool wxWindowGTK::IsExposed( int x
, int y 
) const 
3788     return m_updateRegion
.Contains(x
, y
) != wxOutRegion
; 
3792 bool wxWindowGTK::IsExposed( int x
, int y
, int w
, int h 
) const 
3794     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3795         return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
; 
3797         return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
; 
3800 void wxWindowGTK::GtkSendPaintEvents() 
3804         m_updateRegion
.Clear(); 
3808     // Clip to paint region in wxClientDC 
3809     m_clipPaintRegion 
= true; 
3811     wxRegion maybe_rtl_region 
= m_updateRegion
; 
3814     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3816         maybe_rtl_region
.Clear(); 
3819         gdk_window_get_geometry( GTK_PIZZA(m_wxwindow
)->bin_window
, 
3820                                  NULL
, NULL
, &width
, NULL
, NULL 
); 
3822         wxRegionIterator 
upd( m_updateRegion 
); 
3826             rect
.x 
= upd
.GetX(); 
3827             rect
.y 
= upd
.GetY(); 
3828             rect
.width 
= upd
.GetWidth(); 
3829             rect
.height 
= upd
.GetHeight(); 
3831             rect
.x 
= width 
- rect
.x 
- rect
.width
; 
3832             maybe_rtl_region
.Union( rect 
); 
3839     // widget to draw on 
3840     GtkPizza 
*pizza 
= GTK_PIZZA (m_wxwindow
); 
3842     if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)) 
3844         // find ancestor from which to steal background 
3845         wxWindow 
*parent 
= wxGetTopLevelParent((wxWindow 
*)this); 
3847             parent 
= (wxWindow
*)this; 
3849         if (GTK_WIDGET_MAPPED(parent
->m_widget
)) 
3851             wxRegionIterator 
upd( m_updateRegion 
); 
3855                 rect
.x 
= upd
.GetX(); 
3856                 rect
.y 
= upd
.GetY(); 
3857                 rect
.width 
= upd
.GetWidth(); 
3858                 rect
.height 
= upd
.GetHeight(); 
3860                 gtk_paint_flat_box( parent
->m_widget
->style
, 
3862                             (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
), 
3875         m_updateRegion 
= maybe_rtl_region
; 
3877         wxWindowDC 
dc( (wxWindow
*)this ); 
3878         dc
.SetClippingRegion( m_updateRegion 
); 
3880         wxEraseEvent 
erase_event( GetId(), &dc 
); 
3881         erase_event
.SetEventObject( this ); 
3883         GetEventHandler()->ProcessEvent(erase_event
); 
3886     m_updateRegion 
= maybe_rtl_region
; 
3888     wxNcPaintEvent 
nc_paint_event( GetId() ); 
3889     nc_paint_event
.SetEventObject( this ); 
3890     GetEventHandler()->ProcessEvent( nc_paint_event 
); 
3892     wxPaintEvent 
paint_event( GetId() ); 
3893     paint_event
.SetEventObject( this ); 
3894     GetEventHandler()->ProcessEvent( paint_event 
); 
3896     m_clipPaintRegion 
= false; 
3898     m_updateRegion
.Clear(); 
3901 void wxWindowGTK::SetDoubleBuffered( bool on 
) 
3903     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3906         gtk_widget_set_double_buffered( m_wxwindow
, on 
); 
3909 void wxWindowGTK::ClearBackground() 
3911     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3915 void wxWindowGTK::DoSetToolTip( wxToolTip 
*tip 
) 
3917     wxWindowBase::DoSetToolTip(tip
); 
3920         m_tooltip
->Apply( (wxWindow 
*)this ); 
3923 void wxWindowGTK::ApplyToolTip( GtkTooltips 
*tips
, const wxChar 
*tip 
) 
3925     wxString 
tmp( tip 
); 
3926     gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL 
); 
3928 #endif // wxUSE_TOOLTIPS 
3930 bool wxWindowGTK::SetBackgroundColour( const wxColour 
&colour 
) 
3932     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3934     if (!wxWindowBase::SetBackgroundColour(colour
)) 
3939         // We need the pixel value e.g. for background clearing. 
3940         m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
)); 
3943     // apply style change (forceStyle=true so that new style is applied 
3944     // even if the bg colour changed from valid to wxNullColour) 
3945     if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
) 
3946         ApplyWidgetStyle(true); 
3951 bool wxWindowGTK::SetForegroundColour( const wxColour 
&colour 
) 
3953     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3955     if (!wxWindowBase::SetForegroundColour(colour
)) 
3962         // We need the pixel value e.g. for background clearing. 
3963         m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
)); 
3966     // apply style change (forceStyle=true so that new style is applied 
3967     // even if the bg colour changed from valid to wxNullColour): 
3968     ApplyWidgetStyle(true); 
3973 PangoContext 
*wxWindowGTK::GtkGetPangoDefaultContext() 
3975     return gtk_widget_get_pango_context( m_widget 
); 
3978 GtkRcStyle 
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
) 
3980     // do we need to apply any changes at all? 
3983          !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() ) 
3988     GtkRcStyle 
*style 
= gtk_rc_style_new(); 
3993             pango_font_description_copy( m_font
.GetNativeFontInfo()->description 
); 
3996     if ( m_foregroundColour
.Ok() ) 
3998         const GdkColor 
*fg 
= m_foregroundColour
.GetColor(); 
4000         style
->fg
[GTK_STATE_NORMAL
] = *fg
; 
4001         style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
; 
4003         style
->fg
[GTK_STATE_PRELIGHT
] = *fg
; 
4004         style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
; 
4006         style
->fg
[GTK_STATE_ACTIVE
] = *fg
; 
4007         style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
; 
4010     if ( m_backgroundColour
.Ok() ) 
4012         const GdkColor 
*bg 
= m_backgroundColour
.GetColor(); 
4014         style
->bg
[GTK_STATE_NORMAL
] = *bg
; 
4015         style
->base
[GTK_STATE_NORMAL
] = *bg
; 
4016         style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
) 
4017             (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG 
| GTK_RC_BASE
); 
4019         style
->bg
[GTK_STATE_PRELIGHT
] = *bg
; 
4020         style
->base
[GTK_STATE_PRELIGHT
] = *bg
; 
4021         style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
) 
4022             (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG 
| GTK_RC_BASE
); 
4024         style
->bg
[GTK_STATE_ACTIVE
] = *bg
; 
4025         style
->base
[GTK_STATE_ACTIVE
] = *bg
; 
4026         style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
) 
4027             (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG 
| GTK_RC_BASE
); 
4029         style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
; 
4030         style
->base
[GTK_STATE_INSENSITIVE
] = *bg
; 
4031         style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
) 
4032             (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG 
| GTK_RC_BASE
); 
4038 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
) 
4040     GtkRcStyle 
*style 
= CreateWidgetStyle(forceStyle
); 
4043         DoApplyWidgetStyle(style
); 
4044         gtk_rc_style_unref(style
); 
4047     // Style change may affect GTK+'s size calculation: 
4048     InvalidateBestSize(); 
4051 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
4054         gtk_widget_modify_style(m_wxwindow
, style
); 
4056         gtk_widget_modify_style(m_widget
, style
); 
4059 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
) 
4061     wxWindowBase::SetBackgroundStyle(style
); 
4063     if (style 
== wxBG_STYLE_CUSTOM
) 
4065         GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4067             window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4069             window 
= GetConnectWidget()->window
; 
4073             // Make sure GDK/X11 doesn't refresh the window 
4075             gdk_window_set_back_pixmap( window
, None
, False 
); 
4077             Display
* display 
= GDK_WINDOW_DISPLAY(window
); 
4080             m_needsStyleChange 
= false; 
4083             // Do in OnIdle, because the window is not yet available 
4084             m_needsStyleChange 
= true; 
4086         // Don't apply widget style, or we get a grey background 
4090         // apply style change (forceStyle=true so that new style is applied 
4091         // even if the bg colour changed from valid to wxNullColour): 
4092         ApplyWidgetStyle(true); 
4097 #if wxUSE_DRAG_AND_DROP 
4099 void wxWindowGTK::SetDropTarget( wxDropTarget 
*dropTarget 
) 
4101     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4103     GtkWidget 
*dnd_widget 
= GetConnectWidget(); 
4105     if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget 
); 
4107     if (m_dropTarget
) delete m_dropTarget
; 
4108     m_dropTarget 
= dropTarget
; 
4110     if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget 
); 
4113 #endif // wxUSE_DRAG_AND_DROP 
4115 GtkWidget
* wxWindowGTK::GetConnectWidget() 
4117     GtkWidget 
*connect_widget 
= m_widget
; 
4118     if (m_wxwindow
) connect_widget 
= m_wxwindow
; 
4120     return connect_widget
; 
4123 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow 
*window
) const 
4125     wxArrayGdkWindows windowsThis
; 
4126     GdkWindow 
* const winThis 
= GTKGetWindow(windowsThis
); 
4128     return winThis 
? window 
== winThis
 
4129                    : windowsThis
.Index(window
) != wxNOT_FOUND
; 
4132 GdkWindow 
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const 
4134     return m_wxwindow 
? GTK_PIZZA(m_wxwindow
)->bin_window 
: m_widget
->window
; 
4137 bool wxWindowGTK::SetFont( const wxFont 
&font 
) 
4139     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
4141     if (!wxWindowBase::SetFont(font
)) 
4144     // apply style change (forceStyle=true so that new style is applied 
4145     // even if the font changed from valid to wxNullFont): 
4146     ApplyWidgetStyle(true); 
4151 void wxWindowGTK::DoCaptureMouse() 
4153     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4155     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4157         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4159         window 
= GetConnectWidget()->window
; 
4161     wxCHECK_RET( window
, _T("CaptureMouse() failed") ); 
4163     const wxCursor
* cursor 
= &m_cursor
; 
4165         cursor 
= wxSTANDARD_CURSOR
; 
4167     gdk_pointer_grab( window
, FALSE
, 
4169                          (GDK_BUTTON_PRESS_MASK 
| 
4170                           GDK_BUTTON_RELEASE_MASK 
| 
4171                           GDK_POINTER_MOTION_HINT_MASK 
| 
4172                           GDK_POINTER_MOTION_MASK
), 
4174                       cursor
->GetCursor(), 
4175                       (guint32
)GDK_CURRENT_TIME 
); 
4176     g_captureWindow 
= this; 
4177     g_captureWindowHasMouse 
= true; 
4180 void wxWindowGTK::DoReleaseMouse() 
4182     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4184     wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") ); 
4186     g_captureWindow 
= (wxWindowGTK
*) NULL
; 
4188     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4190         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4192         window 
= GetConnectWidget()->window
; 
4197     gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME 
); 
4201 wxWindow 
*wxWindowBase::GetCapture() 
4203     return (wxWindow 
*)g_captureWindow
; 
4206 bool wxWindowGTK::IsRetained() const 
4211 void wxWindowGTK::BlockScrollEvent() 
4213     wxASSERT(!m_blockScrollEvent
); 
4214     m_blockScrollEvent 
= true; 
4217 void wxWindowGTK::UnblockScrollEvent() 
4219     wxASSERT(m_blockScrollEvent
); 
4220     m_blockScrollEvent 
= false; 
4223 void wxWindowGTK::SetScrollbar(int orient
, 
4227                                bool WXUNUSED(update
)) 
4229     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4230     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4234         m_hasScrolling 
= true; 
4238         // GtkRange requires upper > lower 
4243     if (pos 
> range 
- thumbVisible
) 
4244         pos 
= range 
- thumbVisible
; 
4247     GtkAdjustment
* adj 
= m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
; 
4248     adj
->step_increment 
= 1; 
4249     adj
->page_increment 
= 
4250     adj
->page_size 
= thumbVisible
; 
4252     SetScrollPos(orient
, pos
); 
4253     gtk_adjustment_changed(adj
); 
4256 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
)) 
4258     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4259     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4261     // This check is more than an optimization. Without it, the slider 
4262     //   will not move smoothly while tracking when using wxScrollHelper. 
4263     if (GetScrollPos(orient
) != pos
) 
4265         const int dir 
= ScrollDirFromOrient(orient
); 
4266         GtkAdjustment
* adj 
= m_scrollBar
[dir
]->adjustment
; 
4267         const int max 
= int(adj
->upper 
- adj
->page_size
); 
4274         // If a "value_changed" signal emission is not already in progress 
4275         if (!m_blockValueChanged
[dir
]) 
4277             gtk_adjustment_value_changed(adj
); 
4282 int wxWindowGTK::GetScrollThumb(int orient
) const 
4284     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4285     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4287     return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->page_size
); 
4290 int wxWindowGTK::GetScrollPos( int orient 
) const 
4292     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4293     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4295     return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->value 
+ 0.5); 
4298 int wxWindowGTK::GetScrollRange( int orient 
) const 
4300     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4301     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4303     return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->upper
); 
4306 // Determine if increment is the same as +/-x, allowing for some small 
4307 //   difference due to possible inexactness in floating point arithmetic 
4308 static inline bool IsScrollIncrement(double increment
, double x
) 
4310     wxASSERT(increment 
> 0); 
4311     const double tolerance 
= 1.0 / 1024; 
4312     return fabs(increment 
- fabs(x
)) < tolerance
; 
4315 wxEventType 
wxWindowGTK::GetScrollEventType(GtkRange
* range
) 
4320         wxapp_install_idle_handler(); 
4322     wxASSERT(range 
== m_scrollBar
[0] || range 
== m_scrollBar
[1]); 
4324     const int barIndex 
= range 
== m_scrollBar
[1]; 
4325     GtkAdjustment
* adj 
= range
->adjustment
; 
4326     const int value 
= int(adj
->value 
+ 0.5); 
4327     // save previous position 
4328     const double oldPos 
= m_scrollPos
[barIndex
]; 
4329     // update current position 
4330     m_scrollPos
[barIndex
] = adj
->value
; 
4331     // If event should be ignored, or integral position has not changed 
4332     if (!m_hasVMT 
|| g_blockEventsOnDrag 
|| value 
== int(oldPos 
+ 0.5)) 
4337     wxEventType eventType 
= wxEVT_SCROLL_THUMBTRACK
; 
4340         // Difference from last change event 
4341         const double diff 
= adj
->value 
- oldPos
; 
4342         const bool isDown 
= diff 
> 0; 
4344         if (IsScrollIncrement(adj
->step_increment
, diff
)) 
4346             eventType 
= isDown 
? wxEVT_SCROLL_LINEDOWN 
: wxEVT_SCROLL_LINEUP
; 
4348         else if (IsScrollIncrement(adj
->page_increment
, diff
)) 
4350             eventType 
= isDown 
? wxEVT_SCROLL_PAGEDOWN 
: wxEVT_SCROLL_PAGEUP
; 
4352         else if (m_mouseButtonDown
) 
4354             // Assume track event 
4355             m_isScrolling 
= true; 
4361 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) ) 
4363     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4365     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4367     // No scrolling requested. 
4368     if ((dx 
== 0) && (dy 
== 0)) return; 
4370     m_clipPaintRegion 
= true; 
4372     gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy 
); 
4374     m_clipPaintRegion 
= false; 
4377 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
) 
4379     //RN: Note that static controls usually have no border on gtk, so maybe 
4380     //it makes sense to treat that as simply no border at the wx level 
4382     if (!(wxstyle 
& wxNO_BORDER
) && !(wxstyle 
& wxBORDER_STATIC
)) 
4384         GtkShadowType gtkstyle
; 
4386         if(wxstyle 
& wxBORDER_RAISED
) 
4387             gtkstyle 
= GTK_SHADOW_OUT
; 
4388         else if (wxstyle 
& wxBORDER_SUNKEN
) 
4389             gtkstyle 
= GTK_SHADOW_IN
; 
4390         else if (wxstyle 
& wxBORDER_DOUBLE
) 
4391             gtkstyle 
= GTK_SHADOW_ETCHED_IN
; 
4393             gtkstyle 
= GTK_SHADOW_IN
; 
4395         gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
), 
4400 void wxWindowGTK::SetWindowStyleFlag( long style 
) 
4402     // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already 
4403     wxWindowBase::SetWindowStyleFlag(style
); 
4406 // Find the wxWindow at the current mouse position, also returning the mouse 
4408 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
) 
4410     pt 
= wxGetMousePosition(); 
4411     wxWindow
* found 
= wxFindWindowAtPoint(pt
); 
4415 // Get the current mouse position. 
4416 wxPoint 
wxGetMousePosition() 
4418   /* This crashes when used within wxHelpContext, 
4419      so we have to use the X-specific implementation below. 
4421     GdkModifierType *mask; 
4422     (void) gdk_window_get_pointer(NULL, &x, &y, mask); 
4424     return wxPoint(x, y); 
4428     GdkWindow
* windowAtPtr 
= gdk_window_at_pointer(& x
, & y
); 
4430     Display 
*display 
= windowAtPtr 
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY(); 
4431     Window rootWindow 
= RootWindowOfScreen (DefaultScreenOfDisplay(display
)); 
4432     Window rootReturn
, childReturn
; 
4433     int rootX
, rootY
, winX
, winY
; 
4434     unsigned int maskReturn
; 
4436     XQueryPointer (display
, 
4440                    &rootX
, &rootY
, &winX
, &winY
, &maskReturn
); 
4441     return wxPoint(rootX
, rootY
); 
4445 // Needed for implementing e.g. combobox on wxGTK within a modal dialog. 
4446 void wxAddGrab(wxWindow
* window
) 
4448     gtk_grab_add( (GtkWidget
*) window
->GetHandle() ); 
4451 void wxRemoveGrab(wxWindow
* window
) 
4453     gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );