1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        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" 
  18 #include "wx/dcclient.h" 
  21 #include "wx/layout.h" 
  23 #include "wx/dialog.h" 
  24 #include "wx/msgdlg.h" 
  25 #include "wx/module.h" 
  26 #include "wx/combobox.h" 
  27 #if wxUSE_TOOLBAR_NATIVE 
  28 #include "wx/toolbar.h" 
  31 #if wxUSE_DRAG_AND_DROP 
  36     #include "wx/tooltip.h" 
  44     #include "wx/textctrl.h" 
  48 #include "wx/statusbr.h" 
  50 #include "wx/settings.h" 
  52 #include "wx/fontutil.h" 
  53 #include "wx/stattext.h" 
  56     #include "wx/thread.h" 
  62 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0 
  63 #include <gtk/gtkversion.h> 
  64 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0) 
  65 #undef GTK_DISABLE_DEPRECATED 
  68 #include "wx/gtk/private.h" 
  69 #include <gdk/gdkprivate.h> 
  70 #include <gdk/gdkkeysyms.h> 
  74 #include <gtk/gtkprivate.h> 
  76 #include "wx/gtk/win_gtk.h" 
  78 #include <pango/pangox.h> 
  84 extern GtkContainerClass 
*pizza_parent_class
; 
  86 //----------------------------------------------------------------------------- 
  87 // documentation on internals 
  88 //----------------------------------------------------------------------------- 
  91    I have been asked several times about writing some documentation about 
  92    the GTK port of wxWidgets, especially its internal structures. Obviously, 
  93    you cannot understand wxGTK without knowing a little about the GTK, but 
  94    some more information about what the wxWindow, which is the base class 
  95    for all other window classes, does seems required as well. 
  99    What does wxWindow do? It contains the common interface for the following 
 100    jobs of its descendants: 
 102    1) Define the rudimentary behaviour common to all window classes, such as 
 103    resizing, intercepting user input (so as to make it possible to use these 
 104    events for special purposes in a derived class), window names etc. 
 106    2) Provide the possibility to contain and manage children, if the derived 
 107    class is allowed to contain children, which holds true for those window 
 108    classes which do not display a native GTK widget. To name them, these 
 109    classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame- 
 110    work classes are a special case and are handled a bit differently from 
 111    the rest. The same holds true for the wxNotebook class. 
 113    3) Provide the possibility to draw into a client area of a window. This, 
 114    too, only holds true for classes that do not display a native GTK widget 
 117    4) Provide the entire mechanism for scrolling widgets. This actual inter- 
 118    face for this is usually in wxScrolledWindow, but the GTK implementation 
 121    5) A multitude of helper or extra methods for special purposes, such as 
 122    Drag'n'Drop, managing validators etc. 
 124    6) Display a border (sunken, raised, simple or none). 
 126    Normally one might expect, that one wxWidgets window would always correspond 
 127    to one GTK widget. Under GTK, there is no such allround widget that has all 
 128    the functionality. Moreover, the GTK defines a client area as a different 
 129    widget from the actual widget you are handling. Last but not least some 
 130    special classes (e.g. wxFrame) handle different categories of widgets and 
 131    still have the possibility to draw something in the client area. 
 132    It was therefore required to write a special purpose GTK widget, that would 
 133    represent a client area in the sense of wxWidgets capable to do the jobs 
 134    2), 3) and 4). I have written this class and it resides in win_gtk.c of 
 137    All windows must have a widget, with which they interact with other under- 
 138    lying GTK widgets. It is this widget, e.g. that has to be resized etc and 
 139    the wxWindow class has a member variable called m_widget which holds a 
 140    pointer to this widget. When the window class represents a GTK native widget, 
 141    this is (in most cases) the only GTK widget the class manages. E.g. the 
 142    wxStaticText class handles only a GtkLabel widget a pointer to which you 
 143    can find in m_widget (defined in wxWindow) 
 145    When the class has a client area for drawing into and for containing children 
 146    it has to handle the client area widget (of the type GtkPizza, defined in 
 147    win_gtk.c), but there could be any number of widgets, handled by a class 
 148    The common rule for all windows is only, that the widget that interacts with 
 149    the rest of GTK must be referenced in m_widget and all other widgets must be 
 150    children of this widget on the GTK level. The top-most widget, which also 
 151    represents the client area, must be in the m_wxwindow field and must be of 
 154    As I said, the window classes that display a GTK native widget only have 
 155    one widget, so in the case of e.g. the wxButton class m_widget holds a 
 156    pointer to a GtkButton widget. But windows with client areas (for drawing 
 157    and children) have a m_widget field that is a pointer to a GtkScrolled- 
 158    Window and a m_wxwindow field that is pointer to a GtkPizza and this 
 159    one is (in the GTK sense) a child of the GtkScrolledWindow. 
 161    If the m_wxwindow field is set, then all input to this widget is inter- 
 162    cepted and sent to the wxWidgets class. If not, all input to the widget 
 163    that gets pointed to by m_widget gets intercepted and sent to the class. 
 167    The design of scrolling in wxWidgets is markedly different from that offered 
 168    by the GTK itself and therefore we cannot simply take it as it is. In GTK, 
 169    clicking on a scrollbar belonging to scrolled window will inevitably move 
 170    the window. In wxWidgets, the scrollbar will only emit an event, send this 
 171    to (normally) a wxScrolledWindow and that class will call ScrollWindow() 
 172    which actually moves the window and its subchildren. Note that GtkPizza 
 173    memorizes how much it has been scrolled but that wxWidgets forgets this 
 174    so that the two coordinates systems have to be kept in synch. This is done 
 175    in various places using the pizza->xoffset and pizza->yoffset values. 
 179    Singularily the most broken code in GTK is the code that is supposed to 
 180    inform subwindows (child windows) about new positions. Very often, duplicate 
 181    events are sent without changes in size or position, equally often no 
 182    events are sent at all (All this is due to a bug in the GtkContainer code 
 183    which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores 
 184    GTK's own system and it simply waits for size events for toplevel windows 
 185    and then iterates down the respective size events to all window. This has 
 186    the disadvantage that windows might get size events before the GTK widget 
 187    actually has the reported size. This doesn't normally pose any problem, but 
 188    the OpenGL drawing routines rely on correct behaviour. Therefore, I have 
 189    added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas, 
 190    i.e. the wxGLCanvas will emit a size event, when (and not before) the X11 
 191    window that is used for OpenGL output really has that size (as reported by 
 196    If someone at some point of time feels the immense desire to have a look at, 
 197    change or attempt to optimise the Refresh() logic, this person will need an 
 198    intimate understanding of what "draw" and "expose" events are and what 
 199    they are used for, in particular when used in connection with GTK's 
 200    own windowless widgets. Beware. 
 204    Cursors, too, have been a constant source of pleasure. The main difficulty 
 205    is that a GdkWindow inherits a cursor if the programmer sets a new cursor 
 206    for the parent. To prevent this from doing too much harm, I use idle time 
 207    to set the cursor over and over again, starting from the toplevel windows 
 208    and ending with the youngest generation (speaking of parent and child windows). 
 209    Also don't forget that cursors (like much else) are connected to GdkWindows, 
 210    not GtkWidgets and that the "window" field of a GtkWidget might very well 
 211    point to the GdkWindow of the parent widget (-> "window-less widget") and 
 212    that the two obviously have very different meanings. 
 216 //----------------------------------------------------------------------------- 
 218 //----------------------------------------------------------------------------- 
 220 extern wxList     wxPendingDelete
; 
 221 extern bool       g_blockEventsOnDrag
; 
 222 extern bool       g_blockEventsOnScroll
; 
 223 extern wxCursor   g_globalCursor
; 
 225 static GdkGC 
*g_eraseGC 
= NULL
; 
 227 // mouse capture state: the window which has it and if the mouse is currently 
 229 static wxWindowGTK  
*g_captureWindow 
= (wxWindowGTK
*) NULL
; 
 230 static bool g_captureWindowHasMouse 
= false; 
 232 wxWindowGTK  
*g_focusWindow 
= (wxWindowGTK
*) NULL
; 
 234 // the last window which had the focus - this is normally never NULL (except 
 235 // if we never had focus at all) as even when g_focusWindow is NULL it still 
 236 // keeps its previous value 
 237 wxWindowGTK 
*g_focusWindowLast 
= (wxWindowGTK
*) NULL
; 
 239 // If a window get the focus set but has not been realized 
 240 // yet, defer setting the focus to idle time. 
 241 wxWindowGTK 
*g_delayedFocus 
= (wxWindowGTK
*) NULL
; 
 243 extern bool g_mainThreadLocked
; 
 245 //----------------------------------------------------------------------------- 
 247 //----------------------------------------------------------------------------- 
 252 #   define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance"); 
 254 #   define DEBUG_MAIN_THREAD 
 257 #define DEBUG_MAIN_THREAD 
 260 // the trace mask used for the focus debugging messages 
 261 #define TRACE_FOCUS _T("focus") 
 263 //----------------------------------------------------------------------------- 
 264 // missing gdk functions 
 265 //----------------------------------------------------------------------------- 
 268 gdk_window_warp_pointer (GdkWindow      
*window
, 
 273     window 
= GDK_ROOT_PARENT(); 
 275   if (!GDK_WINDOW_DESTROYED(window
)) 
 277       XWarpPointer (GDK_WINDOW_XDISPLAY(window
), 
 278                     None
,              /* not source window -> move from anywhere */ 
 279                     GDK_WINDOW_XID(window
),  /* dest window */ 
 280                     0, 0, 0, 0,        /* not source window -> move from anywhere */ 
 285 //----------------------------------------------------------------------------- 
 286 // local code (see below) 
 287 //----------------------------------------------------------------------------- 
 289 // returns the child of win which currently has focus or NULL if not found 
 291 // Note: can't be static, needed by textctrl.cpp. 
 292 wxWindow 
*wxFindFocusedChild(wxWindowGTK 
*win
) 
 294     wxWindow 
*winFocus 
= wxWindowGTK::FindFocus(); 
 296         return (wxWindow 
*)NULL
; 
 298     if ( winFocus 
== win 
) 
 299         return (wxWindow 
*)win
; 
 301     for ( wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
 303           node 
= node
->GetNext() ) 
 305         wxWindow 
*child 
= wxFindFocusedChild(node
->GetData()); 
 310     return (wxWindow 
*)NULL
; 
 313 static void draw_frame( GtkWidget 
*widget
, wxWindowGTK 
*win 
) 
 315     // wxUniversal widgets draw the borders and scrollbars themselves 
 316 #ifndef __WXUNIVERSAL__ 
 323     if (win
->m_hasScrolling
) 
 325         GtkScrolledWindow 
*scroll_window 
= GTK_SCROLLED_WINDOW(widget
); 
 327         GtkRequisition vscroll_req
; 
 328         vscroll_req
.width 
= 2; 
 329         vscroll_req
.height 
= 2; 
 330         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request 
) 
 331             (scroll_window
->vscrollbar
, &vscroll_req 
); 
 333         GtkRequisition hscroll_req
; 
 334         hscroll_req
.width 
= 2; 
 335         hscroll_req
.height 
= 2; 
 336         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request 
) 
 337             (scroll_window
->hscrollbar
, &hscroll_req 
); 
 339         GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) ); 
 341         if (scroll_window
->vscrollbar_visible
) 
 343             dw 
+= vscroll_req
.width
; 
 344             dw 
+= scroll_class
->scrollbar_spacing
; 
 347         if (scroll_window
->hscrollbar_visible
) 
 349             dh 
+= hscroll_req
.height
; 
 350             dh 
+= scroll_class
->scrollbar_spacing
; 
 356     if (GTK_WIDGET_NO_WINDOW (widget
)) 
 358         dx 
+= widget
->allocation
.x
; 
 359         dy 
+= widget
->allocation
.y
; 
 362     if (win
->HasFlag(wxRAISED_BORDER
)) 
 364         gtk_paint_shadow (widget
->style
, 
 368                           NULL
, NULL
, NULL
, // FIXME: No clipping? 
 370                           widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh 
); 
 374     if (win
->HasFlag(wxSUNKEN_BORDER
)) 
 376         gtk_paint_shadow (widget
->style
, 
 380                           NULL
, NULL
, NULL
, // FIXME: No clipping? 
 382                           widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh 
); 
 386     if (win
->HasFlag(wxSIMPLE_BORDER
)) 
 389         gc 
= gdk_gc_new( widget
->window 
); 
 390         gdk_gc_set_foreground( gc
, &widget
->style
->black 
); 
 391         gdk_draw_rectangle( widget
->window
, gc
, FALSE
, 
 393                          widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 ); 
 397 #endif // __WXUNIVERSAL__ 
 400 //----------------------------------------------------------------------------- 
 401 // "expose_event" of m_widget 
 402 //----------------------------------------------------------------------------- 
 406 gtk_window_own_expose_callback( GtkWidget 
*widget
, 
 407                                 GdkEventExpose 
*gdk_event
, 
 410     if (gdk_event
->count 
> 0) return FALSE
; 
 412     draw_frame( widget
, win 
); 
 414     (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
); 
 420 //----------------------------------------------------------------------------- 
 421 // "size_request" of m_widget 
 422 //----------------------------------------------------------------------------- 
 424 // make it extern because wxStaticText needs to disconnect this one 
 426 void wxgtk_window_size_request_callback(GtkWidget 
*widget
, 
 427                                         GtkRequisition 
*requisition
, 
 431     win
->GetSize( &w
, &h 
); 
 437     requisition
->height 
= h
; 
 438     requisition
->width 
= w
; 
 444 void wxgtk_combo_size_request_callback(GtkWidget 
*widget
, 
 445                                        GtkRequisition 
*requisition
, 
 448     // This callback is actually hooked into the text entry 
 449     // of the combo box, not the GtkHBox. 
 452     win
->GetSize( &w
, &h 
); 
 458     GtkCombo 
*gcombo 
= GTK_COMBO(win
->m_widget
); 
 460     GtkRequisition entry_req
; 
 462     entry_req
.height 
= 2; 
 463     (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request 
) 
 464         (gcombo
->button
, &entry_req 
); 
 466     requisition
->width 
= w 
- entry_req
.width
; 
 467     requisition
->height 
= entry_req
.height
; 
 471 //----------------------------------------------------------------------------- 
 472 // "expose_event" of m_wxwindow 
 473 //----------------------------------------------------------------------------- 
 477 gtk_window_expose_callback( GtkWidget 
*widget
, 
 478                             GdkEventExpose 
*gdk_event
, 
 484         wxapp_install_idle_handler(); 
 486     // This callback gets called in drawing-idle time under 
 487     // GTK 2.0, so we don't need to defer anything to idle 
 490     GtkPizza 
*pizza 
= GTK_PIZZA( widget 
); 
 491     if (gdk_event
->window 
!= pizza
->bin_window
) return FALSE
; 
 496         wxPrintf( wxT("OnExpose from ") ); 
 497         if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName()) 
 498             wxPrintf( win
->GetClassInfo()->GetClassName() ); 
 499         wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
, 
 500                                          (int)gdk_event
->area
.y
, 
 501                                          (int)gdk_event
->area
.width
, 
 502                                          (int)gdk_event
->area
.height 
); 
 507         win
->m_wxwindow
->style
, 
 511         (GdkRectangle
*) NULL
, 
 513         (char *)"button", // const_cast 
 518     win
->GetUpdateRegion() = wxRegion( gdk_event
->region 
); 
 520     win
->GtkSendPaintEvents(); 
 523     // Let parent window draw window-less widgets 
 524     (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
); 
 530 //----------------------------------------------------------------------------- 
 531 // "key_press_event" from any window 
 532 //----------------------------------------------------------------------------- 
 534 // set WXTRACE to this to see the key event codes on the console 
 535 #define TRACE_KEYS  _T("keyevent") 
 537 // translates an X key symbol to WXK_XXX value 
 539 // if isChar is true it means that the value returned will be used for EVT_CHAR 
 540 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide, 
 541 // for example, while if it is false it means that the value is going to be 
 542 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to 
 544 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
) 
 550         // Shift, Control and Alt don't generate the CHAR events at all 
 553             key_code 
= isChar 
? 0 : WXK_SHIFT
; 
 557             key_code 
= isChar 
? 0 : WXK_CONTROL
; 
 565             key_code 
= isChar 
? 0 : WXK_ALT
; 
 568         // neither do the toggle modifies 
 569         case GDK_Scroll_Lock
: 
 570             key_code 
= isChar 
? 0 : WXK_SCROLL
; 
 574             key_code 
= isChar 
? 0 : WXK_CAPITAL
; 
 578             key_code 
= isChar 
? 0 : WXK_NUMLOCK
; 
 582         // various other special keys 
 595         case GDK_ISO_Left_Tab
: 
 602             key_code 
= WXK_RETURN
; 
 606             key_code 
= WXK_CLEAR
; 
 610             key_code 
= WXK_PAUSE
; 
 614             key_code 
= WXK_SELECT
; 
 618             key_code 
= WXK_PRINT
; 
 622             key_code 
= WXK_EXECUTE
; 
 626             key_code 
= WXK_ESCAPE
; 
 629         // cursor and other extended keyboard keys 
 631             key_code 
= WXK_DELETE
; 
 647             key_code 
= WXK_RIGHT
; 
 654         case GDK_Prior
:     // == GDK_Page_Up 
 655             key_code 
= WXK_PRIOR
; 
 658         case GDK_Next
:      // == GDK_Page_Down 
 671             key_code 
= WXK_INSERT
; 
 686             key_code 
= (isChar 
? '0' : WXK_NUMPAD0
) + keysym 
- GDK_KP_0
; 
 690             key_code 
= isChar 
? ' ' : WXK_NUMPAD_SPACE
; 
 694             key_code 
= isChar 
? WXK_TAB 
: WXK_NUMPAD_TAB
; 
 698             key_code 
= isChar 
? WXK_RETURN 
: WXK_NUMPAD_ENTER
; 
 702             key_code 
= isChar 
? WXK_F1 
: WXK_NUMPAD_F1
; 
 706             key_code 
= isChar 
? WXK_F2 
: WXK_NUMPAD_F2
; 
 710             key_code 
= isChar 
? WXK_F3 
: WXK_NUMPAD_F3
; 
 714             key_code 
= isChar 
? WXK_F4 
: WXK_NUMPAD_F4
; 
 718             key_code 
= isChar 
? WXK_HOME 
: WXK_NUMPAD_HOME
; 
 722             key_code 
= isChar 
? WXK_LEFT 
: WXK_NUMPAD_LEFT
; 
 726             key_code 
= isChar 
? WXK_UP 
: WXK_NUMPAD_UP
; 
 730             key_code 
= isChar 
? WXK_RIGHT 
: WXK_NUMPAD_RIGHT
; 
 734             key_code 
= isChar 
? WXK_DOWN 
: WXK_NUMPAD_DOWN
; 
 737         case GDK_KP_Prior
: // == GDK_KP_Page_Up 
 738             key_code 
= isChar 
? WXK_PRIOR 
: WXK_NUMPAD_PRIOR
; 
 741         case GDK_KP_Next
: // == GDK_KP_Page_Down 
 742             key_code 
= isChar 
? WXK_NEXT 
: WXK_NUMPAD_NEXT
; 
 746             key_code 
= isChar 
? WXK_END 
: WXK_NUMPAD_END
; 
 750             key_code 
= isChar 
? WXK_HOME 
: WXK_NUMPAD_BEGIN
; 
 754             key_code 
= isChar 
? WXK_INSERT 
: WXK_NUMPAD_INSERT
; 
 758             key_code 
= isChar 
? WXK_DELETE 
: WXK_NUMPAD_DELETE
; 
 762             key_code 
= isChar 
? '=' : WXK_NUMPAD_EQUAL
; 
 765         case GDK_KP_Multiply
: 
 766             key_code 
= isChar 
? '*' : WXK_NUMPAD_MULTIPLY
; 
 770             key_code 
= isChar 
? '+' : WXK_NUMPAD_ADD
; 
 773         case GDK_KP_Separator
: 
 774             // FIXME: what is this? 
 775             key_code 
= isChar 
? '.' : WXK_NUMPAD_SEPARATOR
; 
 778         case GDK_KP_Subtract
: 
 779             key_code 
= isChar 
? '-' : WXK_NUMPAD_SUBTRACT
; 
 783             key_code 
= isChar 
? '.' : WXK_NUMPAD_DECIMAL
; 
 787             key_code 
= isChar 
? '/' : WXK_NUMPAD_DIVIDE
; 
 804             key_code 
= WXK_F1 
+ keysym 
- GDK_F1
; 
 814 static inline bool wxIsAsciiKeysym(KeySym ks
) 
 819 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
, 
 821                                       GdkEventKey 
*gdk_event
) 
 825     GdkModifierType state
; 
 826     if (gdk_event
->window
) 
 827         gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
 829     event
.SetTimestamp( gdk_event
->time 
); 
 830     event
.SetId(win
->GetId()); 
 831     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
) != 0; 
 832     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
) != 0; 
 833     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
) != 0; 
 834     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
) != 0; 
 835     event
.m_scanCode 
= gdk_event
->keyval
; 
 836     event
.m_rawCode 
= (wxUint32
) gdk_event
->keyval
; 
 837     event
.m_rawFlags 
= 0; 
 839     event
.m_uniChar 
= gdk_keyval_to_unicode(gdk_event
->keyval
); 
 841     wxGetMousePosition( &x
, &y 
); 
 842     win
->ScreenToClient( &x
, &y 
); 
 845     event
.SetEventObject( win 
); 
 850 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
, 
 852                            GdkEventKey 
*gdk_event
) 
 854     // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string 
 855     //     but only event->keyval which is quite useless to us, so remember 
 856     //     the last character from GDK_KEY_PRESS and reuse it as last resort 
 858     // NB: should be MT-safe as we're always called from the main thread only 
 863     } s_lastKeyPress 
= { 0, 0 }; 
 865     KeySym keysym 
= gdk_event
->keyval
; 
 867     wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"), 
 868                event
.GetEventType() == wxEVT_KEY_UP 
? _T("release") 
 872     long key_code 
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */); 
 876         // do we have the translation or is it a plain ASCII character? 
 877         if ( (gdk_event
->length 
== 1) || wxIsAsciiKeysym(keysym
) ) 
 879             // we should use keysym if it is ASCII as X does some translations 
 880             // like "I pressed while Control is down" => "Ctrl-I" == "TAB" 
 881             // which we don't want here (but which we do use for OnChar()) 
 882             if ( !wxIsAsciiKeysym(keysym
) ) 
 884                 keysym 
= (KeySym
)gdk_event
->string
[0]; 
 887             // we want to always get the same key code when the same key is 
 888             // pressed regardless of the state of the modifiers, i.e. on a 
 889             // standard US keyboard pressing '5' or '%' ('5' key with 
 890             // Shift) should result in the same key code in OnKeyDown(): 
 891             // '5' (although OnChar() will get either '5' or '%'). 
 893             // to do it we first translate keysym to keycode (== scan code) 
 894             // and then back but always using the lower register 
 895             Display 
*dpy 
= (Display 
*)wxGetDisplay(); 
 896             KeyCode keycode 
= XKeysymToKeycode(dpy
, keysym
); 
 898             wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
); 
 900             KeySym keysymNormalized 
= XKeycodeToKeysym(dpy
, keycode
, 0); 
 902             // use the normalized, i.e. lower register, keysym if we've 
 904             key_code 
= keysymNormalized 
? keysymNormalized 
: keysym
; 
 906             // as explained above, we want to have lower register key codes 
 907             // normally but for the letter keys we want to have the upper ones 
 909             // NB: don't use XConvertCase() here, we want to do it for letters 
 911             key_code 
= toupper(key_code
); 
 913         else // non ASCII key, what to do? 
 915             // by default, ignore it 
 918             // but if we have cached information from the last KEY_PRESS 
 919             if ( gdk_event
->type 
== GDK_KEY_RELEASE 
) 
 922                 if ( keysym 
== s_lastKeyPress
.keysym 
) 
 924                     key_code 
= s_lastKeyPress
.keycode
; 
 929         if ( gdk_event
->type 
== GDK_KEY_PRESS 
) 
 931             // remember it to be reused for KEY_UP event later 
 932             s_lastKeyPress
.keysym 
= keysym
; 
 933             s_lastKeyPress
.keycode 
= key_code
; 
 937     wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
); 
 939     // sending unknown key events doesn't really make sense 
 943     // now fill all the other fields 
 944     wxFillOtherKeyEventFields(event
, win
, gdk_event
); 
 946     event
.m_keyCode 
= key_code
; 
 948     if ( gdk_event
->type 
== GDK_KEY_PRESS 
||  gdk_event
->type 
== GDK_KEY_RELEASE 
) 
 950         event
.m_uniChar 
= key_code
; 
 960     GtkIMContext 
*context
; 
 961     GdkEventKey  
*lastKeyEvent
; 
 965         context 
= gtk_im_multicontext_new(); 
 970         g_object_unref(context
); 
 976 gtk_window_key_press_callback( GtkWidget 
*widget
, 
 977                                GdkEventKey 
*gdk_event
, 
 983         wxapp_install_idle_handler(); 
 987     if (g_blockEventsOnDrag
) 
 991     wxKeyEvent 
event( wxEVT_KEY_DOWN 
); 
 993     bool return_after_IM 
= false; 
 995     if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) ) 
 997         // Emit KEY_DOWN event 
 998         ret 
= win
->GetEventHandler()->ProcessEvent( event 
); 
1002         // Return after IM processing as we cannot do 
1003         // anything with it anyhow. 
1004         return_after_IM 
= true; 
1007     // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw): 
1008     // When we get a key_press event here, it could be originate 
1009     // from the current widget or its child widgets.  However, only the widget 
1010     // with the INPUT FOCUS can generate the INITIAL key_press event.  That is, 
1011     // if the CURRENT widget doesn't have the FOCUS at all, this event definitely 
1012     // originated from its child widgets and shouldn't be passed to IM context. 
1013     // In fact, what a GTK+ IM should do is filtering keyEvents and convert them 
1014     // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS.  Besides, when current 
1015     // widgets has both IM context and input focus, the event should be filtered 
1016     // by gtk_im_context_filter_keypress(). 
1017     // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns. 
1018     if ((!ret
) && (win
->m_imData 
!= NULL
) && ( wxWindow::FindFocus() == win 
)) 
1020         // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API 
1021         // docs, if IM filter returns true, no further processing should be done. 
1022         // we should send the key_down event anyway. 
1023         bool intercepted_by_IM 
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
); 
1024         win
->m_imData
->lastKeyEvent 
= NULL
; 
1025         if (intercepted_by_IM
) 
1027             wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM")); 
1032     if (return_after_IM
) 
1038         wxWindowGTK 
*ancestor 
= win
; 
1041             int command 
= ancestor
->GetAcceleratorTable()->GetCommand( event 
); 
1044                 wxCommandEvent 
command_event( wxEVT_COMMAND_MENU_SELECTED
, command 
); 
1045                 ret 
= ancestor
->GetEventHandler()->ProcessEvent( command_event 
); 
1048             if (ancestor
->IsTopLevel()) 
1050             ancestor 
= ancestor
->GetParent(); 
1053 #endif // wxUSE_ACCEL 
1055     // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x 
1056     // will only be sent if it is not in an accelerator table. 
1060         KeySym keysym 
= gdk_event
->keyval
; 
1061         // Find key code for EVT_CHAR and EVT_CHAR_HOOK events 
1062         key_code 
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */); 
1065             if ( wxIsAsciiKeysym(keysym
) ) 
1068                 key_code 
= (unsigned char)keysym
; 
1070             // gdk_event->string is actually deprecated 
1071             else if ( gdk_event
->length 
== 1 ) 
1073                 key_code 
= (unsigned char)gdk_event
->string
[0]; 
1079             wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
); 
1081             event
.m_keyCode 
= key_code
; 
1083             // To conform to the docs we need to translate Ctrl-alpha 
1084             // characters to values in the range 1-26. 
1085             if (event
.ControlDown() && key_code 
>= 'a' && key_code 
<= 'z' ) 
1087                 event
.m_keyCode 
= key_code 
- 'a' + 1; 
1089                 event
.m_uniChar 
= event
.m_keyCode
; 
1093             // Implement OnCharHook by checking ancestor top level windows 
1094             wxWindow 
*parent 
= win
; 
1095             while (parent 
&& !parent
->IsTopLevel()) 
1096                 parent 
= parent
->GetParent(); 
1099                 event
.SetEventType( wxEVT_CHAR_HOOK 
); 
1100                 ret 
= parent
->GetEventHandler()->ProcessEvent( event 
); 
1105                 event
.SetEventType(wxEVT_CHAR
); 
1106                 ret 
= win
->GetEventHandler()->ProcessEvent( event 
); 
1115     // win is a control: tab can be propagated up 
1117          ((gdk_event
->keyval 
== GDK_Tab
) || (gdk_event
->keyval 
== GDK_ISO_Left_Tab
)) && 
1118 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may 
1119 //     have this style, yet choose not to process this particular TAB in which 
1120 //     case TAB must still work as a navigational character 
1121 // JS: enabling again to make consistent with other platforms 
1122 //     (with wxTE_PROCESS_TAB you have to call Navigate to get default 
1123 //     navigation behaviour) 
1125          (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) && 
1127          win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) ) 
1129         wxNavigationKeyEvent new_event
; 
1130         new_event
.SetEventObject( win
->GetParent() ); 
1131         // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB 
1132         new_event
.SetDirection( (gdk_event
->keyval 
== GDK_Tab
) ); 
1133         // CTRL-TAB changes the (parent) window, i.e. switch notebook page 
1134         new_event
.SetWindowChange( (gdk_event
->state 
& GDK_CONTROL_MASK
) ); 
1135         new_event
.SetCurrentFocus( win 
); 
1136         ret 
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event 
); 
1139     // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) 
1141          (gdk_event
->keyval 
== GDK_Escape
) ) 
1143         // however only do it if we have a Cancel button in the dialog, 
1144         // otherwise the user code may get confused by the events from a 
1145         // non-existing button and, worse, a wxButton might get button event 
1146         // from another button which is not really expected 
1147         wxWindow 
*winForCancel 
= win
, 
1149         while ( winForCancel 
) 
1151             btnCancel 
= winForCancel
->FindWindow(wxID_CANCEL
); 
1154                 // found a cancel button 
1158             if ( winForCancel
->IsTopLevel() ) 
1160                 // no need to look further 
1164             // maybe our parent has a cancel button? 
1165             winForCancel 
= winForCancel
->GetParent(); 
1170             wxCommandEvent 
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
); 
1171             eventClick
.SetEventObject(btnCancel
); 
1172             ret 
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
); 
1178         g_signal_stop_emission_by_name (widget
, "key_press_event"); 
1188 gtk_wxwindow_commit_cb (GtkIMContext 
*context
, 
1192     wxKeyEvent 
event( wxEVT_KEY_DOWN 
); 
1194     // take modifiers, cursor position, timestamp etc. from the last 
1195     // key_press_event that was fed into Input Method: 
1196     if (window
->m_imData
->lastKeyEvent
) 
1198         wxFillOtherKeyEventFields(event
, 
1199                                   window
, window
->m_imData
->lastKeyEvent
); 
1203     const wxWCharBuffer data 
= wxConvUTF8
.cMB2WC( (char*)str 
); 
1205     const wxWCharBuffer wdata 
= wxConvUTF8
.cMB2WC( (char*)str 
); 
1206     const wxCharBuffer data 
= wxConvLocal
.cWC2MB( wdata 
); 
1207 #endif // wxUSE_UNICODE 
1208     if( !(const wxChar
*)data 
) 
1213     // Implement OnCharHook by checking ancestor top level windows 
1214     wxWindow 
*parent 
= window
; 
1215     while (parent 
&& !parent
->IsTopLevel()) 
1216         parent 
= parent
->GetParent(); 
1218     for( const wxChar
* pstr 
= data
; *pstr
; pstr
++ ) 
1221         event
.m_uniChar 
= *pstr
; 
1222         // Backward compatible for ISO-8859-1 
1223         event
.m_keyCode 
= *pstr 
< 256 ? event
.m_uniChar 
: 0; 
1224         wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
); 
1226         event
.m_keyCode 
= *pstr
; 
1227 #endif  // wxUSE_UNICODE 
1229         // To conform to the docs we need to translate Ctrl-alpha 
1230         // characters to values in the range 1-26. 
1231         if (event
.ControlDown() && *pstr 
>= 'a' && *pstr 
<= 'z' ) 
1233             event
.m_keyCode 
= *pstr 
- 'a' + 1; 
1235             event
.m_uniChar 
= event
.m_keyCode
; 
1241             event
.SetEventType( wxEVT_CHAR_HOOK 
); 
1242             ret 
= parent
->GetEventHandler()->ProcessEvent( event 
); 
1247             event
.SetEventType(wxEVT_CHAR
); 
1248             ret 
= window
->GetEventHandler()->ProcessEvent( event 
); 
1255 //----------------------------------------------------------------------------- 
1256 // "key_release_event" from any window 
1257 //----------------------------------------------------------------------------- 
1261 gtk_window_key_release_callback( GtkWidget 
*widget
, 
1262                                  GdkEventKey 
*gdk_event
, 
1268         wxapp_install_idle_handler(); 
1273     if (g_blockEventsOnDrag
) 
1276     wxKeyEvent 
event( wxEVT_KEY_UP 
); 
1277     if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) ) 
1279         // unknown key pressed, ignore (the event would be useless anyhow) 
1283     if ( !win
->GetEventHandler()->ProcessEvent( event 
) ) 
1286     g_signal_stop_emission_by_name (widget
, "key_release_event"); 
1291 // ============================================================================ 
1293 // ============================================================================ 
1295 // ---------------------------------------------------------------------------- 
1296 // mouse event processing helpers 
1297 // ---------------------------------------------------------------------------- 
1299 // init wxMouseEvent with the info from GdkEventXXX struct 
1300 template<typename T
> void InitMouseEvent(wxWindowGTK 
*win
, 
1301                                          wxMouseEvent
& event
, 
1304     event
.SetTimestamp( gdk_event
->time 
); 
1305     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
); 
1306     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
); 
1307     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
); 
1308     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
); 
1309     event
.m_leftDown 
= (gdk_event
->state 
& GDK_BUTTON1_MASK
); 
1310     event
.m_middleDown 
= (gdk_event
->state 
& GDK_BUTTON2_MASK
); 
1311     event
.m_rightDown 
= (gdk_event
->state 
& GDK_BUTTON3_MASK
); 
1312     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
1314        event
.m_linesPerAction 
= 3; 
1315        event
.m_wheelDelta 
= 120; 
1316        if (((GdkEventButton
*)gdk_event
)->button 
== 4) 
1317            event
.m_wheelRotation 
= 120; 
1318        else if (((GdkEventButton
*)gdk_event
)->button 
== 5) 
1319            event
.m_wheelRotation 
= -120; 
1322     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1323     event
.m_x 
= (wxCoord
)gdk_event
->x 
- pt
.x
; 
1324     event
.m_y 
= (wxCoord
)gdk_event
->y 
- pt
.y
; 
1326     event
.SetEventObject( win 
); 
1327     event
.SetId( win
->GetId() ); 
1328     event
.SetTimestamp( gdk_event
->time 
); 
1331 static void AdjustEventButtonState(wxMouseEvent
& event
) 
1333     // GDK reports the old state of the button for a button press event, but 
1334     // for compatibility with MSW and common sense we want m_leftDown be TRUE 
1335     // for a LEFT_DOWN event, not FALSE, so we will invert 
1336     // left/right/middleDown for the corresponding click events 
1338     if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) || 
1339         (event
.GetEventType() == wxEVT_LEFT_DCLICK
) || 
1340         (event
.GetEventType() == wxEVT_LEFT_UP
)) 
1342         event
.m_leftDown 
= !event
.m_leftDown
; 
1346     if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) || 
1347         (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) || 
1348         (event
.GetEventType() == wxEVT_MIDDLE_UP
)) 
1350         event
.m_middleDown 
= !event
.m_middleDown
; 
1354     if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) || 
1355         (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) || 
1356         (event
.GetEventType() == wxEVT_RIGHT_UP
)) 
1358         event
.m_rightDown 
= !event
.m_rightDown
; 
1363 // find the window to send the mouse event too 
1365 wxWindowGTK 
*FindWindowForMouseEvent(wxWindowGTK 
*win
, wxCoord
& x
, wxCoord
& y
) 
1370     if (win
->m_wxwindow
) 
1372         GtkPizza 
*pizza 
= GTK_PIZZA(win
->m_wxwindow
); 
1373         xx 
+= pizza
->xoffset
; 
1374         yy 
+= pizza
->yoffset
; 
1377     wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
1380         wxWindowGTK 
*child 
= node
->GetData(); 
1382         node 
= node
->GetNext(); 
1383         if (!child
->IsShown()) 
1386         if (child
->IsTransparentForMouse()) 
1388             // wxStaticBox is transparent in the box itself 
1389             int xx1 
= child
->m_x
; 
1390             int yy1 
= child
->m_y
; 
1391             int xx2 
= child
->m_x 
+ child
->m_width
; 
1392             int yy2 
= child
->m_y 
+ child
->m_height
; 
1395             if (((xx 
>= xx1
) && (xx 
<= xx1
+10) && (yy 
>= yy1
) && (yy 
<= yy2
)) || 
1397                 ((xx 
>= xx2
-10) && (xx 
<= xx2
) && (yy 
>= yy1
) && (yy 
<= yy2
)) || 
1399                 ((xx 
>= xx1
) && (xx 
<= xx2
) && (yy 
>= yy1
) && (yy 
<= yy1
+10)) || 
1401                 ((xx 
>= xx1
) && (xx 
<= xx2
) && (yy 
>= yy2
-1) && (yy 
<= yy2
))) 
1412             if ((child
->m_wxwindow 
== (GtkWidget
*) NULL
) && 
1413                 (child
->m_x 
<= xx
) && 
1414                 (child
->m_y 
<= yy
) && 
1415                 (child
->m_x
+child
->m_width  
>= xx
) && 
1416                 (child
->m_y
+child
->m_height 
>= yy
)) 
1429 //----------------------------------------------------------------------------- 
1430 // "button_press_event" 
1431 //----------------------------------------------------------------------------- 
1435 gtk_window_button_press_callback( GtkWidget 
*widget
, 
1436                                   GdkEventButton 
*gdk_event
, 
1442         wxapp_install_idle_handler(); 
1445     wxPrintf( wxT("1) OnButtonPress from ") ); 
1446     if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) 
1447         wxPrintf( win->GetClassInfo()->GetClassName() ); 
1448     wxPrintf( wxT(".\n") ); 
1450     if (!win
->m_hasVMT
) return FALSE
; 
1451     if (g_blockEventsOnDrag
) return TRUE
; 
1452     if (g_blockEventsOnScroll
) return TRUE
; 
1454     if (!win
->IsOwnGtkWindow( gdk_event
->window 
)) return FALSE
; 
1456     if (win
->m_wxwindow 
&& (g_focusWindow 
!= win
) && win
->AcceptsFocus()) 
1458         gtk_widget_grab_focus( win
->m_wxwindow 
); 
1460         wxPrintf( wxT("GrabFocus from ") ); 
1461         if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) 
1462             wxPrintf( win->GetClassInfo()->GetClassName() ); 
1463         wxPrintf( wxT(".\n") ); 
1467     // GDK sends surplus button down events 
1468     // before a double click event. We 
1469     // need to filter these out. 
1470     if (gdk_event
->type 
== GDK_BUTTON_PRESS
) 
1472         GdkEvent 
*peek_event 
= gdk_event_peek(); 
1475             if ((peek_event
->type 
== GDK_2BUTTON_PRESS
) || 
1476                 (peek_event
->type 
== GDK_3BUTTON_PRESS
)) 
1478                 gdk_event_free( peek_event 
); 
1483                 gdk_event_free( peek_event 
); 
1488     wxEventType event_type 
= wxEVT_NULL
; 
1490     // GdkDisplay is a GTK+ 2.2.0 thing 
1491 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0) 
1492     if ( gdk_event
->type 
== GDK_2BUTTON_PRESS 
&& 
1493             !gtk_check_version(2,2,0) && 
1494             gdk_event
->button 
>= 1 && gdk_event
->button 
<= 3 ) 
1496         // Reset GDK internal timestamp variables in order to disable GDK 
1497         // triple click events. GDK will then next time believe no button has 
1498         // been clicked just before, and send a normal button click event. 
1499         GdkDisplay
* display 
= gtk_widget_get_display (widget
); 
1500         display
->button_click_time
[1] = 0; 
1501         display
->button_click_time
[0] = 0; 
1505     if (gdk_event
->button 
== 1) 
1507         // note that GDK generates triple click events which are not supported 
1508         // by wxWidgets but still have to be passed to the app as otherwise 
1509         // clicks would simply go missing 
1510         switch (gdk_event
->type
) 
1512             // we shouldn't get triple clicks at all for GTK2 because we 
1513             // suppress them artificially using the code above but we still 
1514             // should map them to something for GTK1 and not just ignore them 
1515             // as this would lose clicks 
1516             case GDK_3BUTTON_PRESS
:     // we could also map this to DCLICK... 
1517             case GDK_BUTTON_PRESS
: 
1518                 event_type 
= wxEVT_LEFT_DOWN
; 
1521             case GDK_2BUTTON_PRESS
: 
1522                 event_type 
= wxEVT_LEFT_DCLICK
; 
1526                 // just to silence gcc warnings 
1530     else if (gdk_event
->button 
== 2) 
1532         switch (gdk_event
->type
) 
1534             case GDK_3BUTTON_PRESS
: 
1535             case GDK_BUTTON_PRESS
: 
1536                 event_type 
= wxEVT_MIDDLE_DOWN
; 
1539             case GDK_2BUTTON_PRESS
: 
1540                 event_type 
= wxEVT_MIDDLE_DCLICK
; 
1547     else if (gdk_event
->button 
== 3) 
1549         switch (gdk_event
->type
) 
1551             case GDK_3BUTTON_PRESS
: 
1552             case GDK_BUTTON_PRESS
: 
1553                 event_type 
= wxEVT_RIGHT_DOWN
; 
1556             case GDK_2BUTTON_PRESS
: 
1557                 event_type 
= wxEVT_RIGHT_DCLICK
; 
1564     else if (gdk_event
->button 
== 4 || gdk_event
->button 
== 5) 
1566         if (gdk_event
->type 
== GDK_BUTTON_PRESS 
) 
1568             event_type 
= wxEVT_MOUSEWHEEL
; 
1572     if ( event_type 
== wxEVT_NULL 
) 
1574         // unknown mouse button or click type 
1578     wxMouseEvent 
event( event_type 
); 
1579     InitMouseEvent( win
, event
, gdk_event 
); 
1581     AdjustEventButtonState(event
); 
1583     // wxListBox actually gets mouse events from the item, so we need to give it 
1584     // a chance to correct this 
1585     win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
); 
1587     // find the correct window to send the event to: it may be a different one 
1588     // from the one which got it at GTK+ level because some controls don't have 
1589     // their own X window and thus cannot get any events. 
1590     if ( !g_captureWindow 
) 
1591         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1593     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
1595         g_signal_stop_emission_by_name (widget
, "button_press_event"); 
1599     if (event_type 
== wxEVT_RIGHT_DOWN
) 
1601         // generate a "context menu" event: this is similar to right mouse 
1602         // click under many GUIs except that it is generated differently 
1603         // (right up under MSW, ctrl-click under Mac, right down here) and 
1605         // (a) it's a command event and so is propagated to the parent 
1606         // (b) under some ports it can be generated from kbd too 
1607         // (c) it uses screen coords (because of (a)) 
1608         wxContextMenuEvent 
evtCtx( 
1611             win
->ClientToScreen(event
.GetPosition())); 
1612         evtCtx
.SetEventObject(win
); 
1613         return win
->GetEventHandler()->ProcessEvent(evtCtx
); 
1620 //----------------------------------------------------------------------------- 
1621 // "button_release_event" 
1622 //----------------------------------------------------------------------------- 
1626 gtk_window_button_release_callback( GtkWidget 
*widget
, 
1627                                     GdkEventButton 
*gdk_event
, 
1633         wxapp_install_idle_handler(); 
1635     if (!win
->m_hasVMT
) return FALSE
; 
1636     if (g_blockEventsOnDrag
) return FALSE
; 
1637     if (g_blockEventsOnScroll
) return FALSE
; 
1639     if (!win
->IsOwnGtkWindow( gdk_event
->window 
)) return FALSE
; 
1641     wxEventType event_type 
= wxEVT_NULL
; 
1643     switch (gdk_event
->button
) 
1646             event_type 
= wxEVT_LEFT_UP
; 
1650             event_type 
= wxEVT_MIDDLE_UP
; 
1654             event_type 
= wxEVT_RIGHT_UP
; 
1658             // unknwon button, don't process 
1662     wxMouseEvent 
event( event_type 
); 
1663     InitMouseEvent( win
, event
, gdk_event 
); 
1665     AdjustEventButtonState(event
); 
1667     // same wxListBox hack as above 
1668     win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
); 
1670     if ( !g_captureWindow 
) 
1671         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1673     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
1675         g_signal_stop_emission_by_name (widget
, "button_release_event"); 
1683 //----------------------------------------------------------------------------- 
1684 // "motion_notify_event" 
1685 //----------------------------------------------------------------------------- 
1689 gtk_window_motion_notify_callback( GtkWidget 
*widget
, 
1690                                    GdkEventMotion 
*gdk_event
, 
1696         wxapp_install_idle_handler(); 
1698     if (!win
->m_hasVMT
) return FALSE
; 
1699     if (g_blockEventsOnDrag
) return FALSE
; 
1700     if (g_blockEventsOnScroll
) return FALSE
; 
1702     if (!win
->IsOwnGtkWindow( gdk_event
->window 
)) return FALSE
; 
1704     if (gdk_event
->is_hint
) 
1708         GdkModifierType state
; 
1709         gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
1715     printf( "OnMotion from " ); 
1716     if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) 
1717       printf( win->GetClassInfo()->GetClassName() ); 
1721     wxMouseEvent 
event( wxEVT_MOTION 
); 
1722     InitMouseEvent(win
, event
, gdk_event
); 
1724     if ( g_captureWindow 
) 
1726         // synthetize a mouse enter or leave event if needed 
1727         GdkWindow 
*winUnderMouse 
= gdk_window_at_pointer(NULL
, NULL
); 
1728         // This seems to be necessary and actually been added to 
1729         // GDK itself in version 2.0.X 
1732         bool hasMouse 
= winUnderMouse 
== gdk_event
->window
; 
1733         if ( hasMouse 
!= g_captureWindowHasMouse 
) 
1735             // the mouse changed window 
1736             g_captureWindowHasMouse 
= hasMouse
; 
1738             wxMouseEvent 
eventM(g_captureWindowHasMouse 
? wxEVT_ENTER_WINDOW
 
1739                                                         : wxEVT_LEAVE_WINDOW
); 
1740             InitMouseEvent(win
, eventM
, gdk_event
); 
1741             eventM
.SetEventObject(win
); 
1742             win
->GetEventHandler()->ProcessEvent(eventM
); 
1747         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1750     if ( !g_captureWindow 
) 
1752         wxSetCursorEvent 
cevent( event
.m_x
, event
.m_y 
); 
1753         if (win
->GetEventHandler()->ProcessEvent( cevent 
)) 
1755             // Rewrite cursor handling here (away from idle). 
1759     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
1761         g_signal_stop_emission_by_name (widget
, "motion_notify_event"); 
1769 //----------------------------------------------------------------------------- 
1770 // "mouse_wheel_event" 
1771 //----------------------------------------------------------------------------- 
1775 gtk_window_wheel_callback (GtkWidget 
* widget
, 
1776                            GdkEventScroll 
* gdk_event
, 
1782         wxapp_install_idle_handler(); 
1784     wxEventType event_type 
= wxEVT_NULL
; 
1785     if (gdk_event
->direction 
== GDK_SCROLL_UP
) 
1786         event_type 
= wxEVT_MOUSEWHEEL
; 
1787     else if (gdk_event
->direction 
== GDK_SCROLL_DOWN
) 
1788         event_type 
= wxEVT_MOUSEWHEEL
; 
1792     wxMouseEvent 
event( event_type 
); 
1793     // Can't use InitMouse macro because scroll events don't have button 
1794     event
.SetTimestamp( gdk_event
->time 
); 
1795     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
); 
1796     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
); 
1797     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
); 
1798     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
); 
1799     event
.m_leftDown 
= (gdk_event
->state 
& GDK_BUTTON1_MASK
); 
1800     event
.m_middleDown 
= (gdk_event
->state 
& GDK_BUTTON2_MASK
); 
1801     event
.m_rightDown 
= (gdk_event
->state 
& GDK_BUTTON3_MASK
); 
1802     event
.m_linesPerAction 
= 3; 
1803     event
.m_wheelDelta 
= 120; 
1804     if (gdk_event
->direction 
== GDK_SCROLL_UP
) 
1805         event
.m_wheelRotation 
= 120; 
1807         event
.m_wheelRotation 
= -120; 
1809     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1810     event
.m_x 
= (wxCoord
)gdk_event
->x 
- pt
.x
; 
1811     event
.m_y 
= (wxCoord
)gdk_event
->y 
- pt
.y
; 
1813     event
.SetEventObject( win 
); 
1814     event
.SetId( win
->GetId() ); 
1815     event
.SetTimestamp( gdk_event
->time 
); 
1817     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
1819         g_signal_stop_emission_by_name (widget
, "scroll_event"); 
1827 //----------------------------------------------------------------------------- 
1829 //----------------------------------------------------------------------------- 
1831 static gboolean 
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
) 
1833     wxContextMenuEvent 
event( 
1837     event
.SetEventObject(win
); 
1838     return win
->GetEventHandler()->ProcessEvent(event
); 
1842 //----------------------------------------------------------------------------- 
1844 //----------------------------------------------------------------------------- 
1846 // send the wxChildFocusEvent and wxFocusEvent, common code of 
1847 // gtk_window_focus_in_callback() and SetFocus() 
1848 static bool DoSendFocusEvents(wxWindow 
*win
) 
1850     // Notify the parent keeping track of focus for the kbd navigation 
1851     // purposes that we got it. 
1852     wxChildFocusEvent 
eventChildFocus(win
); 
1853     (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
); 
1855     wxFocusEvent 
eventFocus(wxEVT_SET_FOCUS
, win
->GetId()); 
1856     eventFocus
.SetEventObject(win
); 
1858     return win
->GetEventHandler()->ProcessEvent(eventFocus
); 
1863 gtk_window_focus_in_callback( GtkWidget 
*widget
, 
1864                               GdkEventFocus 
*WXUNUSED(event
), 
1870         wxapp_install_idle_handler(); 
1873         gtk_im_context_focus_in(win
->m_imData
->context
); 
1876     g_focusWindow 
= win
; 
1878     wxLogTrace(TRACE_FOCUS
, 
1879                _T("%s: focus in"), win
->GetName().c_str()); 
1883         gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
); 
1887     // caret needs to be informed about focus change 
1888     wxCaret 
*caret 
= win
->GetCaret(); 
1891         caret
->OnSetFocus(); 
1893 #endif // wxUSE_CARET 
1895     gboolean ret 
= FALSE
; 
1897     // does the window itself think that it has the focus? 
1898     if ( !win
->m_hasFocus 
) 
1900         // not yet, notify it 
1901         win
->m_hasFocus 
= true; 
1903         (void)DoSendFocusEvents(win
); 
1908     // Disable default focus handling for custom windows 
1909     // since the default GTK+ handler issues a repaint 
1910     if (win
->m_wxwindow
) 
1917 //----------------------------------------------------------------------------- 
1918 // "focus_out_event" 
1919 //----------------------------------------------------------------------------- 
1923 gtk_window_focus_out_callback( GtkWidget 
*widget
, 
1924                                GdkEventFocus 
*gdk_event
, 
1930         wxapp_install_idle_handler(); 
1933         gtk_im_context_focus_out(win
->m_imData
->context
); 
1935     wxLogTrace( TRACE_FOCUS
, 
1936                 _T("%s: focus out"), win
->GetName().c_str() ); 
1939     wxWindowGTK 
*winFocus 
= wxFindFocusedChild(win
); 
1943     g_focusWindow 
= (wxWindowGTK 
*)NULL
; 
1951     // caret needs to be informed about focus change 
1952     wxCaret 
*caret 
= win
->GetCaret(); 
1955         caret
->OnKillFocus(); 
1957 #endif // wxUSE_CARET 
1959     gboolean ret 
= FALSE
; 
1961     // don't send the window a kill focus event if it thinks that it doesn't 
1962     // have focus already 
1963     if ( win
->m_hasFocus 
) 
1965         win
->m_hasFocus 
= false; 
1967         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, win
->GetId() ); 
1968         event
.SetEventObject( win 
); 
1970         (void)win
->GetEventHandler()->ProcessEvent( event 
); 
1975     // Disable default focus handling for custom windows 
1976     // since the default GTK+ handler issues a repaint 
1977     if (win
->m_wxwindow
) 
1984 //----------------------------------------------------------------------------- 
1985 // "enter_notify_event" 
1986 //----------------------------------------------------------------------------- 
1990 gtk_window_enter_callback( GtkWidget 
*widget
, 
1991                            GdkEventCrossing 
*gdk_event
, 
1997         wxapp_install_idle_handler(); 
1999     if (!win
->m_hasVMT
) return FALSE
; 
2000     if (g_blockEventsOnDrag
) return FALSE
; 
2002     // Event was emitted after a grab 
2003     if (gdk_event
->mode 
!= GDK_CROSSING_NORMAL
) return FALSE
; 
2005     if (!win
->IsOwnGtkWindow( gdk_event
->window 
)) return FALSE
; 
2009     GdkModifierType state 
= (GdkModifierType
)0; 
2011     gdk_window_get_pointer( widget
->window
, &x
, &y
, &state 
); 
2013     wxMouseEvent 
event( wxEVT_ENTER_WINDOW 
); 
2014     InitMouseEvent(win
, event
, gdk_event
); 
2015     wxPoint pt 
= win
->GetClientAreaOrigin(); 
2016     event
.m_x 
= x 
+ pt
.x
; 
2017     event
.m_y 
= y 
+ pt
.y
; 
2019     if ( !g_captureWindow 
) 
2021         wxSetCursorEvent 
cevent( event
.m_x
, event
.m_y 
); 
2022         if (win
->GetEventHandler()->ProcessEvent( cevent 
)) 
2024             // Rewrite cursor handling here (away from idle). 
2028     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
2030        g_signal_stop_emission_by_name (widget
, "enter_notify_event"); 
2038 //----------------------------------------------------------------------------- 
2039 // "leave_notify_event" 
2040 //----------------------------------------------------------------------------- 
2044 gtk_window_leave_callback( GtkWidget 
*widget
, 
2045                            GdkEventCrossing 
*gdk_event
, 
2051         wxapp_install_idle_handler(); 
2053     if (!win
->m_hasVMT
) return FALSE
; 
2054     if (g_blockEventsOnDrag
) return FALSE
; 
2056     // Event was emitted after an ungrab 
2057     if (gdk_event
->mode 
!= GDK_CROSSING_NORMAL
) return FALSE
; 
2059     if (!win
->IsOwnGtkWindow( gdk_event
->window 
)) return FALSE
; 
2061     wxMouseEvent 
event( wxEVT_LEAVE_WINDOW 
); 
2062     event
.SetTimestamp( gdk_event
->time 
); 
2063     event
.SetEventObject( win 
); 
2067     GdkModifierType state 
= (GdkModifierType
)0; 
2069     gdk_window_get_pointer( widget
->window
, &x
, &y
, &state 
); 
2071     event
.m_shiftDown 
= (state 
& GDK_SHIFT_MASK
) != 0; 
2072     event
.m_controlDown 
= (state 
& GDK_CONTROL_MASK
) != 0; 
2073     event
.m_altDown 
= (state 
& GDK_MOD1_MASK
) != 0; 
2074     event
.m_metaDown 
= (state 
& GDK_MOD2_MASK
) != 0; 
2075     event
.m_leftDown 
= (state 
& GDK_BUTTON1_MASK
) != 0; 
2076     event
.m_middleDown 
= (state 
& GDK_BUTTON2_MASK
) != 0; 
2077     event
.m_rightDown 
= (state 
& GDK_BUTTON3_MASK
) != 0; 
2079     wxPoint pt 
= win
->GetClientAreaOrigin(); 
2080     event
.m_x 
= x 
+ pt
.x
; 
2081     event
.m_y 
= y 
+ pt
.y
; 
2083     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
2085         g_signal_stop_emission_by_name (widget
, "leave_notify_event"); 
2093 //----------------------------------------------------------------------------- 
2094 // "value_changed" from m_vAdjust 
2095 //----------------------------------------------------------------------------- 
2098 static void gtk_window_vscroll_callback( GtkAdjustment 
*adjust
, 
2104         wxapp_install_idle_handler(); 
2106     if (g_blockEventsOnDrag
) return; 
2108     if (!win
->m_hasVMT
) return; 
2110     float diff 
= adjust
->value 
- win
->m_oldVerticalPos
; 
2111     if (fabs(diff
) < 0.2) return; 
2113     win
->m_oldVerticalPos 
= adjust
->value
; 
2115     wxEventType command 
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
); 
2117     int value 
= (int)(adjust
->value
+0.5); 
2119     wxScrollWinEvent 
event( command
, value
, wxVERTICAL 
); 
2120     event
.SetEventObject( win 
); 
2121     win
->GetEventHandler()->ProcessEvent( event 
); 
2125 //----------------------------------------------------------------------------- 
2126 // "value_changed" from m_hAdjust 
2127 //----------------------------------------------------------------------------- 
2130 static void gtk_window_hscroll_callback( GtkAdjustment 
*adjust
, 
2136         wxapp_install_idle_handler(); 
2138     if (g_blockEventsOnDrag
) return; 
2139     if (!win
->m_hasVMT
) return; 
2141     float diff 
= adjust
->value 
- win
->m_oldHorizontalPos
; 
2142     if (fabs(diff
) < 0.2) return; 
2144     wxEventType command 
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
); 
2146     win
->m_oldHorizontalPos 
= adjust
->value
; 
2148     int value 
= (int)(adjust
->value
+0.5); 
2150     wxScrollWinEvent 
event( command
, value
, wxHORIZONTAL 
); 
2151     event
.SetEventObject( win 
); 
2152     win
->GetEventHandler()->ProcessEvent( event 
); 
2156 //----------------------------------------------------------------------------- 
2157 // "button_press_event" from scrollbar 
2158 //----------------------------------------------------------------------------- 
2162 gtk_scrollbar_button_press_callback( GtkWidget 
*widget
, 
2163                                      GdkEventButton 
*gdk_event
, 
2169         wxapp_install_idle_handler(); 
2172     g_blockEventsOnScroll 
= true; 
2174 // FIXME: there is no 'slider' field in GTK+ 2.0 any more 
2176     win
->m_isScrolling 
= (gdk_event
->window 
== widget
->slider
); 
2183 //----------------------------------------------------------------------------- 
2184 // "button_release_event" from scrollbar 
2185 //----------------------------------------------------------------------------- 
2189 gtk_scrollbar_button_release_callback( GtkRange 
*widget
, 
2190                                        GdkEventButton 
*WXUNUSED(gdk_event
), 
2195 //  don't test here as we can release the mouse while being over 
2196 //  a different window than the slider 
2198 //    if (gdk_event->window != widget->slider) return FALSE; 
2200     g_blockEventsOnScroll 
= false; 
2202     if (win
->m_isScrolling
) 
2204         wxEventType command 
= wxEVT_SCROLLWIN_THUMBRELEASE
; 
2208         GtkScrolledWindow 
*scrolledWindow 
= GTK_SCROLLED_WINDOW(win
->m_widget
); 
2209         if (widget 
== GTK_RANGE(scrolledWindow
->hscrollbar
)) 
2211             value 
= (int)(win
->m_hAdjust
->value
+0.5); 
2214         if (widget 
== GTK_RANGE(scrolledWindow
->vscrollbar
)) 
2216             value 
= (int)(win
->m_vAdjust
->value
+0.5); 
2220         wxScrollWinEvent 
event( command
, value
, dir 
); 
2221         event
.SetEventObject( win 
); 
2222         win
->GetEventHandler()->ProcessEvent( event 
); 
2225     win
->m_isScrolling 
= false; 
2231 // ---------------------------------------------------------------------------- 
2232 // this wxWindowBase function is implemented here (in platform-specific file) 
2233 // because it is static and so couldn't be made virtual 
2234 // ---------------------------------------------------------------------------- 
2236 wxWindow 
*wxWindowBase::DoFindFocus() 
2238     // the cast is necessary when we compile in wxUniversal mode 
2239     return (wxWindow 
*)g_focusWindow
; 
2242 //----------------------------------------------------------------------------- 
2243 // "realize" from m_widget 
2244 //----------------------------------------------------------------------------- 
2246 /* We cannot set colours and fonts before the widget has 
2247    been realized, so we do this directly after realization. */ 
2251 gtk_window_realized_callback( GtkWidget 
*m_widget
, wxWindow 
*win 
) 
2256         wxapp_install_idle_handler(); 
2260         GtkPizza 
*pizza 
= GTK_PIZZA( m_widget 
); 
2261         gtk_im_context_set_client_window( win
->m_imData
->context
, 
2262                                           pizza
->bin_window 
); 
2265     wxWindowCreateEvent 
event( win 
); 
2266     event
.SetEventObject( win 
); 
2267     win
->GetEventHandler()->ProcessEvent( event 
); 
2271 //----------------------------------------------------------------------------- 
2273 //----------------------------------------------------------------------------- 
2277 void gtk_window_size_callback( GtkWidget 
*WXUNUSED(widget
), 
2278                                GtkAllocation 
*WXUNUSED(alloc
), 
2282         wxapp_install_idle_handler(); 
2284     if (!win
->m_hasScrolling
) return; 
2286     int client_width 
= 0; 
2287     int client_height 
= 0; 
2288     win
->GetClientSize( &client_width
, &client_height 
); 
2289     if ((client_width 
== win
->m_oldClientWidth
) && (client_height 
== win
->m_oldClientHeight
)) 
2292     win
->m_oldClientWidth 
= client_width
; 
2293     win
->m_oldClientHeight 
= client_height
; 
2295     if (!win
->m_nativeSizeEvent
) 
2297         wxSizeEvent 
event( win
->GetSize(), win
->GetId() ); 
2298         event
.SetEventObject( win 
); 
2299         win
->GetEventHandler()->ProcessEvent( event 
); 
2306     #define WXUNUSED_UNLESS_XIM(param)  param 
2308     #define WXUNUSED_UNLESS_XIM(param)  WXUNUSED(param) 
2311 /* Resize XIM window */ 
2315 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
), 
2316                                  GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
), 
2317                                  wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) ) 
2320         wxapp_install_idle_handler(); 
2326     if  (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
) 
2330         gdk_window_get_size (widget
->window
, &width
, &height
); 
2331         win
->m_icattr
->preedit_area
.width 
= width
; 
2332         win
->m_icattr
->preedit_area
.height 
= height
; 
2333         gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
); 
2339 //----------------------------------------------------------------------------- 
2340 // "realize" from m_wxwindow 
2341 //----------------------------------------------------------------------------- 
2343 /* Initialize XIM support */ 
2347 gtk_wxwindow_realized_callback( GtkWidget 
* WXUNUSED_UNLESS_XIM(widget
), 
2348                                 wxWindowGTK 
* WXUNUSED_UNLESS_XIM(win
) ) 
2351         wxapp_install_idle_handler(); 
2354     if (win
->m_ic
) return; 
2355     if (!widget
) return; 
2356     if (!gdk_im_ready()) return; 
2358     win
->m_icattr 
= gdk_ic_attr_new(); 
2359     if (!win
->m_icattr
) return; 
2363     GdkColormap 
*colormap
; 
2364     GdkICAttr 
*attr 
= win
->m_icattr
; 
2365     unsigned attrmask 
= GDK_IC_ALL_REQ
; 
2367     GdkIMStyle supported_style 
= (GdkIMStyle
) 
2368                                   (GDK_IM_PREEDIT_NONE 
| 
2369                                    GDK_IM_PREEDIT_NOTHING 
| 
2370                                    GDK_IM_PREEDIT_POSITION 
| 
2371                                    GDK_IM_STATUS_NONE 
| 
2372                                    GDK_IM_STATUS_NOTHING
); 
2374     if (widget
->style 
&& widget
->style
->font
->type 
!= GDK_FONT_FONTSET
) 
2375         supported_style 
= (GdkIMStyle
)(supported_style 
& ~GDK_IM_PREEDIT_POSITION
); 
2377     attr
->style 
= style 
= gdk_im_decide_style (supported_style
); 
2378     attr
->client_window 
= widget
->window
; 
2380     if ((colormap 
= gtk_widget_get_colormap (widget
)) != 
2381             gtk_widget_get_default_colormap ()) 
2383         attrmask 
|= GDK_IC_PREEDIT_COLORMAP
; 
2384         attr
->preedit_colormap 
= colormap
; 
2387     attrmask 
|= GDK_IC_PREEDIT_FOREGROUND
; 
2388     attrmask 
|= GDK_IC_PREEDIT_BACKGROUND
; 
2389     attr
->preedit_foreground 
= widget
->style
->fg
[GTK_STATE_NORMAL
]; 
2390     attr
->preedit_background 
= widget
->style
->base
[GTK_STATE_NORMAL
]; 
2392     switch (style 
& GDK_IM_PREEDIT_MASK
) 
2394         case GDK_IM_PREEDIT_POSITION
: 
2395             if (widget
->style 
&& widget
->style
->font
->type 
!= GDK_FONT_FONTSET
) 
2397                 g_warning ("over-the-spot style requires fontset"); 
2401             gdk_window_get_size (widget
->window
, &width
, &height
); 
2403             attrmask 
|= GDK_IC_PREEDIT_POSITION_REQ
; 
2404             attr
->spot_location
.x 
= 0; 
2405             attr
->spot_location
.y 
= height
; 
2406             attr
->preedit_area
.x 
= 0; 
2407             attr
->preedit_area
.y 
= 0; 
2408             attr
->preedit_area
.width 
= width
; 
2409             attr
->preedit_area
.height 
= height
; 
2410             attr
->preedit_fontset 
= widget
->style
->font
; 
2415       win
->m_ic 
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
); 
2417       if (win
->m_ic 
== NULL
) 
2418           g_warning ("Can't create input context."); 
2421           mask 
= gdk_window_get_events (widget
->window
); 
2422           mask 
= (GdkEventMask
)(mask 
| gdk_ic_get_events (win
->m_ic
)); 
2423           gdk_window_set_events (widget
->window
, mask
); 
2425           if (GTK_WIDGET_HAS_FOCUS(widget
)) 
2426               gdk_im_begin (win
->m_ic
, widget
->window
); 
2432 //----------------------------------------------------------------------------- 
2433 // InsertChild for wxWindowGTK. 
2434 //----------------------------------------------------------------------------- 
2436 /* Callback for wxWindowGTK. This very strange beast has to be used because 
2437  * C++ has no virtual methods in a constructor. We have to emulate a 
2438  * virtual function here as wxNotebook requires a different way to insert 
2439  * a child in it. I had opted for creating a wxNotebookPage window class 
2440  * which would have made this superfluous (such in the MDI window system), 
2441  * but no-one was listening to me... */ 
2443 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child 
) 
2445     /* the window might have been scrolled already, do we 
2446        have to adapt the position */ 
2447     GtkPizza 
*pizza 
= GTK_PIZZA(parent
->m_wxwindow
); 
2448     child
->m_x 
+= pizza
->xoffset
; 
2449     child
->m_y 
+= pizza
->yoffset
; 
2451     gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
), 
2452                      GTK_WIDGET(child
->m_widget
), 
2459 //----------------------------------------------------------------------------- 
2461 //----------------------------------------------------------------------------- 
2463 wxWindow 
*wxGetActiveWindow() 
2465     return wxWindow::FindFocus(); 
2469 wxMouseState 
wxGetMouseState() 
2475     GdkModifierType mask
; 
2477     gdk_window_get_pointer(NULL
, &x
, &y
, &mask
); 
2481     ms
.SetLeftDown(mask 
& GDK_BUTTON1_MASK
); 
2482     ms
.SetMiddleDown(mask 
& GDK_BUTTON2_MASK
); 
2483     ms
.SetRightDown(mask 
& GDK_BUTTON3_MASK
); 
2485     ms
.SetControlDown(mask 
& GDK_CONTROL_MASK
); 
2486     ms
.SetShiftDown(mask 
& GDK_SHIFT_MASK
); 
2487     ms
.SetAltDown(mask 
& GDK_MOD1_MASK
); 
2488     ms
.SetMetaDown(mask 
& GDK_MOD2_MASK
); 
2493 //----------------------------------------------------------------------------- 
2495 //----------------------------------------------------------------------------- 
2497 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu() 
2499 #ifdef __WXUNIVERSAL__ 
2500     IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
) 
2502     IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
) 
2503 #endif // __WXUNIVERSAL__/__WXGTK__ 
2505 void wxWindowGTK::Init() 
2508     m_widget 
= (GtkWidget 
*) NULL
; 
2509     m_wxwindow 
= (GtkWidget 
*) NULL
; 
2510     m_focusWidget 
= (GtkWidget 
*) NULL
; 
2520     m_needParent 
= true; 
2521     m_isBeingDeleted 
= false; 
2524     m_nativeSizeEvent 
= false; 
2526     m_hasScrolling 
= false; 
2527     m_isScrolling 
= false; 
2529     m_hAdjust 
= (GtkAdjustment
*) NULL
; 
2530     m_vAdjust 
= (GtkAdjustment
*) NULL
; 
2531     m_oldHorizontalPos 
= 
2532     m_oldVerticalPos 
= 0.0; 
2534     m_oldClientHeight 
= 0; 
2538     m_insertCallback 
= (wxInsertChildFunction
) NULL
; 
2540     m_acceptsFocus 
= false; 
2543     m_clipPaintRegion 
= false; 
2545     m_needsStyleChange 
= false; 
2547     m_cursor 
= *wxSTANDARD_CURSOR
; 
2550     m_dirtyTabOrder 
= false; 
2553 wxWindowGTK::wxWindowGTK() 
2558 wxWindowGTK::wxWindowGTK( wxWindow 
*parent
, 
2563                           const wxString 
&name  
) 
2567     Create( parent
, id
, pos
, size
, style
, name 
); 
2570 bool wxWindowGTK::Create( wxWindow 
*parent
, 
2575                           const wxString 
&name  
) 
2577     if (!PreCreation( parent
, pos
, size 
) || 
2578         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
2580         wxFAIL_MSG( wxT("wxWindowGTK creation failed") ); 
2584     m_insertCallback 
= wxInsertChildInWindow
; 
2586     m_widget 
= gtk_scrolled_window_new( (GtkAdjustment 
*) NULL
, (GtkAdjustment 
*) NULL 
); 
2587     GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
2589     GtkScrolledWindow 
*scrolledWindow 
= GTK_SCROLLED_WINDOW(m_widget
); 
2591     GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) ); 
2592     scroll_class
->scrollbar_spacing 
= 0; 
2594     gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC 
); 
2596     m_hAdjust 
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) ); 
2597     m_vAdjust 
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) ); 
2599     m_wxwindow 
= gtk_pizza_new(); 
2601 #ifndef __WXUNIVERSAL__ 
2602     GtkPizza 
*pizza 
= GTK_PIZZA(m_wxwindow
); 
2604     if (HasFlag(wxRAISED_BORDER
)) 
2606         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT 
); 
2608     else if (HasFlag(wxSUNKEN_BORDER
)) 
2610         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN 
); 
2612     else if (HasFlag(wxSIMPLE_BORDER
)) 
2614         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN 
); 
2618         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE 
); 
2620 #endif // __WXUNIVERSAL__ 
2622     gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow 
); 
2624     GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS 
); 
2625     m_acceptsFocus 
= true; 
2627     // I _really_ don't want scrollbars in the beginning 
2628     m_vAdjust
->lower 
= 0.0; 
2629     m_vAdjust
->upper 
= 1.0; 
2630     m_vAdjust
->value 
= 0.0; 
2631     m_vAdjust
->step_increment 
= 1.0; 
2632     m_vAdjust
->page_increment 
= 1.0; 
2633     m_vAdjust
->page_size 
= 5.0; 
2634     g_signal_emit_by_name (m_vAdjust
, "changed"); 
2635     m_hAdjust
->lower 
= 0.0; 
2636     m_hAdjust
->upper 
= 1.0; 
2637     m_hAdjust
->value 
= 0.0; 
2638     m_hAdjust
->step_increment 
= 1.0; 
2639     m_hAdjust
->page_increment 
= 1.0; 
2640     m_hAdjust
->page_size 
= 5.0; 
2641     g_signal_emit_by_name (m_hAdjust
, "changed"); 
2643     // these handlers block mouse events to any window during scrolling such as 
2644     // motion events and prevent GTK and wxWidgets from fighting over where the 
2646     g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event", 
2647                       G_CALLBACK (gtk_scrollbar_button_press_callback
), this); 
2648     g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event", 
2649                       G_CALLBACK (gtk_scrollbar_button_press_callback
), this); 
2650     g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event", 
2651                       G_CALLBACK (gtk_scrollbar_button_release_callback
), this); 
2652     g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event", 
2653                       G_CALLBACK (gtk_scrollbar_button_release_callback
), this); 
2655     // these handlers get notified when screen updates are required either when 
2656     // scrolling or when the window size (and therefore scrollbar configuration) 
2659     g_signal_connect (m_hAdjust
, "value_changed", 
2660                       G_CALLBACK (gtk_window_hscroll_callback
), this); 
2661     g_signal_connect (m_vAdjust
, "value_changed", 
2662                       G_CALLBACK (gtk_window_vscroll_callback
), this); 
2664     gtk_widget_show( m_wxwindow 
); 
2667         m_parent
->DoAddChild( this ); 
2669     m_focusWidget 
= m_wxwindow
; 
2676 wxWindowGTK::~wxWindowGTK() 
2680     if (g_focusWindow 
== this) 
2681         g_focusWindow 
= NULL
; 
2683     if ( g_delayedFocus 
== this ) 
2684         g_delayedFocus 
= NULL
; 
2686     m_isBeingDeleted 
= true; 
2689     // destroy children before destroying this window itself 
2692     // unhook focus handlers to prevent stray events being 
2693     // propagated to this (soon to be) dead object 
2694     if (m_focusWidget 
!= NULL
) 
2696         g_signal_handlers_disconnect_by_func (m_focusWidget
, 
2697                                               (gpointer
) gtk_window_focus_in_callback
, 
2699         g_signal_handlers_disconnect_by_func (m_focusWidget
, 
2700                                               (gpointer
) gtk_window_focus_out_callback
, 
2709         gdk_ic_destroy (m_ic
); 
2711         gdk_ic_attr_destroy (m_icattr
); 
2714     // delete before the widgets to avoid a crash on solaris 
2719         gtk_widget_destroy( m_wxwindow 
); 
2720         m_wxwindow 
= (GtkWidget
*) NULL
; 
2725         gtk_widget_destroy( m_widget 
); 
2726         m_widget 
= (GtkWidget
*) NULL
; 
2730 bool wxWindowGTK::PreCreation( wxWindowGTK 
*parent
, const wxPoint 
&pos
,  const wxSize 
&size 
) 
2732     wxCHECK_MSG( !m_needParent 
|| parent
, false, wxT("Need complete parent.") ); 
2734     // Use either the given size, or the default if -1 is given. 
2735     // See wxWindowBase for these functions. 
2736     m_width 
= WidthDefault(size
.x
) ; 
2737     m_height 
= HeightDefault(size
.y
); 
2745 void wxWindowGTK::PostCreation() 
2747     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2753             // these get reported to wxWidgets -> wxPaintEvent 
2755             gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE 
); 
2757             g_signal_connect (m_wxwindow
, "expose_event", 
2758                               G_CALLBACK (gtk_window_expose_callback
), this); 
2760             gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE 
) ); 
2763         // Create input method handler 
2764         m_imData 
= new wxGtkIMData
; 
2766         // Cannot handle drawing preedited text yet 
2767         gtk_im_context_set_use_preedit( m_imData
->context
, FALSE 
); 
2769         g_signal_connect (m_imData
->context
, "commit", 
2770                           G_CALLBACK (gtk_wxwindow_commit_cb
), this); 
2772         // these are called when the "sunken" or "raised" borders are drawn 
2773         g_signal_connect (m_widget
, "expose_event", 
2774                           G_CALLBACK (gtk_window_own_expose_callback
), this); 
2779     if (!GTK_IS_WINDOW(m_widget
)) 
2781         if (m_focusWidget 
== NULL
) 
2782             m_focusWidget 
= m_widget
; 
2786             g_signal_connect (m_focusWidget
, "focus_in_event", 
2787                           G_CALLBACK (gtk_window_focus_in_callback
), this); 
2788             g_signal_connect (m_focusWidget
, "focus_out_event", 
2789                                 G_CALLBACK (gtk_window_focus_out_callback
), this); 
2793             g_signal_connect_after (m_focusWidget
, "focus_in_event", 
2794                           G_CALLBACK (gtk_window_focus_in_callback
), this); 
2795             g_signal_connect_after (m_focusWidget
, "focus_out_event", 
2796                                 G_CALLBACK (gtk_window_focus_out_callback
), this); 
2800     // connect to the various key and mouse handlers 
2802     GtkWidget 
*connect_widget 
= GetConnectWidget(); 
2804     ConnectWidget( connect_widget 
); 
2806     /* We cannot set colours, fonts and cursors before the widget has 
2807        been realized, so we do this directly after realization */ 
2808     g_signal_connect (connect_widget
, "realize", 
2809                       G_CALLBACK (gtk_window_realized_callback
), this); 
2813         // Catch native resize events 
2814         g_signal_connect (m_wxwindow
, "size_allocate", 
2815                           G_CALLBACK (gtk_window_size_callback
), this); 
2817         // Initialize XIM support 
2818         g_signal_connect (m_wxwindow
, "realize", 
2819                           G_CALLBACK (gtk_wxwindow_realized_callback
), this); 
2821         // And resize XIM window 
2822         g_signal_connect (m_wxwindow
, "size_allocate", 
2823                           G_CALLBACK (gtk_wxwindow_size_callback
), this); 
2826     if (GTK_IS_COMBO(m_widget
)) 
2828         GtkCombo 
*gcombo 
= GTK_COMBO(m_widget
); 
2830         g_signal_connect (gcombo
->entry
, "size_request", 
2831                           G_CALLBACK (wxgtk_combo_size_request_callback
), 
2836         // This is needed if we want to add our windows into native 
2837         // GTK controls, such as the toolbar. With this callback, the 
2838         // toolbar gets to know the correct size (the one set by the 
2839         // programmer). Sadly, it misbehaves for wxComboBox. 
2840         g_signal_connect (m_widget
, "size_request", 
2841                           G_CALLBACK (wxgtk_window_size_request_callback
), 
2845     InheritAttributes(); 
2849     // unless the window was created initially hidden (i.e. Hide() had been 
2850     // called before Create()), we should show it at GTK+ level as well 
2852         gtk_widget_show( m_widget 
); 
2855 void wxWindowGTK::ConnectWidget( GtkWidget 
*widget 
) 
2857     g_signal_connect (widget
, "key_press_event", 
2858                       G_CALLBACK (gtk_window_key_press_callback
), this); 
2859     g_signal_connect (widget
, "key_release_event", 
2860                       G_CALLBACK (gtk_window_key_release_callback
), this); 
2861     g_signal_connect (widget
, "button_press_event", 
2862                       G_CALLBACK (gtk_window_button_press_callback
), this); 
2863     g_signal_connect (widget
, "button_release_event", 
2864                       G_CALLBACK (gtk_window_button_release_callback
), this); 
2865     g_signal_connect (widget
, "motion_notify_event", 
2866                       G_CALLBACK (gtk_window_motion_notify_callback
), this); 
2867     g_signal_connect (widget
, "scroll_event", 
2868                       G_CALLBACK (gtk_window_wheel_callback
), this); 
2869     g_signal_connect (widget
, "popup_menu", 
2870                      G_CALLBACK (wxgtk_window_popup_menu_callback
), this); 
2871     g_signal_connect (widget
, "enter_notify_event", 
2872                       G_CALLBACK (gtk_window_enter_callback
), this); 
2873     g_signal_connect (widget
, "leave_notify_event", 
2874                       G_CALLBACK (gtk_window_leave_callback
), this); 
2877 bool wxWindowGTK::Destroy() 
2879     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2883     return wxWindowBase::Destroy(); 
2886 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
) 
2888     gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height 
); 
2891 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
2893     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2894     wxASSERT_MSG( (m_parent 
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") ); 
2897     printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height ); 
2900     if (m_resizing
) return; /* I don't like recursions */ 
2903     int currentX
, currentY
; 
2904     GetPosition(¤tX
, ¤tY
); 
2905     if (x 
== -1 && !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
2907     if (y 
== -1 && !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
2909     AdjustForParentClientOrigin(x
, y
, sizeFlags
); 
2911     // calculate the best size if we should auto size the window 
2912     if ( ((sizeFlags 
& wxSIZE_AUTO_WIDTH
) && width 
== -1) || 
2913          ((sizeFlags 
& wxSIZE_AUTO_HEIGHT
) && height 
== -1) ) 
2915         const wxSize sizeBest 
= GetBestSize(); 
2916         if ( (sizeFlags 
& wxSIZE_AUTO_WIDTH
) && width 
== -1 ) 
2918         if ( (sizeFlags 
& wxSIZE_AUTO_HEIGHT
) && height 
== -1 ) 
2919             height 
= sizeBest
.y
; 
2927     int minWidth  
= GetMinWidth(), 
2928         minHeight 
= GetMinHeight(), 
2929         maxWidth  
= GetMaxWidth(), 
2930         maxHeight 
= GetMaxHeight(); 
2932     if ((minWidth  
!= -1) && (m_width  
< minWidth 
)) m_width  
= minWidth
; 
2933     if ((minHeight 
!= -1) && (m_height 
< minHeight
)) m_height 
= minHeight
; 
2934     if ((maxWidth  
!= -1) && (m_width  
> maxWidth 
)) m_width  
= maxWidth
; 
2935     if ((maxHeight 
!= -1) && (m_height 
> maxHeight
)) m_height 
= maxHeight
; 
2937 #if wxUSE_TOOLBAR_NATIVE 
2938     if (wxDynamicCast(GetParent(), wxToolBar
)) 
2940        // don't take the x,y values, they're wrong because toolbar sets them 
2941        GtkWidget  
*widget 
= GTK_WIDGET(m_widget
); 
2942        gtk_widget_set_size_request (widget
, m_width
, m_height
); 
2943        if (GTK_WIDGET_VISIBLE (widget
)) 
2944             gtk_widget_queue_resize (widget
); 
2948     if (m_parent
->m_wxwindow 
== NULL
) // i.e. wxNotebook 
2950         // don't set the size for children of wxNotebook, just take the values. 
2958         GtkPizza 
*pizza 
= GTK_PIZZA(m_parent
->m_wxwindow
); 
2959         if ((sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
) == 0) 
2961             if (x 
!= -1) m_x 
= x 
+ pizza
->xoffset
; 
2962             if (y 
!= -1) m_y 
= y 
+ pizza
->yoffset
; 
2966             m_x 
= x 
+ pizza
->xoffset
; 
2967             m_y 
= y 
+ pizza
->yoffset
; 
2970         int left_border 
= 0; 
2971         int right_border 
= 0; 
2973         int bottom_border 
= 0; 
2975         /* the default button has a border around it */ 
2976         if (GTK_WIDGET_CAN_DEFAULT(m_widget
)) 
2978             GtkBorder 
*default_border 
= NULL
; 
2979             gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL 
); 
2982                 left_border 
+= default_border
->left
; 
2983                 right_border 
+= default_border
->right
; 
2984                 top_border 
+= default_border
->top
; 
2985                 bottom_border 
+= default_border
->bottom
; 
2986                 g_free( default_border 
); 
2990         DoMoveWindow( m_x
-top_border
, 
2992                       m_width
+left_border
+right_border
, 
2993                       m_height
+top_border
+bottom_border 
); 
2998         /* Sometimes the client area changes size without the 
2999            whole windows's size changing, but if the whole 
3000            windows's size doesn't change, no wxSizeEvent will 
3001            normally be sent. Here we add an extra test if 
3002            the client test has been changed and this will 
3004         GetClientSize( &m_oldClientWidth
, &m_oldClientHeight 
); 
3008     wxPrintf( "OnSize sent from " ); 
3009     if (GetClassInfo() && GetClassInfo()->GetClassName()) 
3010         wxPrintf( GetClassInfo()->GetClassName() ); 
3011     wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height ); 
3014     if (!m_nativeSizeEvent
) 
3016         wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
3017         event
.SetEventObject( this ); 
3018         GetEventHandler()->ProcessEvent( event 
); 
3024 void wxWindowGTK::OnInternalIdle() 
3026     if ( m_dirtyTabOrder 
) 
3028         m_dirtyTabOrder 
= false; 
3032     // Update style if the window was not yet realized 
3033     // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called 
3034     if (m_needsStyleChange
) 
3036         SetBackgroundStyle(GetBackgroundStyle()); 
3037         m_needsStyleChange 
= false; 
3040     // Update invalidated regions. 
3043     wxCursor cursor 
= m_cursor
; 
3044     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
3048         /* I now set the cursor anew in every OnInternalIdle call 
3049            as setting the cursor in a parent window also effects the 
3050            windows above so that checking for the current cursor is 
3055             GdkWindow 
*window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3057                 gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
3059             if (!g_globalCursor
.Ok()) 
3060                 cursor 
= *wxSTANDARD_CURSOR
; 
3062             window 
= m_widget
->window
; 
3063             if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
))) 
3064                 gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
3070             GdkWindow 
*window 
= m_widget
->window
; 
3071             if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
))) 
3072                gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
3077     if (wxUpdateUIEvent::CanUpdate(this)) 
3078         UpdateWindowUI(wxUPDATE_UI_FROMIDLE
); 
3081 void wxWindowGTK::DoGetSize( int *width
, int *height 
) const 
3083     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3085     if (width
) (*width
) = m_width
; 
3086     if (height
) (*height
) = m_height
; 
3089 void wxWindowGTK::DoSetClientSize( int width
, int height 
) 
3091     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3095         SetSize( width
, height 
); 
3102 #ifndef __WXUNIVERSAL__ 
3103         if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
)) 
3105             /* when using GTK 1.2 we set the shadow border size to 2 */ 
3109         if (HasFlag(wxSIMPLE_BORDER
)) 
3111             /* when using GTK 1.2 we set the simple border size to 1 */ 
3115 #endif // __WXUNIVERSAL__ 
3119             GtkScrolledWindow 
*scroll_window 
= GTK_SCROLLED_WINDOW(m_widget
); 
3121             GtkRequisition vscroll_req
; 
3122             vscroll_req
.width 
= 2; 
3123             vscroll_req
.height 
= 2; 
3124             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request 
) 
3125                 (scroll_window
->vscrollbar
, &vscroll_req 
); 
3127             GtkRequisition hscroll_req
; 
3128             hscroll_req
.width 
= 2; 
3129             hscroll_req
.height 
= 2; 
3130             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request 
) 
3131                 (scroll_window
->hscrollbar
, &hscroll_req 
); 
3133             GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) ); 
3135             if (scroll_window
->vscrollbar_visible
) 
3137                 dw 
+= vscroll_req
.width
; 
3138                 dw 
+= scroll_class
->scrollbar_spacing
; 
3141             if (scroll_window
->hscrollbar_visible
) 
3143                 dh 
+= hscroll_req
.height
; 
3144                 dh 
+= scroll_class
->scrollbar_spacing
; 
3148        SetSize( width
+dw
, height
+dh 
); 
3152 void wxWindowGTK::DoGetClientSize( int *width
, int *height 
) const 
3154     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3158         if (width
) (*width
) = m_width
; 
3159         if (height
) (*height
) = m_height
; 
3166 #ifndef __WXUNIVERSAL__ 
3167         if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
)) 
3169             /* when using GTK 1.2 we set the shadow border size to 2 */ 
3173         if (HasFlag(wxSIMPLE_BORDER
)) 
3175             /* when using GTK 1.2 we set the simple border size to 1 */ 
3179 #endif // __WXUNIVERSAL__ 
3183             GtkScrolledWindow 
*scroll_window 
= GTK_SCROLLED_WINDOW(m_widget
); 
3185             GtkRequisition vscroll_req
; 
3186             vscroll_req
.width 
= 2; 
3187             vscroll_req
.height 
= 2; 
3188             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request 
) 
3189                 (scroll_window
->vscrollbar
, &vscroll_req 
); 
3191             GtkRequisition hscroll_req
; 
3192             hscroll_req
.width 
= 2; 
3193             hscroll_req
.height 
= 2; 
3194             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request 
) 
3195                 (scroll_window
->hscrollbar
, &hscroll_req 
); 
3197             GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) ); 
3199             if (scroll_window
->vscrollbar_visible
) 
3201                 dw 
+= vscroll_req
.width
; 
3202                 dw 
+= scroll_class
->scrollbar_spacing
; 
3205             if (scroll_window
->hscrollbar_visible
) 
3207                 dh 
+= hscroll_req
.height
; 
3208                 dh 
+= scroll_class
->scrollbar_spacing
; 
3212         if (width
) (*width
) = m_width 
- dw
; 
3213         if (height
) (*height
) = m_height 
- dh
; 
3217     printf( "GetClientSize, name %s ", GetName().c_str() ); 
3218     if (width) printf( " width = %d", (*width) ); 
3219     if (height) printf( " height = %d", (*height) ); 
3224 void wxWindowGTK::DoGetPosition( int *x
, int *y 
) const 
3226     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3230     if (m_parent 
&& m_parent
->m_wxwindow
) 
3232         GtkPizza 
*pizza 
= GTK_PIZZA(m_parent
->m_wxwindow
); 
3233         dx 
= pizza
->xoffset
; 
3234         dy 
= pizza
->yoffset
; 
3237     if (x
) (*x
) = m_x 
- dx
; 
3238     if (y
) (*y
) = m_y 
- dy
; 
3241 void wxWindowGTK::DoClientToScreen( int *x
, int *y 
) const 
3243     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3245     if (!m_widget
->window
) return; 
3247     GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
3249         source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3251         source 
= m_widget
->window
; 
3255     gdk_window_get_origin( source
, &org_x
, &org_y 
); 
3259         if (GTK_WIDGET_NO_WINDOW (m_widget
)) 
3261             org_x 
+= m_widget
->allocation
.x
; 
3262             org_y 
+= m_widget
->allocation
.y
; 
3270 void wxWindowGTK::DoScreenToClient( int *x
, int *y 
) const 
3272     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3274     if (!m_widget
->window
) return; 
3276     GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
3278         source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3280         source 
= m_widget
->window
; 
3284     gdk_window_get_origin( source
, &org_x
, &org_y 
); 
3288         if (GTK_WIDGET_NO_WINDOW (m_widget
)) 
3290             org_x 
+= m_widget
->allocation
.x
; 
3291             org_y 
+= m_widget
->allocation
.y
; 
3299 bool wxWindowGTK::Show( bool show 
) 
3301     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3303     if (!wxWindowBase::Show(show
)) 
3310         gtk_widget_show( m_widget 
); 
3312         gtk_widget_hide( m_widget 
); 
3314     wxShowEvent 
eventShow(GetId(), show
); 
3315     eventShow
.SetEventObject(this); 
3317     GetEventHandler()->ProcessEvent(eventShow
); 
3322 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
) 
3324     win
->OnParentEnable(enable
); 
3326     // Recurse, so that children have the opportunity to Do The Right Thing 
3327     // and reset colours that have been messed up by a parent's (really ancestor's) 
3329     for ( wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
3331           node 
= node
->GetNext() ) 
3333         wxWindow 
*child 
= node
->GetData(); 
3334         if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
))) 
3335             wxWindowNotifyEnable(child
, enable
); 
3339 bool wxWindowGTK::Enable( bool enable 
) 
3341     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3343     if (!wxWindowBase::Enable(enable
)) 
3349     gtk_widget_set_sensitive( m_widget
, enable 
); 
3351         gtk_widget_set_sensitive( m_wxwindow
, enable 
); 
3353     wxWindowNotifyEnable(this, enable
); 
3358 int wxWindowGTK::GetCharHeight() const 
3360     wxCHECK_MSG( (m_widget 
!= NULL
), 12, wxT("invalid window") ); 
3362     wxFont font 
= GetFont(); 
3363     wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") ); 
3365     PangoContext 
*context 
= NULL
; 
3367         context 
= gtk_widget_get_pango_context( m_widget 
); 
3372     PangoFontDescription 
*desc 
= font
.GetNativeFontInfo()->description
; 
3373     PangoLayout 
*layout 
= pango_layout_new(context
); 
3374     pango_layout_set_font_description(layout
, desc
); 
3375     pango_layout_set_text(layout
, "H", 1); 
3376     PangoLayoutLine 
*line 
= (PangoLayoutLine 
*)pango_layout_get_lines(layout
)->data
; 
3378     PangoRectangle rect
; 
3379     pango_layout_line_get_extents(line
, NULL
, &rect
); 
3381     g_object_unref( G_OBJECT( layout 
) ); 
3383     return (int) PANGO_PIXELS(rect
.height
); 
3386 int wxWindowGTK::GetCharWidth() const 
3388     wxCHECK_MSG( (m_widget 
!= NULL
), 8, wxT("invalid window") ); 
3390     wxFont font 
= GetFont(); 
3391     wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") ); 
3393     PangoContext 
*context 
= NULL
; 
3395         context 
= gtk_widget_get_pango_context( m_widget 
); 
3400     PangoFontDescription 
*desc 
= font
.GetNativeFontInfo()->description
; 
3401     PangoLayout 
*layout 
= pango_layout_new(context
); 
3402     pango_layout_set_font_description(layout
, desc
); 
3403     pango_layout_set_text(layout
, "g", 1); 
3404     PangoLayoutLine 
*line 
= (PangoLayoutLine 
*)pango_layout_get_lines(layout
)->data
; 
3406     PangoRectangle rect
; 
3407     pango_layout_line_get_extents(line
, NULL
, &rect
); 
3409     g_object_unref( G_OBJECT( layout 
) ); 
3411     return (int) PANGO_PIXELS(rect
.width
); 
3414 void wxWindowGTK::GetTextExtent( const wxString
& string
, 
3418                                  int *externalLeading
, 
3419                                  const wxFont 
*theFont 
) const 
3421     wxFont fontToUse 
= theFont 
? *theFont 
: GetFont(); 
3423     wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") ); 
3432     PangoContext 
*context 
= NULL
; 
3434         context 
= gtk_widget_get_pango_context( m_widget 
); 
3443     PangoFontDescription 
*desc 
= fontToUse
.GetNativeFontInfo()->description
; 
3444     PangoLayout 
*layout 
= pango_layout_new(context
); 
3445     pango_layout_set_font_description(layout
, desc
); 
3448         const wxCharBuffer data 
= wxConvUTF8
.cWC2MB( string 
); 
3449         pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data 
)); 
3451         const wxWCharBuffer wdata 
= wxConvLocal
.cMB2WC( string 
); 
3452         const wxCharBuffer data 
= wxConvUTF8
.cWC2MB( wdata 
); 
3453         pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data 
)); 
3457     PangoRectangle rect
; 
3458     pango_layout_get_extents(layout
, NULL
, &rect
); 
3460     if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
); 
3461     if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
); 
3464         PangoLayoutIter 
*iter 
= pango_layout_get_iter(layout
); 
3465         int baseline 
= pango_layout_iter_get_baseline(iter
); 
3466         pango_layout_iter_free(iter
); 
3467         *descent 
= *y 
- PANGO_PIXELS(baseline
); 
3469     if (externalLeading
) (*externalLeading
) = 0;  // ?? 
3471     g_object_unref( G_OBJECT( layout 
) ); 
3474 void wxWindowGTK::SetFocus() 
3476     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3479         // don't do anything if we already have focus 
3485         if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
)) 
3487             gtk_widget_grab_focus (m_wxwindow
); 
3492         if (GTK_IS_CONTAINER(m_widget
)) 
3494             gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD 
); 
3497         if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) ) 
3500             if (!GTK_WIDGET_REALIZED(m_widget
)) 
3502                 // we can't set the focus to the widget now so we remember that 
3503                 // it should be focused and will do it later, during the idle 
3504                 // time, as soon as we can 
3505                 wxLogTrace(TRACE_FOCUS
, 
3506                            _T("Delaying setting focus to %s(%s)"), 
3507                            GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3509                 g_delayedFocus 
= this; 
3513                 wxLogTrace(TRACE_FOCUS
, 
3514                            _T("Setting focus to %s(%s)"), 
3515                            GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3517                 gtk_widget_grab_focus (m_widget
); 
3522            wxLogTrace(TRACE_FOCUS
, 
3523                       _T("Can't set focus to %s(%s)"), 
3524                       GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3529 bool wxWindowGTK::AcceptsFocus() const 
3531     return m_acceptsFocus 
&& wxWindowBase::AcceptsFocus(); 
3534 bool wxWindowGTK::Reparent( wxWindowBase 
*newParentBase 
) 
3536     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3538     wxWindowGTK 
*oldParent 
= m_parent
, 
3539              *newParent 
= (wxWindowGTK 
*)newParentBase
; 
3541     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3543     if ( !wxWindowBase::Reparent(newParent
) ) 
3546     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3548     /* prevent GTK from deleting the widget arbitrarily */ 
3549     gtk_widget_ref( m_widget 
); 
3553         gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget 
); 
3556     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3560         /* insert GTK representation */ 
3561         (*(newParent
->m_insertCallback
))(newParent
, this); 
3564     /* reverse: prevent GTK from deleting the widget arbitrarily */ 
3565     gtk_widget_unref( m_widget 
); 
3570 void wxWindowGTK::DoAddChild(wxWindowGTK 
*child
) 
3572     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
3574     wxASSERT_MSG( (child 
!= NULL
), wxT("invalid child window") ); 
3576     wxASSERT_MSG( (m_insertCallback 
!= NULL
), wxT("invalid child insertion function") ); 
3581     /* insert GTK representation */ 
3582     (*m_insertCallback
)(this, child
); 
3585 void wxWindowGTK::AddChild(wxWindowBase 
*child
) 
3587     wxWindowBase::AddChild(child
); 
3588     m_dirtyTabOrder 
= true; 
3590         wxapp_install_idle_handler(); 
3593 void wxWindowGTK::RemoveChild(wxWindowBase 
*child
) 
3595     wxWindowBase::RemoveChild(child
); 
3596     m_dirtyTabOrder 
= true; 
3598         wxapp_install_idle_handler(); 
3601 void wxWindowGTK::DoMoveInTabOrder(wxWindow 
*win
, MoveKind move
) 
3603     wxWindowBase::DoMoveInTabOrder(win
, move
); 
3604     m_dirtyTabOrder 
= true; 
3606         wxapp_install_idle_handler(); 
3609 void wxWindowGTK::RealizeTabOrder() 
3613         if ( !m_children
.empty() ) 
3616             // we don't only construct the correct focus chain but also use 
3617             // this opportunity to update the mnemonic widgets for all labels 
3619             // it would be nice to extract this code from here and put it in 
3620             // stattext.cpp to reduce dependencies but there is no really easy 
3621             // way to do it unfortunately 
3622             wxStaticText 
*lastLabel 
= NULL
; 
3623 #endif // wxUSE_STATTEXT 
3625             GList 
*chain 
= NULL
; 
3627             for ( wxWindowList::const_iterator i 
= m_children
.begin(); 
3628                   i 
!= m_children
.end(); 
3631                 wxWindowGTK 
*win 
= *i
; 
3635                     if ( win
->AcceptsFocusFromKeyboard() ) 
3637                         GtkLabel 
*l 
= GTK_LABEL(lastLabel
->m_widget
); 
3638                         gtk_label_set_mnemonic_widget(l
, win
->m_widget
); 
3642                 else // check if this one is a label 
3644                     lastLabel 
= wxDynamicCast(win
, wxStaticText
); 
3646 #endif // wxUSE_STATTEXT 
3648                 chain 
= g_list_prepend(chain
, win
->m_widget
); 
3651             chain 
= g_list_reverse(chain
); 
3653             gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
); 
3658             gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
)); 
3663 void wxWindowGTK::Raise() 
3665     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3667     if (m_wxwindow 
&& m_wxwindow
->window
) 
3669         gdk_window_raise( m_wxwindow
->window 
); 
3671     else if (m_widget
->window
) 
3673         gdk_window_raise( m_widget
->window 
); 
3677 void wxWindowGTK::Lower() 
3679     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3681     if (m_wxwindow 
&& m_wxwindow
->window
) 
3683         gdk_window_lower( m_wxwindow
->window 
); 
3685     else if (m_widget
->window
) 
3687         gdk_window_lower( m_widget
->window 
); 
3691 bool wxWindowGTK::SetCursor( const wxCursor 
&cursor 
) 
3693     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3695     if (cursor 
== m_cursor
) 
3699         wxapp_install_idle_handler(); 
3701     if (cursor 
== wxNullCursor
) 
3702        return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR 
); 
3704        return wxWindowBase::SetCursor( cursor 
); 
3707 void wxWindowGTK::WarpPointer( int x
, int y 
) 
3709     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3711     // We provide this function ourselves as it is 
3712     // missing in GDK (top of this file). 
3714     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
3716         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3718         window 
= GetConnectWidget()->window
; 
3721         gdk_window_warp_pointer( window
, x
, y 
); 
3724 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
) 
3726     double value_start 
= adj
->value
; 
3727     double value 
= value_start 
+ change
; 
3728     double upper 
= adj
->upper 
- adj
->page_size
; 
3733     // Lower bound will be checked by gtk_adjustment_set_value 
3734     gtk_adjustment_set_value(adj
, value
); 
3735     return adj
->value 
!= value_start
; 
3738 bool wxWindowGTK::ScrollLines(int lines
) 
3741         m_vAdjust 
!= NULL 
&& 
3742         wxScrollAdjust(m_vAdjust
, lines 
* m_vAdjust
->step_increment
); 
3745 bool wxWindowGTK::ScrollPages(int pages
) 
3748         m_vAdjust 
!= NULL 
&& 
3749         wxScrollAdjust(m_vAdjust
, pages 
* m_vAdjust
->page_increment
); 
3752 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
) 
3754     wxASSERT(m_vAdjust 
== NULL
); 
3758 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect 
*rect 
) 
3762     if (!m_widget
->window
) 
3767         GdkRectangle gdk_rect
, 
3771             gdk_rect
.x 
= rect
->x
; 
3772             gdk_rect
.y 
= rect
->y
; 
3773             gdk_rect
.width 
= rect
->width
; 
3774             gdk_rect
.height 
= rect
->height
; 
3777         else // invalidate everything 
3782         gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE 
); 
3786 void wxWindowGTK::Update() 
3790     // when we call Update() we really want to update the window immediately on 
3791     // screen, even if it means flushing the entire queue and hence slowing down 
3792     // everything -- but it should still be done, it's just that Update() should 
3793     // be called very rarely 
3797 void wxWindowGTK::GtkUpdate() 
3799     if (m_wxwindow 
&& GTK_PIZZA(m_wxwindow
)->bin_window
) 
3800         gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE 
); 
3802     // for consistency with other platforms (and also because it's convenient 
3803     // to be able to update an entire TLW by calling Update() only once), we 
3804     // should also update all our children here 
3805     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
3807           node 
= node
->GetNext() ) 
3809         node
->GetData()->GtkUpdate(); 
3813 void wxWindowGTK::GtkSendPaintEvents() 
3817         m_updateRegion
.Clear(); 
3821     // Clip to paint region in wxClientDC 
3822     m_clipPaintRegion 
= true; 
3824     // widget to draw on 
3825     GtkPizza 
*pizza 
= GTK_PIZZA (m_wxwindow
); 
3827     if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)) 
3829         // find ancestor from which to steal background 
3830         wxWindow 
*parent 
= wxGetTopLevelParent((wxWindow 
*)this); 
3832             parent 
= (wxWindow
*)this; 
3834         if (GTK_WIDGET_MAPPED(parent
->m_widget
)) 
3836             wxRegionIterator 
upd( m_updateRegion 
); 
3840                 rect
.x 
= upd
.GetX(); 
3841                 rect
.y 
= upd
.GetY(); 
3842                 rect
.width 
= upd
.GetWidth(); 
3843                 rect
.height 
= upd
.GetHeight(); 
3845                 gtk_paint_flat_box( parent
->m_widget
->style
, 
3847                             (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
), 
3861         wxWindowDC 
dc( (wxWindow
*)this ); 
3862         dc
.SetClippingRegion( m_updateRegion 
); 
3864         wxEraseEvent 
erase_event( GetId(), &dc 
); 
3865         erase_event
.SetEventObject( this ); 
3867         GetEventHandler()->ProcessEvent(erase_event
); 
3870     wxNcPaintEvent 
nc_paint_event( GetId() ); 
3871     nc_paint_event
.SetEventObject( this ); 
3872     GetEventHandler()->ProcessEvent( nc_paint_event 
); 
3874     wxPaintEvent 
paint_event( GetId() ); 
3875     paint_event
.SetEventObject( this ); 
3876     GetEventHandler()->ProcessEvent( paint_event 
); 
3878     m_clipPaintRegion 
= false; 
3880     m_updateRegion
.Clear(); 
3883 void wxWindowGTK::ClearBackground() 
3885     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3889 void wxWindowGTK::DoSetToolTip( wxToolTip 
*tip 
) 
3891     wxWindowBase::DoSetToolTip(tip
); 
3894         m_tooltip
->Apply( (wxWindow 
*)this ); 
3897 void wxWindowGTK::ApplyToolTip( GtkTooltips 
*tips
, const wxChar 
*tip 
) 
3899     wxString 
tmp( tip 
); 
3900     gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL 
); 
3902 #endif // wxUSE_TOOLTIPS 
3904 bool wxWindowGTK::SetBackgroundColour( const wxColour 
&colour 
) 
3906     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3908     if (!wxWindowBase::SetBackgroundColour(colour
)) 
3913         // We need the pixel value e.g. for background clearing. 
3914         m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
)); 
3917     // apply style change (forceStyle=true so that new style is applied 
3918     // even if the bg colour changed from valid to wxNullColour) 
3919     if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
) 
3920         ApplyWidgetStyle(true); 
3925 bool wxWindowGTK::SetForegroundColour( const wxColour 
&colour 
) 
3927     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3929     if (!wxWindowBase::SetForegroundColour(colour
)) 
3936         // We need the pixel value e.g. for background clearing. 
3937         m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
)); 
3940     // apply style change (forceStyle=true so that new style is applied 
3941     // even if the bg colour changed from valid to wxNullColour): 
3942     ApplyWidgetStyle(true); 
3947 PangoContext 
*wxWindowGTK::GtkGetPangoDefaultContext() 
3949     return gtk_widget_get_pango_context( m_widget 
); 
3952 GtkRcStyle 
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
) 
3954     // do we need to apply any changes at all? 
3957          !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() ) 
3962     GtkRcStyle 
*style 
= gtk_rc_style_new(); 
3967             pango_font_description_copy( m_font
.GetNativeFontInfo()->description 
); 
3970     if ( m_foregroundColour
.Ok() ) 
3972         GdkColor 
*fg 
= m_foregroundColour
.GetColor(); 
3974         style
->fg
[GTK_STATE_NORMAL
] = *fg
; 
3975         style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
; 
3977         style
->fg
[GTK_STATE_PRELIGHT
] = *fg
; 
3978         style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
; 
3980         style
->fg
[GTK_STATE_ACTIVE
] = *fg
; 
3981         style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
; 
3984     if ( m_backgroundColour
.Ok() ) 
3986         GdkColor 
*bg 
= m_backgroundColour
.GetColor(); 
3988         style
->bg
[GTK_STATE_NORMAL
] = *bg
; 
3989         style
->base
[GTK_STATE_NORMAL
] = *bg
; 
3990         style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
) 
3991             (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG 
| GTK_RC_BASE
); 
3993         style
->bg
[GTK_STATE_PRELIGHT
] = *bg
; 
3994         style
->base
[GTK_STATE_PRELIGHT
] = *bg
; 
3995         style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
) 
3996             (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG 
| GTK_RC_BASE
); 
3998         style
->bg
[GTK_STATE_ACTIVE
] = *bg
; 
3999         style
->base
[GTK_STATE_ACTIVE
] = *bg
; 
4000         style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
) 
4001             (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG 
| GTK_RC_BASE
); 
4003         style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
; 
4004         style
->base
[GTK_STATE_INSENSITIVE
] = *bg
; 
4005         style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
) 
4006             (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG 
| GTK_RC_BASE
); 
4012 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
) 
4014     GtkRcStyle 
*style 
= CreateWidgetStyle(forceStyle
); 
4017         DoApplyWidgetStyle(style
); 
4018         gtk_rc_style_unref(style
); 
4021     // Style change may affect GTK+'s size calculation: 
4022     InvalidateBestSize(); 
4025 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
4028         gtk_widget_modify_style(m_wxwindow
, style
); 
4030         gtk_widget_modify_style(m_widget
, style
); 
4033 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
) 
4035     wxWindowBase::SetBackgroundStyle(style
); 
4037     if (style 
== wxBG_STYLE_CUSTOM
) 
4039         GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4041             window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4043             window 
= GetConnectWidget()->window
; 
4047             // Make sure GDK/X11 doesn't refresh the window 
4049             gdk_window_set_back_pixmap( window
, None
, False 
); 
4051             Display
* display 
= GDK_WINDOW_DISPLAY(window
); 
4054             m_needsStyleChange 
= false; 
4057             // Do in OnIdle, because the window is not yet available 
4058             m_needsStyleChange 
= true; 
4060         // Don't apply widget style, or we get a grey background 
4064         // apply style change (forceStyle=true so that new style is applied 
4065         // even if the bg colour changed from valid to wxNullColour): 
4066         ApplyWidgetStyle(true); 
4071 #if wxUSE_DRAG_AND_DROP 
4073 void wxWindowGTK::SetDropTarget( wxDropTarget 
*dropTarget 
) 
4075     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4077     GtkWidget 
*dnd_widget 
= GetConnectWidget(); 
4079     if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget 
); 
4081     if (m_dropTarget
) delete m_dropTarget
; 
4082     m_dropTarget 
= dropTarget
; 
4084     if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget 
); 
4087 #endif // wxUSE_DRAG_AND_DROP 
4089 GtkWidget
* wxWindowGTK::GetConnectWidget() 
4091     GtkWidget 
*connect_widget 
= m_widget
; 
4092     if (m_wxwindow
) connect_widget 
= m_wxwindow
; 
4094     return connect_widget
; 
4097 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow 
*window 
) 
4100         return (window 
== GTK_PIZZA(m_wxwindow
)->bin_window
); 
4102     return (window 
== m_widget
->window
); 
4105 bool wxWindowGTK::SetFont( const wxFont 
&font 
) 
4107     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
4109     if (!wxWindowBase::SetFont(font
)) 
4112     // apply style change (forceStyle=true so that new style is applied 
4113     // even if the font changed from valid to wxNullFont): 
4114     ApplyWidgetStyle(true); 
4119 void wxWindowGTK::DoCaptureMouse() 
4121     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4123     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4125         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4127         window 
= GetConnectWidget()->window
; 
4129     wxCHECK_RET( window
, _T("CaptureMouse() failed") ); 
4131     wxCursor
* cursor 
= & m_cursor
; 
4133         cursor 
= wxSTANDARD_CURSOR
; 
4135     gdk_pointer_grab( window
, FALSE
, 
4137                          (GDK_BUTTON_PRESS_MASK 
| 
4138                           GDK_BUTTON_RELEASE_MASK 
| 
4139                           GDK_POINTER_MOTION_HINT_MASK 
| 
4140                           GDK_POINTER_MOTION_MASK
), 
4142                       cursor
->GetCursor(), 
4143                       (guint32
)GDK_CURRENT_TIME 
); 
4144     g_captureWindow 
= this; 
4145     g_captureWindowHasMouse 
= true; 
4148 void wxWindowGTK::DoReleaseMouse() 
4150     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4152     wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") ); 
4154     g_captureWindow 
= (wxWindowGTK
*) NULL
; 
4156     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4158         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4160         window 
= GetConnectWidget()->window
; 
4165     gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME 
); 
4169 wxWindow 
*wxWindowBase::GetCapture() 
4171     return (wxWindow 
*)g_captureWindow
; 
4174 bool wxWindowGTK::IsRetained() const 
4179 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
, 
4180       int range
, bool refresh 
) 
4182     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4184     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4186     m_hasScrolling 
= true; 
4188     if (orient 
== wxHORIZONTAL
) 
4190         float fpos 
= (float)pos
; 
4191         float frange 
= (float)range
; 
4192         float fthumb 
= (float)thumbVisible
; 
4193         if (fpos 
> frange
-fthumb
) fpos 
= frange
-fthumb
; 
4194         if (fpos 
< 0.0) fpos 
= 0.0; 
4196         if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) && 
4197             (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2)) 
4199             SetScrollPos( orient
, pos
, refresh 
); 
4203         m_oldHorizontalPos 
= fpos
; 
4205         m_hAdjust
->lower 
= 0.0; 
4206         m_hAdjust
->upper 
= frange
; 
4207         m_hAdjust
->value 
= fpos
; 
4208         m_hAdjust
->step_increment 
= 1.0; 
4209         m_hAdjust
->page_increment 
= (float)(wxMax(fthumb
,0)); 
4210         m_hAdjust
->page_size 
= fthumb
; 
4214         float fpos 
= (float)pos
; 
4215         float frange 
= (float)range
; 
4216         float fthumb 
= (float)thumbVisible
; 
4217         if (fpos 
> frange
-fthumb
) fpos 
= frange
-fthumb
; 
4218         if (fpos 
< 0.0) fpos 
= 0.0; 
4220         if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) && 
4221             (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2)) 
4223             SetScrollPos( orient
, pos
, refresh 
); 
4227         m_oldVerticalPos 
= fpos
; 
4229         m_vAdjust
->lower 
= 0.0; 
4230         m_vAdjust
->upper 
= frange
; 
4231         m_vAdjust
->value 
= fpos
; 
4232         m_vAdjust
->step_increment 
= 1.0; 
4233         m_vAdjust
->page_increment 
= (float)(wxMax(fthumb
,0)); 
4234         m_vAdjust
->page_size 
= fthumb
; 
4237     if (orient 
== wxHORIZONTAL
) 
4238         g_signal_emit_by_name (m_hAdjust
, "changed"); 
4240         g_signal_emit_by_name (m_vAdjust
, "changed"); 
4243 void wxWindowGTK::GtkUpdateScrollbar(int orient
) 
4245     GtkAdjustment 
*adj 
= orient 
== wxHORIZONTAL 
? m_hAdjust 
: m_vAdjust
; 
4246     gpointer fn 
= orient 
== wxHORIZONTAL
 
4247             ? (gpointer
) gtk_window_hscroll_callback
 
4248             : (gpointer
) gtk_window_vscroll_callback
; 
4250     g_signal_handlers_disconnect_by_func (adj
, fn
, this); 
4251     g_signal_emit_by_name (adj
, "value_changed"); 
4252     g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this); 
4255 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) ) 
4257     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4258     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4260     GtkAdjustment 
*adj 
= orient 
== wxHORIZONTAL 
? m_hAdjust 
: m_vAdjust
; 
4262     float fpos 
= (float)pos
; 
4263     if (fpos 
> adj
->upper 
- adj
->page_size
) 
4264         fpos 
= adj
->upper 
- adj
->page_size
; 
4267     *(orient 
== wxHORIZONTAL 
? &m_oldHorizontalPos 
: &m_oldVerticalPos
) = fpos
; 
4269     if (fabs(fpos
-adj
->value
) < 0.2) 
4273     if ( m_wxwindow
->window 
) 
4278 int wxWindowGTK::GetScrollThumb( int orient 
) const 
4280     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4282     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4284     if (orient 
== wxHORIZONTAL
) 
4285         return (int)(m_hAdjust
->page_size
+0.5); 
4287         return (int)(m_vAdjust
->page_size
+0.5); 
4290 int wxWindowGTK::GetScrollPos( int orient 
) const 
4292     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4294     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4296     if (orient 
== wxHORIZONTAL
) 
4297         return (int)(m_hAdjust
->value
+0.5); 
4299         return (int)(m_vAdjust
->value
+0.5); 
4302 int wxWindowGTK::GetScrollRange( int orient 
) const 
4304     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4306     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4308     if (orient 
== wxHORIZONTAL
) 
4309         return (int)(m_hAdjust
->upper
+0.5); 
4311         return (int)(m_vAdjust
->upper
+0.5); 
4314 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) ) 
4316     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4318     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4320     // No scrolling requested. 
4321     if ((dx 
== 0) && (dy 
== 0)) return; 
4323     m_clipPaintRegion 
= true; 
4325     gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy 
); 
4327     m_clipPaintRegion 
= false; 
4330 void wxWindowGTK::SetWindowStyleFlag( long style 
) 
4332     // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already 
4333     wxWindowBase::SetWindowStyleFlag(style
); 
4336 // Find the wxWindow at the current mouse position, also returning the mouse 
4338 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
) 
4340     pt 
= wxGetMousePosition(); 
4341     wxWindow
* found 
= wxFindWindowAtPoint(pt
); 
4345 // Get the current mouse position. 
4346 wxPoint 
wxGetMousePosition() 
4348   /* This crashes when used within wxHelpContext, 
4349      so we have to use the X-specific implementation below. 
4351     GdkModifierType *mask; 
4352     (void) gdk_window_get_pointer(NULL, &x, &y, mask); 
4354     return wxPoint(x, y); 
4358     GdkWindow
* windowAtPtr 
= gdk_window_at_pointer(& x
, & y
); 
4360     Display 
*display 
= windowAtPtr 
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY(); 
4361     Window rootWindow 
= RootWindowOfScreen (DefaultScreenOfDisplay(display
)); 
4362     Window rootReturn
, childReturn
; 
4363     int rootX
, rootY
, winX
, winY
; 
4364     unsigned int maskReturn
; 
4366     XQueryPointer (display
, 
4370                    &rootX
, &rootY
, &winX
, &winY
, &maskReturn
); 
4371     return wxPoint(rootX
, rootY
); 
4375 // Needed for implementing e.g. combobox on wxGTK within a modal dialog. 
4376 void wxAddGrab(wxWindow
* window
) 
4378     gtk_grab_add( (GtkWidget
*) window
->GetHandle() ); 
4381 void wxRemoveGrab(wxWindow
* window
) 
4383     gtk_grab_remove( (GtkWidget
*) window
->GetHandle() ); 
4386 // ---------------------------------------------------------------------------- 
4388 // ---------------------------------------------------------------------------- 
4390 class wxWinModule 
: public wxModule
 
4397     DECLARE_DYNAMIC_CLASS(wxWinModule
) 
4400 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
) 
4402 bool wxWinModule::OnInit() 
4404     // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() ); 
4405     // gdk_gc_set_fill( g_eraseGC, GDK_SOLID ); 
4410 void wxWinModule::OnExit() 
4413         gdk_gc_unref( g_eraseGC 
);