1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/window.cpp 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling, Julian Smart 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  14 #define XWarpPointer XWARPPOINTER 
  17 #include "wx/window.h" 
  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" 
  55     #include "wx/thread.h" 
  61 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0 
  62 #include <gtk/gtkversion.h> 
  63 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0) 
  64 #undef GTK_DISABLE_DEPRECATED 
  67 #include "wx/gtk/private.h" 
  68 #include <gdk/gdkprivate.h> 
  69 #include <gdk/gdkkeysyms.h> 
  73 #include <gtk/gtkprivate.h> 
  75 #include "wx/gtk/win_gtk.h" 
  77 #include <pango/pangox.h> 
  83 extern GtkContainerClass 
*pizza_parent_class
; 
  85 //----------------------------------------------------------------------------- 
  86 // documentation on internals 
  87 //----------------------------------------------------------------------------- 
  90    I have been asked several times about writing some documentation about 
  91    the GTK port of wxWidgets, especially its internal structures. Obviously, 
  92    you cannot understand wxGTK without knowing a little about the GTK, but 
  93    some more information about what the wxWindow, which is the base class 
  94    for all other window classes, does seems required as well. 
  98    What does wxWindow do? It contains the common interface for the following 
  99    jobs of its descendants: 
 101    1) Define the rudimentary behaviour common to all window classes, such as 
 102    resizing, intercepting user input (so as to make it possible to use these 
 103    events for special purposes in a derived class), window names etc. 
 105    2) Provide the possibility to contain and manage children, if the derived 
 106    class is allowed to contain children, which holds true for those window 
 107    classes which do not display a native GTK widget. To name them, these 
 108    classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame- 
 109    work classes are a special case and are handled a bit differently from 
 110    the rest. The same holds true for the wxNotebook class. 
 112    3) Provide the possibility to draw into a client area of a window. This, 
 113    too, only holds true for classes that do not display a native GTK widget 
 116    4) Provide the entire mechanism for scrolling widgets. This actual inter- 
 117    face for this is usually in wxScrolledWindow, but the GTK implementation 
 120    5) A multitude of helper or extra methods for special purposes, such as 
 121    Drag'n'Drop, managing validators etc. 
 123    6) Display a border (sunken, raised, simple or none). 
 125    Normally one might expect, that one wxWidgets window would always correspond 
 126    to one GTK widget. Under GTK, there is no such allround widget that has all 
 127    the functionality. Moreover, the GTK defines a client area as a different 
 128    widget from the actual widget you are handling. Last but not least some 
 129    special classes (e.g. wxFrame) handle different categories of widgets and 
 130    still have the possibility to draw something in the client area. 
 131    It was therefore required to write a special purpose GTK widget, that would 
 132    represent a client area in the sense of wxWidgets capable to do the jobs 
 133    2), 3) and 4). I have written this class and it resides in win_gtk.c of 
 136    All windows must have a widget, with which they interact with other under- 
 137    lying GTK widgets. It is this widget, e.g. that has to be resized etc and 
 138    the wxWindow class has a member variable called m_widget which holds a 
 139    pointer to this widget. When the window class represents a GTK native widget, 
 140    this is (in most cases) the only GTK widget the class manages. E.g. the 
 141    wxStaticText class handles only a GtkLabel widget a pointer to which you 
 142    can find in m_widget (defined in wxWindow) 
 144    When the class has a client area for drawing into and for containing children 
 145    it has to handle the client area widget (of the type GtkPizza, defined in 
 146    win_gtk.c), but there could be any number of widgets, handled by a class 
 147    The common rule for all windows is only, that the widget that interacts with 
 148    the rest of GTK must be referenced in m_widget and all other widgets must be 
 149    children of this widget on the GTK level. The top-most widget, which also 
 150    represents the client area, must be in the m_wxwindow field and must be of 
 153    As I said, the window classes that display a GTK native widget only have 
 154    one widget, so in the case of e.g. the wxButton class m_widget holds a 
 155    pointer to a GtkButton widget. But windows with client areas (for drawing 
 156    and children) have a m_widget field that is a pointer to a GtkScrolled- 
 157    Window and a m_wxwindow field that is pointer to a GtkPizza and this 
 158    one is (in the GTK sense) a child of the GtkScrolledWindow. 
 160    If the m_wxwindow field is set, then all input to this widget is inter- 
 161    cepted and sent to the wxWidgets class. If not, all input to the widget 
 162    that gets pointed to by m_widget gets intercepted and sent to the class. 
 166    The design of scrolling in wxWidgets is markedly different from that offered 
 167    by the GTK itself and therefore we cannot simply take it as it is. In GTK, 
 168    clicking on a scrollbar belonging to scrolled window will inevitably move 
 169    the window. In wxWidgets, the scrollbar will only emit an event, send this 
 170    to (normally) a wxScrolledWindow and that class will call ScrollWindow() 
 171    which actually moves the window and its subchildren. Note that GtkPizza 
 172    memorizes how much it has been scrolled but that wxWidgets forgets this 
 173    so that the two coordinates systems have to be kept in synch. This is done 
 174    in various places using the pizza->xoffset and pizza->yoffset values. 
 178    Singularily the most broken code in GTK is the code that is supposed to 
 179    inform subwindows (child windows) about new positions. Very often, duplicate 
 180    events are sent without changes in size or position, equally often no 
 181    events are sent at all (All this is due to a bug in the GtkContainer code 
 182    which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores 
 183    GTK's own system and it simply waits for size events for toplevel windows 
 184    and then iterates down the respective size events to all window. This has 
 185    the disadvantage that windows might get size events before the GTK widget 
 186    actually has the reported size. This doesn't normally pose any problem, but 
 187    the OpenGL drawing routines rely on correct behaviour. Therefore, I have 
 188    added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas, 
 189    i.e. the wxGLCanvas will emit a size event, when (and not before) the X11 
 190    window that is used for OpenGL output really has that size (as reported by 
 195    If someone at some point of time feels the immense desire to have a look at, 
 196    change or attempt to optimise the Refresh() logic, this person will need an 
 197    intimate understanding of what "draw" and "expose" events are and what 
 198    they are used for, in particular when used in connection with GTK's 
 199    own windowless widgets. Beware. 
 203    Cursors, too, have been a constant source of pleasure. The main difficulty 
 204    is that a GdkWindow inherits a cursor if the programmer sets a new cursor 
 205    for the parent. To prevent this from doing too much harm, I use idle time 
 206    to set the cursor over and over again, starting from the toplevel windows 
 207    and ending with the youngest generation (speaking of parent and child windows). 
 208    Also don't forget that cursors (like much else) are connected to GdkWindows, 
 209    not GtkWidgets and that the "window" field of a GtkWidget might very well 
 210    point to the GdkWindow of the parent widget (-> "window-less widget") and 
 211    that the two obviously have very different meanings. 
 215 //----------------------------------------------------------------------------- 
 217 //----------------------------------------------------------------------------- 
 219 extern wxList     wxPendingDelete
; 
 220 extern bool       g_blockEventsOnDrag
; 
 221 extern bool       g_blockEventsOnScroll
; 
 222 extern wxCursor   g_globalCursor
; 
 224 static GdkGC 
*g_eraseGC 
= NULL
; 
 226 // mouse capture state: the window which has it and if the mouse is currently 
 228 static wxWindowGTK  
*g_captureWindow 
= (wxWindowGTK
*) NULL
; 
 229 static bool g_captureWindowHasMouse 
= false; 
 231 wxWindowGTK  
*g_focusWindow 
= (wxWindowGTK
*) NULL
; 
 233 // the last window which had the focus - this is normally never NULL (except 
 234 // if we never had focus at all) as even when g_focusWindow is NULL it still 
 235 // keeps its previous value 
 236 wxWindowGTK 
*g_focusWindowLast 
= (wxWindowGTK
*) NULL
; 
 238 // If a window get the focus set but has not been realized 
 239 // yet, defer setting the focus to idle time. 
 240 wxWindowGTK 
*g_delayedFocus 
= (wxWindowGTK
*) NULL
; 
 242 extern bool g_mainThreadLocked
; 
 244 //----------------------------------------------------------------------------- 
 246 //----------------------------------------------------------------------------- 
 251 #   define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance"); 
 253 #   define DEBUG_MAIN_THREAD 
 256 #define DEBUG_MAIN_THREAD 
 259 // the trace mask used for the focus debugging messages 
 260 #define TRACE_FOCUS _T("focus") 
 262 //----------------------------------------------------------------------------- 
 263 // missing gdk functions 
 264 //----------------------------------------------------------------------------- 
 267 gdk_window_warp_pointer (GdkWindow      
*window
, 
 272     window 
= GDK_ROOT_PARENT(); 
 274   if (!GDK_WINDOW_DESTROYED(window
)) 
 276       XWarpPointer (GDK_WINDOW_XDISPLAY(window
), 
 277                     None
,              /* not source window -> move from anywhere */ 
 278                     GDK_WINDOW_XID(window
),  /* dest window */ 
 279                     0, 0, 0, 0,        /* not source window -> move from anywhere */ 
 284 //----------------------------------------------------------------------------- 
 285 // local code (see below) 
 286 //----------------------------------------------------------------------------- 
 288 // returns the child of win which currently has focus or NULL if not found 
 290 // Note: can't be static, needed by textctrl.cpp. 
 291 wxWindow 
*wxFindFocusedChild(wxWindowGTK 
*win
) 
 293     wxWindow 
*winFocus 
= wxWindowGTK::FindFocus(); 
 295         return (wxWindow 
*)NULL
; 
 297     if ( winFocus 
== win 
) 
 298         return (wxWindow 
*)win
; 
 300     for ( wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
 302           node 
= node
->GetNext() ) 
 304         wxWindow 
*child 
= wxFindFocusedChild(node
->GetData()); 
 309     return (wxWindow 
*)NULL
; 
 312 static void draw_frame( GtkWidget 
*widget
, wxWindowGTK 
*win 
) 
 314     // wxUniversal widgets draw the borders and scrollbars themselves 
 315 #ifndef __WXUNIVERSAL__ 
 322     if (win
->m_hasScrolling
) 
 324         GtkScrolledWindow 
*scroll_window 
= GTK_SCROLLED_WINDOW(widget
); 
 326         GtkRequisition vscroll_req
; 
 327         vscroll_req
.width 
= 2; 
 328         vscroll_req
.height 
= 2; 
 329         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request 
) 
 330             (scroll_window
->vscrollbar
, &vscroll_req 
); 
 332         GtkRequisition hscroll_req
; 
 333         hscroll_req
.width 
= 2; 
 334         hscroll_req
.height 
= 2; 
 335         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request 
) 
 336             (scroll_window
->hscrollbar
, &hscroll_req 
); 
 338         GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) ); 
 340         if (scroll_window
->vscrollbar_visible
) 
 342             dw 
+= vscroll_req
.width
; 
 343             dw 
+= scroll_class
->scrollbar_spacing
; 
 346         if (scroll_window
->hscrollbar_visible
) 
 348             dh 
+= hscroll_req
.height
; 
 349             dh 
+= scroll_class
->scrollbar_spacing
; 
 355     if (GTK_WIDGET_NO_WINDOW (widget
)) 
 357         dx 
+= widget
->allocation
.x
; 
 358         dy 
+= widget
->allocation
.y
; 
 361     if (win
->HasFlag(wxRAISED_BORDER
)) 
 363         gtk_paint_shadow (widget
->style
, 
 367                           NULL
, NULL
, NULL
, // FIXME: No clipping? 
 369                           widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh 
); 
 373     if (win
->HasFlag(wxSUNKEN_BORDER
)) 
 375         gtk_paint_shadow (widget
->style
, 
 379                           NULL
, NULL
, NULL
, // FIXME: No clipping? 
 381                           widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh 
); 
 385     if (win
->HasFlag(wxSIMPLE_BORDER
)) 
 388         gc 
= gdk_gc_new( widget
->window 
); 
 389         gdk_gc_set_foreground( gc
, &widget
->style
->black 
); 
 390         gdk_draw_rectangle( widget
->window
, gc
, FALSE
, 
 392                          widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 ); 
 396 #endif // __WXUNIVERSAL__ 
 399 //----------------------------------------------------------------------------- 
 400 // "expose_event" of m_widget 
 401 //----------------------------------------------------------------------------- 
 405 gtk_window_own_expose_callback( GtkWidget 
*widget
, 
 406                                 GdkEventExpose 
*gdk_event
, 
 409     if (gdk_event
->count 
> 0) return FALSE
; 
 411     draw_frame( widget
, win 
); 
 413     (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
); 
 419 //----------------------------------------------------------------------------- 
 420 // "size_request" of m_widget 
 421 //----------------------------------------------------------------------------- 
 423 // make it extern because wxStaticText needs to disconnect this one 
 425 void wxgtk_window_size_request_callback(GtkWidget 
*widget
, 
 426                                         GtkRequisition 
*requisition
, 
 430     win
->GetSize( &w
, &h 
); 
 436     requisition
->height 
= h
; 
 437     requisition
->width 
= w
; 
 443 void wxgtk_combo_size_request_callback(GtkWidget 
*widget
, 
 444                                        GtkRequisition 
*requisition
, 
 447     // This callback is actually hooked into the text entry 
 448     // of the combo box, not the GtkHBox. 
 451     win
->GetSize( &w
, &h 
); 
 457     GtkCombo 
*gcombo 
= GTK_COMBO(win
->m_widget
); 
 459     GtkRequisition entry_req
; 
 461     entry_req
.height 
= 2; 
 462     (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request 
) 
 463         (gcombo
->button
, &entry_req 
); 
 465     requisition
->width 
= w 
- entry_req
.width
; 
 466     requisition
->height 
= entry_req
.height
; 
 470 //----------------------------------------------------------------------------- 
 471 // "expose_event" of m_wxwindow 
 472 //----------------------------------------------------------------------------- 
 476 gtk_window_expose_callback( GtkWidget 
*widget
, 
 477                             GdkEventExpose 
*gdk_event
, 
 483         wxapp_install_idle_handler(); 
 485     // This callback gets called in drawing-idle time under 
 486     // GTK 2.0, so we don't need to defer anything to idle 
 489     GtkPizza 
*pizza 
= GTK_PIZZA( widget 
); 
 490     if (gdk_event
->window 
!= pizza
->bin_window
) return FALSE
; 
 495         wxPrintf( wxT("OnExpose from ") ); 
 496         if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName()) 
 497             wxPrintf( win
->GetClassInfo()->GetClassName() ); 
 498         wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
, 
 499                                          (int)gdk_event
->area
.y
, 
 500                                          (int)gdk_event
->area
.width
, 
 501                                          (int)gdk_event
->area
.height 
); 
 506         win
->m_wxwindow
->style
, 
 510         (GdkRectangle
*) NULL
, 
 512         (char *)"button", // const_cast 
 517     win
->GetUpdateRegion() = wxRegion( gdk_event
->region 
); 
 519     win
->GtkSendPaintEvents(); 
 522     // Let parent window draw window-less widgets 
 523     (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
); 
 529 //----------------------------------------------------------------------------- 
 530 // "key_press_event" from any window 
 531 //----------------------------------------------------------------------------- 
 533 // set WXTRACE to this to see the key event codes on the console 
 534 #define TRACE_KEYS  _T("keyevent") 
 536 // translates an X key symbol to WXK_XXX value 
 538 // if isChar is true it means that the value returned will be used for EVT_CHAR 
 539 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide, 
 540 // for example, while if it is false it means that the value is going to be 
 541 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to 
 543 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
) 
 549         // Shift, Control and Alt don't generate the CHAR events at all 
 552             key_code 
= isChar 
? 0 : WXK_SHIFT
; 
 556             key_code 
= isChar 
? 0 : WXK_CONTROL
; 
 564             key_code 
= isChar 
? 0 : WXK_ALT
; 
 567         // neither do the toggle modifies 
 568         case GDK_Scroll_Lock
: 
 569             key_code 
= isChar 
? 0 : WXK_SCROLL
; 
 573             key_code 
= isChar 
? 0 : WXK_CAPITAL
; 
 577             key_code 
= isChar 
? 0 : WXK_NUMLOCK
; 
 581         // various other special keys 
 594         case GDK_ISO_Left_Tab
: 
 601             key_code 
= WXK_RETURN
; 
 605             key_code 
= WXK_CLEAR
; 
 609             key_code 
= WXK_PAUSE
; 
 613             key_code 
= WXK_SELECT
; 
 617             key_code 
= WXK_PRINT
; 
 621             key_code 
= WXK_EXECUTE
; 
 625             key_code 
= WXK_ESCAPE
; 
 628         // cursor and other extended keyboard keys 
 630             key_code 
= WXK_DELETE
; 
 646             key_code 
= WXK_RIGHT
; 
 653         case GDK_Prior
:     // == GDK_Page_Up 
 654             key_code 
= WXK_PAGEUP
; 
 657         case GDK_Next
:      // == GDK_Page_Down 
 658             key_code 
= WXK_PAGEDOWN
; 
 670             key_code 
= WXK_INSERT
; 
 685             key_code 
= (isChar 
? '0' : WXK_NUMPAD0
) + keysym 
- GDK_KP_0
; 
 689             key_code 
= isChar 
? ' ' : WXK_NUMPAD_SPACE
; 
 693             key_code 
= isChar 
? WXK_TAB 
: WXK_NUMPAD_TAB
; 
 697             key_code 
= isChar 
? WXK_RETURN 
: WXK_NUMPAD_ENTER
; 
 701             key_code 
= isChar 
? WXK_F1 
: WXK_NUMPAD_F1
; 
 705             key_code 
= isChar 
? WXK_F2 
: WXK_NUMPAD_F2
; 
 709             key_code 
= isChar 
? WXK_F3 
: WXK_NUMPAD_F3
; 
 713             key_code 
= isChar 
? WXK_F4 
: WXK_NUMPAD_F4
; 
 717             key_code 
= isChar 
? WXK_HOME 
: WXK_NUMPAD_HOME
; 
 721             key_code 
= isChar 
? WXK_LEFT 
: WXK_NUMPAD_LEFT
; 
 725             key_code 
= isChar 
? WXK_UP 
: WXK_NUMPAD_UP
; 
 729             key_code 
= isChar 
? WXK_RIGHT 
: WXK_NUMPAD_RIGHT
; 
 733             key_code 
= isChar 
? WXK_DOWN 
: WXK_NUMPAD_DOWN
; 
 736         case GDK_KP_Prior
: // == GDK_KP_Page_Up 
 737             key_code 
= isChar 
? WXK_PAGEUP 
: WXK_NUMPAD_PAGEUP
; 
 740         case GDK_KP_Next
: // == GDK_KP_Page_Down 
 741             key_code 
= isChar 
? WXK_PAGEDOWN 
: WXK_NUMPAD_PAGEDOWN
; 
 745             key_code 
= isChar 
? WXK_END 
: WXK_NUMPAD_END
; 
 749             key_code 
= isChar 
? WXK_HOME 
: WXK_NUMPAD_BEGIN
; 
 753             key_code 
= isChar 
? WXK_INSERT 
: WXK_NUMPAD_INSERT
; 
 757             key_code 
= isChar 
? WXK_DELETE 
: WXK_NUMPAD_DELETE
; 
 761             key_code 
= isChar 
? '=' : WXK_NUMPAD_EQUAL
; 
 764         case GDK_KP_Multiply
: 
 765             key_code 
= isChar 
? '*' : WXK_NUMPAD_MULTIPLY
; 
 769             key_code 
= isChar 
? '+' : WXK_NUMPAD_ADD
; 
 772         case GDK_KP_Separator
: 
 773             // FIXME: what is this? 
 774             key_code 
= isChar 
? '.' : WXK_NUMPAD_SEPARATOR
; 
 777         case GDK_KP_Subtract
: 
 778             key_code 
= isChar 
? '-' : WXK_NUMPAD_SUBTRACT
; 
 782             key_code 
= isChar 
? '.' : WXK_NUMPAD_DECIMAL
; 
 786             key_code 
= isChar 
? '/' : WXK_NUMPAD_DIVIDE
; 
 803             key_code 
= WXK_F1 
+ keysym 
- GDK_F1
; 
 813 static inline bool wxIsAsciiKeysym(KeySym ks
) 
 818 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
, 
 820                                       GdkEventKey 
*gdk_event
) 
 824     GdkModifierType state
; 
 825     if (gdk_event
->window
) 
 826         gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
 828     event
.SetTimestamp( gdk_event
->time 
); 
 829     event
.SetId(win
->GetId()); 
 830     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
) != 0; 
 831     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
) != 0; 
 832     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
) != 0; 
 833     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
) != 0; 
 834     event
.m_scanCode 
= gdk_event
->keyval
; 
 835     event
.m_rawCode 
= (wxUint32
) gdk_event
->keyval
; 
 836     event
.m_rawFlags 
= 0; 
 838     event
.m_uniChar 
= gdk_keyval_to_unicode(gdk_event
->keyval
); 
 840     wxGetMousePosition( &x
, &y 
); 
 841     win
->ScreenToClient( &x
, &y 
); 
 844     event
.SetEventObject( win 
); 
 849 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
, 
 851                            GdkEventKey 
*gdk_event
) 
 853     // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string 
 854     //     but only event->keyval which is quite useless to us, so remember 
 855     //     the last character from GDK_KEY_PRESS and reuse it as last resort 
 857     // NB: should be MT-safe as we're always called from the main thread only 
 862     } s_lastKeyPress 
= { 0, 0 }; 
 864     KeySym keysym 
= gdk_event
->keyval
; 
 866     wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"), 
 867                event
.GetEventType() == wxEVT_KEY_UP 
? _T("release") 
 871     long key_code 
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */); 
 875         // do we have the translation or is it a plain ASCII character? 
 876         if ( (gdk_event
->length 
== 1) || wxIsAsciiKeysym(keysym
) ) 
 878             // we should use keysym if it is ASCII as X does some translations 
 879             // like "I pressed while Control is down" => "Ctrl-I" == "TAB" 
 880             // which we don't want here (but which we do use for OnChar()) 
 881             if ( !wxIsAsciiKeysym(keysym
) ) 
 883                 keysym 
= (KeySym
)gdk_event
->string
[0]; 
 886             // we want to always get the same key code when the same key is 
 887             // pressed regardless of the state of the modifiers, i.e. on a 
 888             // standard US keyboard pressing '5' or '%' ('5' key with 
 889             // Shift) should result in the same key code in OnKeyDown(): 
 890             // '5' (although OnChar() will get either '5' or '%'). 
 892             // to do it we first translate keysym to keycode (== scan code) 
 893             // and then back but always using the lower register 
 894             Display 
*dpy 
= (Display 
*)wxGetDisplay(); 
 895             KeyCode keycode 
= XKeysymToKeycode(dpy
, keysym
); 
 897             wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
); 
 899             KeySym keysymNormalized 
= XKeycodeToKeysym(dpy
, keycode
, 0); 
 901             // use the normalized, i.e. lower register, keysym if we've 
 903             key_code 
= keysymNormalized 
? keysymNormalized 
: keysym
; 
 905             // as explained above, we want to have lower register key codes 
 906             // normally but for the letter keys we want to have the upper ones 
 908             // NB: don't use XConvertCase() here, we want to do it for letters 
 910             key_code 
= toupper(key_code
); 
 912         else // non ASCII key, what to do? 
 914             // by default, ignore it 
 917             // but if we have cached information from the last KEY_PRESS 
 918             if ( gdk_event
->type 
== GDK_KEY_RELEASE 
) 
 921                 if ( keysym 
== s_lastKeyPress
.keysym 
) 
 923                     key_code 
= s_lastKeyPress
.keycode
; 
 928         if ( gdk_event
->type 
== GDK_KEY_PRESS 
) 
 930             // remember it to be reused for KEY_UP event later 
 931             s_lastKeyPress
.keysym 
= keysym
; 
 932             s_lastKeyPress
.keycode 
= key_code
; 
 936     wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
); 
 938     // sending unknown key events doesn't really make sense 
 942     // now fill all the other fields 
 943     wxFillOtherKeyEventFields(event
, win
, gdk_event
); 
 945     event
.m_keyCode 
= key_code
; 
 947     if ( gdk_event
->type 
== GDK_KEY_PRESS 
||  gdk_event
->type 
== GDK_KEY_RELEASE 
) 
 949         event
.m_uniChar 
= key_code
; 
 959     GtkIMContext 
*context
; 
 960     GdkEventKey  
*lastKeyEvent
; 
 964         context 
= gtk_im_multicontext_new(); 
 969         g_object_unref(context
); 
 975 gtk_window_key_press_callback( GtkWidget 
*widget
, 
 976                                GdkEventKey 
*gdk_event
, 
 982         wxapp_install_idle_handler(); 
 986     if (g_blockEventsOnDrag
) 
 990     wxKeyEvent 
event( wxEVT_KEY_DOWN 
); 
 992     bool return_after_IM 
= false; 
 994     if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) ) 
 996         // Emit KEY_DOWN event 
 997         ret 
= win
->GetEventHandler()->ProcessEvent( event 
); 
1001         // Return after IM processing as we cannot do 
1002         // anything with it anyhow. 
1003         return_after_IM 
= true; 
1006     // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw): 
1007     // When we get a key_press event here, it could be originate 
1008     // from the current widget or its child widgets.  However, only the widget 
1009     // with the INPUT FOCUS can generate the INITIAL key_press event.  That is, 
1010     // if the CURRENT widget doesn't have the FOCUS at all, this event definitely 
1011     // originated from its child widgets and shouldn't be passed to IM context. 
1012     // In fact, what a GTK+ IM should do is filtering keyEvents and convert them 
1013     // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS.  Besides, when current 
1014     // widgets has both IM context and input focus, the event should be filtered 
1015     // by gtk_im_context_filter_keypress(). 
1016     // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns. 
1017     if ((!ret
) && (win
->m_imData 
!= NULL
) && ( wxWindow::FindFocus() == win 
)) 
1019         // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API 
1020         // docs, if IM filter returns true, no further processing should be done. 
1021         // we should send the key_down event anyway. 
1022         bool intercepted_by_IM 
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
); 
1023         win
->m_imData
->lastKeyEvent 
= NULL
; 
1024         if (intercepted_by_IM
) 
1026             wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM")); 
1031     if (return_after_IM
) 
1037         wxWindowGTK 
*ancestor 
= win
; 
1040             int command 
= ancestor
->GetAcceleratorTable()->GetCommand( event 
); 
1043                 wxCommandEvent 
command_event( wxEVT_COMMAND_MENU_SELECTED
, command 
); 
1044                 ret 
= ancestor
->GetEventHandler()->ProcessEvent( command_event 
); 
1047             if (ancestor
->IsTopLevel()) 
1049             ancestor 
= ancestor
->GetParent(); 
1052 #endif // wxUSE_ACCEL 
1054     // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x 
1055     // will only be sent if it is not in an accelerator table. 
1059         KeySym keysym 
= gdk_event
->keyval
; 
1060         // Find key code for EVT_CHAR and EVT_CHAR_HOOK events 
1061         key_code 
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */); 
1064             if ( wxIsAsciiKeysym(keysym
) ) 
1067                 key_code 
= (unsigned char)keysym
; 
1069             // gdk_event->string is actually deprecated 
1070             else if ( gdk_event
->length 
== 1 ) 
1072                 key_code 
= (unsigned char)gdk_event
->string
[0]; 
1078             wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
); 
1080             event
.m_keyCode 
= key_code
; 
1082             // To conform to the docs we need to translate Ctrl-alpha 
1083             // characters to values in the range 1-26. 
1084             if (event
.ControlDown() && key_code 
>= 'a' && key_code 
<= 'z' ) 
1086                 event
.m_keyCode 
= key_code 
- 'a' + 1; 
1088                 event
.m_uniChar 
= event
.m_keyCode
; 
1092             // Implement OnCharHook by checking ancestor top level windows 
1093             wxWindow 
*parent 
= win
; 
1094             while (parent 
&& !parent
->IsTopLevel()) 
1095                 parent 
= parent
->GetParent(); 
1098                 event
.SetEventType( wxEVT_CHAR_HOOK 
); 
1099                 ret 
= parent
->GetEventHandler()->ProcessEvent( event 
); 
1104                 event
.SetEventType(wxEVT_CHAR
); 
1105                 ret 
= win
->GetEventHandler()->ProcessEvent( event 
); 
1114     // win is a control: tab can be propagated up 
1116          ((gdk_event
->keyval 
== GDK_Tab
) || (gdk_event
->keyval 
== GDK_ISO_Left_Tab
)) && 
1117 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may 
1118 //     have this style, yet choose not to process this particular TAB in which 
1119 //     case TAB must still work as a navigational character 
1120 // JS: enabling again to make consistent with other platforms 
1121 //     (with wxTE_PROCESS_TAB you have to call Navigate to get default 
1122 //     navigation behaviour) 
1124          (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) && 
1126          win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) ) 
1128         wxNavigationKeyEvent new_event
; 
1129         new_event
.SetEventObject( win
->GetParent() ); 
1130         // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB 
1131         new_event
.SetDirection( (gdk_event
->keyval 
== GDK_Tab
) ); 
1132         // CTRL-TAB changes the (parent) window, i.e. switch notebook page 
1133         new_event
.SetWindowChange( (gdk_event
->state 
& GDK_CONTROL_MASK
) ); 
1134         new_event
.SetCurrentFocus( win 
); 
1135         ret 
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event 
); 
1138     // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) 
1140          (gdk_event
->keyval 
== GDK_Escape
) ) 
1142         // however only do it if we have a Cancel button in the dialog, 
1143         // otherwise the user code may get confused by the events from a 
1144         // non-existing button and, worse, a wxButton might get button event 
1145         // from another button which is not really expected 
1146         wxWindow 
*winForCancel 
= win
, 
1148         while ( winForCancel 
) 
1150             btnCancel 
= winForCancel
->FindWindow(wxID_CANCEL
); 
1153                 // found a cancel button 
1157             if ( winForCancel
->IsTopLevel() ) 
1159                 // no need to look further 
1163             // maybe our parent has a cancel button? 
1164             winForCancel 
= winForCancel
->GetParent(); 
1169             wxCommandEvent 
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
); 
1170             eventClick
.SetEventObject(btnCancel
); 
1171             ret 
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
); 
1177         g_signal_stop_emission_by_name (widget
, "key_press_event"); 
1187 gtk_wxwindow_commit_cb (GtkIMContext 
*context
, 
1191     wxKeyEvent 
event( wxEVT_KEY_DOWN 
); 
1193     // take modifiers, cursor position, timestamp etc. from the last 
1194     // key_press_event that was fed into Input Method: 
1195     if (window
->m_imData
->lastKeyEvent
) 
1197         wxFillOtherKeyEventFields(event
, 
1198                                   window
, window
->m_imData
->lastKeyEvent
); 
1202     const wxWCharBuffer data 
= wxConvUTF8
.cMB2WC( (char*)str 
); 
1204     const wxWCharBuffer wdata 
= wxConvUTF8
.cMB2WC( (char*)str 
); 
1205     const wxCharBuffer data 
= wxConvLocal
.cWC2MB( wdata 
); 
1206 #endif // wxUSE_UNICODE 
1207     if( !(const wxChar
*)data 
) 
1212     // Implement OnCharHook by checking ancestor top level windows 
1213     wxWindow 
*parent 
= window
; 
1214     while (parent 
&& !parent
->IsTopLevel()) 
1215         parent 
= parent
->GetParent(); 
1217     for( const wxChar
* pstr 
= data
; *pstr
; pstr
++ ) 
1220         event
.m_uniChar 
= *pstr
; 
1221         // Backward compatible for ISO-8859-1 
1222         event
.m_keyCode 
= *pstr 
< 256 ? event
.m_uniChar 
: 0; 
1223         wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
); 
1225         event
.m_keyCode 
= *pstr
; 
1226 #endif  // wxUSE_UNICODE 
1228         // To conform to the docs we need to translate Ctrl-alpha 
1229         // characters to values in the range 1-26. 
1230         if (event
.ControlDown() && *pstr 
>= 'a' && *pstr 
<= 'z' ) 
1232             event
.m_keyCode 
= *pstr 
- 'a' + 1; 
1234             event
.m_uniChar 
= event
.m_keyCode
; 
1240             event
.SetEventType( wxEVT_CHAR_HOOK 
); 
1241             ret 
= parent
->GetEventHandler()->ProcessEvent( event 
); 
1246             event
.SetEventType(wxEVT_CHAR
); 
1247             ret 
= window
->GetEventHandler()->ProcessEvent( event 
); 
1254 //----------------------------------------------------------------------------- 
1255 // "key_release_event" from any window 
1256 //----------------------------------------------------------------------------- 
1260 gtk_window_key_release_callback( GtkWidget 
*widget
, 
1261                                  GdkEventKey 
*gdk_event
, 
1267         wxapp_install_idle_handler(); 
1272     if (g_blockEventsOnDrag
) 
1275     wxKeyEvent 
event( wxEVT_KEY_UP 
); 
1276     if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) ) 
1278         // unknown key pressed, ignore (the event would be useless anyhow) 
1282     if ( !win
->GetEventHandler()->ProcessEvent( event 
) ) 
1285     g_signal_stop_emission_by_name (widget
, "key_release_event"); 
1290 // ============================================================================ 
1292 // ============================================================================ 
1294 // ---------------------------------------------------------------------------- 
1295 // mouse event processing helpers 
1296 // ---------------------------------------------------------------------------- 
1298 // init wxMouseEvent with the info from GdkEventXXX struct 
1299 template<typename T
> void InitMouseEvent(wxWindowGTK 
*win
, 
1300                                          wxMouseEvent
& event
, 
1303     event
.SetTimestamp( gdk_event
->time 
); 
1304     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
); 
1305     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
); 
1306     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
); 
1307     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
); 
1308     event
.m_leftDown 
= (gdk_event
->state 
& GDK_BUTTON1_MASK
); 
1309     event
.m_middleDown 
= (gdk_event
->state 
& GDK_BUTTON2_MASK
); 
1310     event
.m_rightDown 
= (gdk_event
->state 
& GDK_BUTTON3_MASK
); 
1311     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
1313        event
.m_linesPerAction 
= 3; 
1314        event
.m_wheelDelta 
= 120; 
1315        if (((GdkEventButton
*)gdk_event
)->button 
== 4) 
1316            event
.m_wheelRotation 
= 120; 
1317        else if (((GdkEventButton
*)gdk_event
)->button 
== 5) 
1318            event
.m_wheelRotation 
= -120; 
1321     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1322     event
.m_x 
= (wxCoord
)gdk_event
->x 
- pt
.x
; 
1323     event
.m_y 
= (wxCoord
)gdk_event
->y 
- pt
.y
; 
1325     event
.SetEventObject( win 
); 
1326     event
.SetId( win
->GetId() ); 
1327     event
.SetTimestamp( gdk_event
->time 
); 
1330 static void AdjustEventButtonState(wxMouseEvent
& event
) 
1332     // GDK reports the old state of the button for a button press event, but 
1333     // for compatibility with MSW and common sense we want m_leftDown be TRUE 
1334     // for a LEFT_DOWN event, not FALSE, so we will invert 
1335     // left/right/middleDown for the corresponding click events 
1337     if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) || 
1338         (event
.GetEventType() == wxEVT_LEFT_DCLICK
) || 
1339         (event
.GetEventType() == wxEVT_LEFT_UP
)) 
1341         event
.m_leftDown 
= !event
.m_leftDown
; 
1345     if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) || 
1346         (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) || 
1347         (event
.GetEventType() == wxEVT_MIDDLE_UP
)) 
1349         event
.m_middleDown 
= !event
.m_middleDown
; 
1353     if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) || 
1354         (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) || 
1355         (event
.GetEventType() == wxEVT_RIGHT_UP
)) 
1357         event
.m_rightDown 
= !event
.m_rightDown
; 
1362 // find the window to send the mouse event too 
1364 wxWindowGTK 
*FindWindowForMouseEvent(wxWindowGTK 
*win
, wxCoord
& x
, wxCoord
& y
) 
1369     if (win
->m_wxwindow
) 
1371         GtkPizza 
*pizza 
= GTK_PIZZA(win
->m_wxwindow
); 
1372         xx 
+= pizza
->xoffset
; 
1373         yy 
+= pizza
->yoffset
; 
1376     wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
1379         wxWindowGTK 
*child 
= node
->GetData(); 
1381         node 
= node
->GetNext(); 
1382         if (!child
->IsShown()) 
1385         if (child
->IsTransparentForMouse()) 
1387             // wxStaticBox is transparent in the box itself 
1388             int xx1 
= child
->m_x
; 
1389             int yy1 
= child
->m_y
; 
1390             int xx2 
= child
->m_x 
+ child
->m_width
; 
1391             int yy2 
= child
->m_y 
+ child
->m_height
; 
1394             if (((xx 
>= xx1
) && (xx 
<= xx1
+10) && (yy 
>= yy1
) && (yy 
<= yy2
)) || 
1396                 ((xx 
>= xx2
-10) && (xx 
<= xx2
) && (yy 
>= yy1
) && (yy 
<= yy2
)) || 
1398                 ((xx 
>= xx1
) && (xx 
<= xx2
) && (yy 
>= yy1
) && (yy 
<= yy1
+10)) || 
1400                 ((xx 
>= xx1
) && (xx 
<= xx2
) && (yy 
>= yy2
-1) && (yy 
<= yy2
))) 
1411             if ((child
->m_wxwindow 
== (GtkWidget
*) NULL
) && 
1412                 (child
->m_x 
<= xx
) && 
1413                 (child
->m_y 
<= yy
) && 
1414                 (child
->m_x
+child
->m_width  
>= xx
) && 
1415                 (child
->m_y
+child
->m_height 
>= yy
)) 
1428 //----------------------------------------------------------------------------- 
1429 // "button_press_event" 
1430 //----------------------------------------------------------------------------- 
1434 gtk_window_button_press_callback( GtkWidget 
*widget
, 
1435                                   GdkEventButton 
*gdk_event
, 
1441         wxapp_install_idle_handler(); 
1444     wxPrintf( wxT("1) OnButtonPress from ") ); 
1445     if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) 
1446         wxPrintf( win->GetClassInfo()->GetClassName() ); 
1447     wxPrintf( wxT(".\n") ); 
1449     if (!win
->m_hasVMT
) return FALSE
; 
1450     if (g_blockEventsOnDrag
) return TRUE
; 
1451     if (g_blockEventsOnScroll
) return TRUE
; 
1453     if (!win
->IsOwnGtkWindow( gdk_event
->window 
)) return FALSE
; 
1455     if (win
->m_wxwindow 
&& (g_focusWindow 
!= win
) && win
->AcceptsFocus()) 
1457         gtk_widget_grab_focus( win
->m_wxwindow 
); 
1459         wxPrintf( wxT("GrabFocus from ") ); 
1460         if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) 
1461             wxPrintf( win->GetClassInfo()->GetClassName() ); 
1462         wxPrintf( wxT(".\n") ); 
1466     // GDK sends surplus button down events 
1467     // before a double click event. We 
1468     // need to filter these out. 
1469     if (gdk_event
->type 
== GDK_BUTTON_PRESS
) 
1471         GdkEvent 
*peek_event 
= gdk_event_peek(); 
1474             if ((peek_event
->type 
== GDK_2BUTTON_PRESS
) || 
1475                 (peek_event
->type 
== GDK_3BUTTON_PRESS
)) 
1477                 gdk_event_free( peek_event 
); 
1482                 gdk_event_free( peek_event 
); 
1487     wxEventType event_type 
= wxEVT_NULL
; 
1489     // GdkDisplay is a GTK+ 2.2.0 thing 
1490 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0) 
1491     if ( gdk_event
->type 
== GDK_2BUTTON_PRESS 
&& 
1492             !gtk_check_version(2,2,0) && 
1493             gdk_event
->button 
>= 1 && gdk_event
->button 
<= 3 ) 
1495         // Reset GDK internal timestamp variables in order to disable GDK 
1496         // triple click events. GDK will then next time believe no button has 
1497         // been clicked just before, and send a normal button click event. 
1498         GdkDisplay
* display 
= gtk_widget_get_display (widget
); 
1499         display
->button_click_time
[1] = 0; 
1500         display
->button_click_time
[0] = 0; 
1504     if (gdk_event
->button 
== 1) 
1506         // note that GDK generates triple click events which are not supported 
1507         // by wxWidgets but still have to be passed to the app as otherwise 
1508         // clicks would simply go missing 
1509         switch (gdk_event
->type
) 
1511             // we shouldn't get triple clicks at all for GTK2 because we 
1512             // suppress them artificially using the code above but we still 
1513             // should map them to something for GTK1 and not just ignore them 
1514             // as this would lose clicks 
1515             case GDK_3BUTTON_PRESS
:     // we could also map this to DCLICK... 
1516             case GDK_BUTTON_PRESS
: 
1517                 event_type 
= wxEVT_LEFT_DOWN
; 
1520             case GDK_2BUTTON_PRESS
: 
1521                 event_type 
= wxEVT_LEFT_DCLICK
; 
1525                 // just to silence gcc warnings 
1529     else if (gdk_event
->button 
== 2) 
1531         switch (gdk_event
->type
) 
1533             case GDK_3BUTTON_PRESS
: 
1534             case GDK_BUTTON_PRESS
: 
1535                 event_type 
= wxEVT_MIDDLE_DOWN
; 
1538             case GDK_2BUTTON_PRESS
: 
1539                 event_type 
= wxEVT_MIDDLE_DCLICK
; 
1546     else if (gdk_event
->button 
== 3) 
1548         switch (gdk_event
->type
) 
1550             case GDK_3BUTTON_PRESS
: 
1551             case GDK_BUTTON_PRESS
: 
1552                 event_type 
= wxEVT_RIGHT_DOWN
; 
1555             case GDK_2BUTTON_PRESS
: 
1556                 event_type 
= wxEVT_RIGHT_DCLICK
; 
1563     else if (gdk_event
->button 
== 4 || gdk_event
->button 
== 5) 
1565         if (gdk_event
->type 
== GDK_BUTTON_PRESS 
) 
1567             event_type 
= wxEVT_MOUSEWHEEL
; 
1571     if ( event_type 
== wxEVT_NULL 
) 
1573         // unknown mouse button or click type 
1577     wxMouseEvent 
event( event_type 
); 
1578     InitMouseEvent( win
, event
, gdk_event 
); 
1580     AdjustEventButtonState(event
); 
1582     // wxListBox actually gets mouse events from the item, so we need to give it 
1583     // a chance to correct this 
1584     win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
); 
1586     // find the correct window to send the event to: it may be a different one 
1587     // from the one which got it at GTK+ level because some controls don't have 
1588     // their own X window and thus cannot get any events. 
1589     if ( !g_captureWindow 
) 
1590         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1592     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
1594         g_signal_stop_emission_by_name (widget
, "button_press_event"); 
1598     if (event_type 
== wxEVT_RIGHT_DOWN
) 
1600         // generate a "context menu" event: this is similar to right mouse 
1601         // click under many GUIs except that it is generated differently 
1602         // (right up under MSW, ctrl-click under Mac, right down here) and 
1604         // (a) it's a command event and so is propagated to the parent 
1605         // (b) under some ports it can be generated from kbd too 
1606         // (c) it uses screen coords (because of (a)) 
1607         wxContextMenuEvent 
evtCtx( 
1610             win
->ClientToScreen(event
.GetPosition())); 
1611         evtCtx
.SetEventObject(win
); 
1612         return win
->GetEventHandler()->ProcessEvent(evtCtx
); 
1619 //----------------------------------------------------------------------------- 
1620 // "button_release_event" 
1621 //----------------------------------------------------------------------------- 
1625 gtk_window_button_release_callback( GtkWidget 
*widget
, 
1626                                     GdkEventButton 
*gdk_event
, 
1632         wxapp_install_idle_handler(); 
1634     if (!win
->m_hasVMT
) return FALSE
; 
1635     if (g_blockEventsOnDrag
) return FALSE
; 
1636     if (g_blockEventsOnScroll
) return FALSE
; 
1638     if (!win
->IsOwnGtkWindow( gdk_event
->window 
)) return FALSE
; 
1640     wxEventType event_type 
= wxEVT_NULL
; 
1642     switch (gdk_event
->button
) 
1645             event_type 
= wxEVT_LEFT_UP
; 
1649             event_type 
= wxEVT_MIDDLE_UP
; 
1653             event_type 
= wxEVT_RIGHT_UP
; 
1657             // unknwon button, don't process 
1661     wxMouseEvent 
event( event_type 
); 
1662     InitMouseEvent( win
, event
, gdk_event 
); 
1664     AdjustEventButtonState(event
); 
1666     // same wxListBox hack as above 
1667     win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
); 
1669     if ( !g_captureWindow 
) 
1670         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1672     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
1674         g_signal_stop_emission_by_name (widget
, "button_release_event"); 
1682 //----------------------------------------------------------------------------- 
1683 // "motion_notify_event" 
1684 //----------------------------------------------------------------------------- 
1688 gtk_window_motion_notify_callback( GtkWidget 
*widget
, 
1689                                    GdkEventMotion 
*gdk_event
, 
1695         wxapp_install_idle_handler(); 
1697     if (!win
->m_hasVMT
) return FALSE
; 
1698     if (g_blockEventsOnDrag
) return FALSE
; 
1699     if (g_blockEventsOnScroll
) return FALSE
; 
1701     if (!win
->IsOwnGtkWindow( gdk_event
->window 
)) return FALSE
; 
1703     if (gdk_event
->is_hint
) 
1707         GdkModifierType state
; 
1708         gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
1714     printf( "OnMotion from " ); 
1715     if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) 
1716       printf( win->GetClassInfo()->GetClassName() ); 
1720     wxMouseEvent 
event( wxEVT_MOTION 
); 
1721     InitMouseEvent(win
, event
, gdk_event
); 
1723     if ( g_captureWindow 
) 
1725         // synthetize a mouse enter or leave event if needed 
1726         GdkWindow 
*winUnderMouse 
= gdk_window_at_pointer(NULL
, NULL
); 
1727         // This seems to be necessary and actually been added to 
1728         // GDK itself in version 2.0.X 
1731         bool hasMouse 
= winUnderMouse 
== gdk_event
->window
; 
1732         if ( hasMouse 
!= g_captureWindowHasMouse 
) 
1734             // the mouse changed window 
1735             g_captureWindowHasMouse 
= hasMouse
; 
1737             wxMouseEvent 
eventM(g_captureWindowHasMouse 
? wxEVT_ENTER_WINDOW
 
1738                                                         : wxEVT_LEAVE_WINDOW
); 
1739             InitMouseEvent(win
, eventM
, gdk_event
); 
1740             eventM
.SetEventObject(win
); 
1741             win
->GetEventHandler()->ProcessEvent(eventM
); 
1746         win 
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
); 
1749     if ( !g_captureWindow 
) 
1751         wxSetCursorEvent 
cevent( event
.m_x
, event
.m_y 
); 
1752         if (win
->GetEventHandler()->ProcessEvent( cevent 
)) 
1754             // Rewrite cursor handling here (away from idle). 
1758     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
1760         g_signal_stop_emission_by_name (widget
, "motion_notify_event"); 
1768 //----------------------------------------------------------------------------- 
1769 // "mouse_wheel_event" 
1770 //----------------------------------------------------------------------------- 
1774 gtk_window_wheel_callback (GtkWidget 
* widget
, 
1775                            GdkEventScroll 
* gdk_event
, 
1781         wxapp_install_idle_handler(); 
1783     wxEventType event_type 
= wxEVT_NULL
; 
1784     if (gdk_event
->direction 
== GDK_SCROLL_UP
) 
1785         event_type 
= wxEVT_MOUSEWHEEL
; 
1786     else if (gdk_event
->direction 
== GDK_SCROLL_DOWN
) 
1787         event_type 
= wxEVT_MOUSEWHEEL
; 
1791     wxMouseEvent 
event( event_type 
); 
1792     // Can't use InitMouse macro because scroll events don't have button 
1793     event
.SetTimestamp( gdk_event
->time 
); 
1794     event
.m_shiftDown 
= (gdk_event
->state 
& GDK_SHIFT_MASK
); 
1795     event
.m_controlDown 
= (gdk_event
->state 
& GDK_CONTROL_MASK
); 
1796     event
.m_altDown 
= (gdk_event
->state 
& GDK_MOD1_MASK
); 
1797     event
.m_metaDown 
= (gdk_event
->state 
& GDK_MOD2_MASK
); 
1798     event
.m_leftDown 
= (gdk_event
->state 
& GDK_BUTTON1_MASK
); 
1799     event
.m_middleDown 
= (gdk_event
->state 
& GDK_BUTTON2_MASK
); 
1800     event
.m_rightDown 
= (gdk_event
->state 
& GDK_BUTTON3_MASK
); 
1801     event
.m_linesPerAction 
= 3; 
1802     event
.m_wheelDelta 
= 120; 
1803     if (gdk_event
->direction 
== GDK_SCROLL_UP
) 
1804         event
.m_wheelRotation 
= 120; 
1806         event
.m_wheelRotation 
= -120; 
1808     wxPoint pt 
= win
->GetClientAreaOrigin(); 
1809     event
.m_x 
= (wxCoord
)gdk_event
->x 
- pt
.x
; 
1810     event
.m_y 
= (wxCoord
)gdk_event
->y 
- pt
.y
; 
1812     event
.SetEventObject( win 
); 
1813     event
.SetId( win
->GetId() ); 
1814     event
.SetTimestamp( gdk_event
->time 
); 
1816     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
1818         g_signal_stop_emission_by_name (widget
, "scroll_event"); 
1826 //----------------------------------------------------------------------------- 
1828 //----------------------------------------------------------------------------- 
1830 static gboolean 
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
) 
1832     wxContextMenuEvent 
event( 
1836     event
.SetEventObject(win
); 
1837     return win
->GetEventHandler()->ProcessEvent(event
); 
1841 //----------------------------------------------------------------------------- 
1843 //----------------------------------------------------------------------------- 
1845 // send the wxChildFocusEvent and wxFocusEvent, common code of 
1846 // gtk_window_focus_in_callback() and SetFocus() 
1847 static bool DoSendFocusEvents(wxWindow 
*win
) 
1849     // Notify the parent keeping track of focus for the kbd navigation 
1850     // purposes that we got it. 
1851     wxChildFocusEvent 
eventChildFocus(win
); 
1852     (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
); 
1854     wxFocusEvent 
eventFocus(wxEVT_SET_FOCUS
, win
->GetId()); 
1855     eventFocus
.SetEventObject(win
); 
1857     return win
->GetEventHandler()->ProcessEvent(eventFocus
); 
1862 gtk_window_focus_in_callback( GtkWidget 
*widget
, 
1863                               GdkEventFocus 
*WXUNUSED(event
), 
1869         wxapp_install_idle_handler(); 
1872         gtk_im_context_focus_in(win
->m_imData
->context
); 
1875     g_focusWindow 
= win
; 
1877     wxLogTrace(TRACE_FOCUS
, 
1878                _T("%s: focus in"), win
->GetName().c_str()); 
1882         gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
); 
1886     // caret needs to be informed about focus change 
1887     wxCaret 
*caret 
= win
->GetCaret(); 
1890         caret
->OnSetFocus(); 
1892 #endif // wxUSE_CARET 
1894     gboolean ret 
= FALSE
; 
1896     // does the window itself think that it has the focus? 
1897     if ( !win
->m_hasFocus 
) 
1899         // not yet, notify it 
1900         win
->m_hasFocus 
= true; 
1902         (void)DoSendFocusEvents(win
); 
1907     // Disable default focus handling for custom windows 
1908     // since the default GTK+ handler issues a repaint 
1909     if (win
->m_wxwindow
) 
1916 //----------------------------------------------------------------------------- 
1917 // "focus_out_event" 
1918 //----------------------------------------------------------------------------- 
1922 gtk_window_focus_out_callback( GtkWidget 
*widget
, 
1923                                GdkEventFocus 
*gdk_event
, 
1929         wxapp_install_idle_handler(); 
1932         gtk_im_context_focus_out(win
->m_imData
->context
); 
1934     wxLogTrace( TRACE_FOCUS
, 
1935                 _T("%s: focus out"), win
->GetName().c_str() ); 
1938     wxWindowGTK 
*winFocus 
= wxFindFocusedChild(win
); 
1942     g_focusWindow 
= (wxWindowGTK 
*)NULL
; 
1950     // caret needs to be informed about focus change 
1951     wxCaret 
*caret 
= win
->GetCaret(); 
1954         caret
->OnKillFocus(); 
1956 #endif // wxUSE_CARET 
1958     gboolean ret 
= FALSE
; 
1960     // don't send the window a kill focus event if it thinks that it doesn't 
1961     // have focus already 
1962     if ( win
->m_hasFocus 
) 
1964         win
->m_hasFocus 
= false; 
1966         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, win
->GetId() ); 
1967         event
.SetEventObject( win 
); 
1969         (void)win
->GetEventHandler()->ProcessEvent( event 
); 
1974     // Disable default focus handling for custom windows 
1975     // since the default GTK+ handler issues a repaint 
1976     if (win
->m_wxwindow
) 
1983 //----------------------------------------------------------------------------- 
1984 // "enter_notify_event" 
1985 //----------------------------------------------------------------------------- 
1989 gtk_window_enter_callback( GtkWidget 
*widget
, 
1990                            GdkEventCrossing 
*gdk_event
, 
1996         wxapp_install_idle_handler(); 
1998     if (!win
->m_hasVMT
) return FALSE
; 
1999     if (g_blockEventsOnDrag
) return FALSE
; 
2001     // Event was emitted after a grab 
2002     if (gdk_event
->mode 
!= GDK_CROSSING_NORMAL
) return FALSE
; 
2004     if (!win
->IsOwnGtkWindow( gdk_event
->window 
)) return FALSE
; 
2008     GdkModifierType state 
= (GdkModifierType
)0; 
2010     gdk_window_get_pointer( widget
->window
, &x
, &y
, &state 
); 
2012     wxMouseEvent 
event( wxEVT_ENTER_WINDOW 
); 
2013     InitMouseEvent(win
, event
, gdk_event
); 
2014     wxPoint pt 
= win
->GetClientAreaOrigin(); 
2015     event
.m_x 
= x 
+ pt
.x
; 
2016     event
.m_y 
= y 
+ pt
.y
; 
2018     if ( !g_captureWindow 
) 
2020         wxSetCursorEvent 
cevent( event
.m_x
, event
.m_y 
); 
2021         if (win
->GetEventHandler()->ProcessEvent( cevent 
)) 
2023             // Rewrite cursor handling here (away from idle). 
2027     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
2029        g_signal_stop_emission_by_name (widget
, "enter_notify_event"); 
2037 //----------------------------------------------------------------------------- 
2038 // "leave_notify_event" 
2039 //----------------------------------------------------------------------------- 
2043 gtk_window_leave_callback( GtkWidget 
*widget
, 
2044                            GdkEventCrossing 
*gdk_event
, 
2050         wxapp_install_idle_handler(); 
2052     if (!win
->m_hasVMT
) return FALSE
; 
2053     if (g_blockEventsOnDrag
) return FALSE
; 
2055     // Event was emitted after an ungrab 
2056     if (gdk_event
->mode 
!= GDK_CROSSING_NORMAL
) return FALSE
; 
2058     if (!win
->IsOwnGtkWindow( gdk_event
->window 
)) return FALSE
; 
2060     wxMouseEvent 
event( wxEVT_LEAVE_WINDOW 
); 
2061     event
.SetTimestamp( gdk_event
->time 
); 
2062     event
.SetEventObject( win 
); 
2066     GdkModifierType state 
= (GdkModifierType
)0; 
2068     gdk_window_get_pointer( widget
->window
, &x
, &y
, &state 
); 
2070     event
.m_shiftDown 
= (state 
& GDK_SHIFT_MASK
) != 0; 
2071     event
.m_controlDown 
= (state 
& GDK_CONTROL_MASK
) != 0; 
2072     event
.m_altDown 
= (state 
& GDK_MOD1_MASK
) != 0; 
2073     event
.m_metaDown 
= (state 
& GDK_MOD2_MASK
) != 0; 
2074     event
.m_leftDown 
= (state 
& GDK_BUTTON1_MASK
) != 0; 
2075     event
.m_middleDown 
= (state 
& GDK_BUTTON2_MASK
) != 0; 
2076     event
.m_rightDown 
= (state 
& GDK_BUTTON3_MASK
) != 0; 
2078     wxPoint pt 
= win
->GetClientAreaOrigin(); 
2079     event
.m_x 
= x 
+ pt
.x
; 
2080     event
.m_y 
= y 
+ pt
.y
; 
2082     if (win
->GetEventHandler()->ProcessEvent( event 
)) 
2084         g_signal_stop_emission_by_name (widget
, "leave_notify_event"); 
2092 //----------------------------------------------------------------------------- 
2093 // "value_changed" from m_vAdjust 
2094 //----------------------------------------------------------------------------- 
2097 static void gtk_window_vscroll_callback( GtkAdjustment 
*adjust
, 
2103         wxapp_install_idle_handler(); 
2105     if (g_blockEventsOnDrag
) return; 
2107     if (!win
->m_hasVMT
) return; 
2109     float diff 
= adjust
->value 
- win
->m_oldVerticalPos
; 
2110     if (fabs(diff
) < 0.2) return; 
2112     win
->m_oldVerticalPos 
= adjust
->value
; 
2114     wxEventType command 
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
); 
2116     int value 
= (int)(adjust
->value
+0.5); 
2118     wxScrollWinEvent 
event( command
, value
, wxVERTICAL 
); 
2119     event
.SetEventObject( win 
); 
2120     win
->GetEventHandler()->ProcessEvent( event 
); 
2124 //----------------------------------------------------------------------------- 
2125 // "value_changed" from m_hAdjust 
2126 //----------------------------------------------------------------------------- 
2129 static void gtk_window_hscroll_callback( GtkAdjustment 
*adjust
, 
2135         wxapp_install_idle_handler(); 
2137     if (g_blockEventsOnDrag
) return; 
2138     if (!win
->m_hasVMT
) return; 
2140     float diff 
= adjust
->value 
- win
->m_oldHorizontalPos
; 
2141     if (fabs(diff
) < 0.2) return; 
2143     wxEventType command 
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
); 
2145     win
->m_oldHorizontalPos 
= adjust
->value
; 
2147     int value 
= (int)(adjust
->value
+0.5); 
2149     wxScrollWinEvent 
event( command
, value
, wxHORIZONTAL 
); 
2150     event
.SetEventObject( win 
); 
2151     win
->GetEventHandler()->ProcessEvent( event 
); 
2155 //----------------------------------------------------------------------------- 
2156 // "button_press_event" from scrollbar 
2157 //----------------------------------------------------------------------------- 
2161 gtk_scrollbar_button_press_callback( GtkWidget 
*widget
, 
2162                                      GdkEventButton 
*gdk_event
, 
2168         wxapp_install_idle_handler(); 
2171     g_blockEventsOnScroll 
= true; 
2173 // FIXME: there is no 'slider' field in GTK+ 2.0 any more 
2175     win
->m_isScrolling 
= (gdk_event
->window 
== widget
->slider
); 
2182 //----------------------------------------------------------------------------- 
2183 // "button_release_event" from scrollbar 
2184 //----------------------------------------------------------------------------- 
2188 gtk_scrollbar_button_release_callback( GtkRange 
*widget
, 
2189                                        GdkEventButton 
*WXUNUSED(gdk_event
), 
2194 //  don't test here as we can release the mouse while being over 
2195 //  a different window than the slider 
2197 //    if (gdk_event->window != widget->slider) return FALSE; 
2199     g_blockEventsOnScroll 
= false; 
2201     if (win
->m_isScrolling
) 
2203         wxEventType command 
= wxEVT_SCROLLWIN_THUMBRELEASE
; 
2207         GtkScrolledWindow 
*scrolledWindow 
= GTK_SCROLLED_WINDOW(win
->m_widget
); 
2208         if (widget 
== GTK_RANGE(scrolledWindow
->hscrollbar
)) 
2210             value 
= (int)(win
->m_hAdjust
->value
+0.5); 
2213         if (widget 
== GTK_RANGE(scrolledWindow
->vscrollbar
)) 
2215             value 
= (int)(win
->m_vAdjust
->value
+0.5); 
2219         wxScrollWinEvent 
event( command
, value
, dir 
); 
2220         event
.SetEventObject( win 
); 
2221         win
->GetEventHandler()->ProcessEvent( event 
); 
2224     win
->m_isScrolling 
= false; 
2230 // ---------------------------------------------------------------------------- 
2231 // this wxWindowBase function is implemented here (in platform-specific file) 
2232 // because it is static and so couldn't be made virtual 
2233 // ---------------------------------------------------------------------------- 
2235 wxWindow 
*wxWindowBase::DoFindFocus() 
2237     // the cast is necessary when we compile in wxUniversal mode 
2238     return (wxWindow 
*)g_focusWindow
; 
2241 //----------------------------------------------------------------------------- 
2242 // "realize" from m_widget 
2243 //----------------------------------------------------------------------------- 
2245 /* We cannot set colours and fonts before the widget has 
2246    been realized, so we do this directly after realization. */ 
2250 gtk_window_realized_callback( GtkWidget 
*m_widget
, wxWindow 
*win 
) 
2255         wxapp_install_idle_handler(); 
2259         GtkPizza 
*pizza 
= GTK_PIZZA( m_widget 
); 
2260         gtk_im_context_set_client_window( win
->m_imData
->context
, 
2261                                           pizza
->bin_window 
); 
2264     wxWindowCreateEvent 
event( win 
); 
2265     event
.SetEventObject( win 
); 
2266     win
->GetEventHandler()->ProcessEvent( event 
); 
2270 //----------------------------------------------------------------------------- 
2272 //----------------------------------------------------------------------------- 
2276 void gtk_window_size_callback( GtkWidget 
*WXUNUSED(widget
), 
2277                                GtkAllocation 
*WXUNUSED(alloc
), 
2281         wxapp_install_idle_handler(); 
2283     if (!win
->m_hasScrolling
) return; 
2285     int client_width 
= 0; 
2286     int client_height 
= 0; 
2287     win
->GetClientSize( &client_width
, &client_height 
); 
2288     if ((client_width 
== win
->m_oldClientWidth
) && (client_height 
== win
->m_oldClientHeight
)) 
2291     win
->m_oldClientWidth 
= client_width
; 
2292     win
->m_oldClientHeight 
= client_height
; 
2294     if (!win
->m_nativeSizeEvent
) 
2296         wxSizeEvent 
event( win
->GetSize(), win
->GetId() ); 
2297         event
.SetEventObject( win 
); 
2298         win
->GetEventHandler()->ProcessEvent( event 
); 
2305     #define WXUNUSED_UNLESS_XIM(param)  param 
2307     #define WXUNUSED_UNLESS_XIM(param)  WXUNUSED(param) 
2310 /* Resize XIM window */ 
2314 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
), 
2315                                  GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
), 
2316                                  wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) ) 
2319         wxapp_install_idle_handler(); 
2325     if  (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
) 
2329         gdk_window_get_size (widget
->window
, &width
, &height
); 
2330         win
->m_icattr
->preedit_area
.width 
= width
; 
2331         win
->m_icattr
->preedit_area
.height 
= height
; 
2332         gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
); 
2338 //----------------------------------------------------------------------------- 
2339 // "realize" from m_wxwindow 
2340 //----------------------------------------------------------------------------- 
2342 /* Initialize XIM support */ 
2346 gtk_wxwindow_realized_callback( GtkWidget 
* WXUNUSED_UNLESS_XIM(widget
), 
2347                                 wxWindowGTK 
* WXUNUSED_UNLESS_XIM(win
) ) 
2350         wxapp_install_idle_handler(); 
2353     if (win
->m_ic
) return; 
2354     if (!widget
) return; 
2355     if (!gdk_im_ready()) return; 
2357     win
->m_icattr 
= gdk_ic_attr_new(); 
2358     if (!win
->m_icattr
) return; 
2362     GdkColormap 
*colormap
; 
2363     GdkICAttr 
*attr 
= win
->m_icattr
; 
2364     unsigned attrmask 
= GDK_IC_ALL_REQ
; 
2366     GdkIMStyle supported_style 
= (GdkIMStyle
) 
2367                                   (GDK_IM_PREEDIT_NONE 
| 
2368                                    GDK_IM_PREEDIT_NOTHING 
| 
2369                                    GDK_IM_PREEDIT_POSITION 
| 
2370                                    GDK_IM_STATUS_NONE 
| 
2371                                    GDK_IM_STATUS_NOTHING
); 
2373     if (widget
->style 
&& widget
->style
->font
->type 
!= GDK_FONT_FONTSET
) 
2374         supported_style 
= (GdkIMStyle
)(supported_style 
& ~GDK_IM_PREEDIT_POSITION
); 
2376     attr
->style 
= style 
= gdk_im_decide_style (supported_style
); 
2377     attr
->client_window 
= widget
->window
; 
2379     if ((colormap 
= gtk_widget_get_colormap (widget
)) != 
2380             gtk_widget_get_default_colormap ()) 
2382         attrmask 
|= GDK_IC_PREEDIT_COLORMAP
; 
2383         attr
->preedit_colormap 
= colormap
; 
2386     attrmask 
|= GDK_IC_PREEDIT_FOREGROUND
; 
2387     attrmask 
|= GDK_IC_PREEDIT_BACKGROUND
; 
2388     attr
->preedit_foreground 
= widget
->style
->fg
[GTK_STATE_NORMAL
]; 
2389     attr
->preedit_background 
= widget
->style
->base
[GTK_STATE_NORMAL
]; 
2391     switch (style 
& GDK_IM_PREEDIT_MASK
) 
2393         case GDK_IM_PREEDIT_POSITION
: 
2394             if (widget
->style 
&& widget
->style
->font
->type 
!= GDK_FONT_FONTSET
) 
2396                 g_warning ("over-the-spot style requires fontset"); 
2400             gdk_window_get_size (widget
->window
, &width
, &height
); 
2402             attrmask 
|= GDK_IC_PREEDIT_POSITION_REQ
; 
2403             attr
->spot_location
.x 
= 0; 
2404             attr
->spot_location
.y 
= height
; 
2405             attr
->preedit_area
.x 
= 0; 
2406             attr
->preedit_area
.y 
= 0; 
2407             attr
->preedit_area
.width 
= width
; 
2408             attr
->preedit_area
.height 
= height
; 
2409             attr
->preedit_fontset 
= widget
->style
->font
; 
2414       win
->m_ic 
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
); 
2416       if (win
->m_ic 
== NULL
) 
2417           g_warning ("Can't create input context."); 
2420           mask 
= gdk_window_get_events (widget
->window
); 
2421           mask 
= (GdkEventMask
)(mask 
| gdk_ic_get_events (win
->m_ic
)); 
2422           gdk_window_set_events (widget
->window
, mask
); 
2424           if (GTK_WIDGET_HAS_FOCUS(widget
)) 
2425               gdk_im_begin (win
->m_ic
, widget
->window
); 
2431 //----------------------------------------------------------------------------- 
2432 // InsertChild for wxWindowGTK. 
2433 //----------------------------------------------------------------------------- 
2435 /* Callback for wxWindowGTK. This very strange beast has to be used because 
2436  * C++ has no virtual methods in a constructor. We have to emulate a 
2437  * virtual function here as wxNotebook requires a different way to insert 
2438  * a child in it. I had opted for creating a wxNotebookPage window class 
2439  * which would have made this superfluous (such in the MDI window system), 
2440  * but no-one was listening to me... */ 
2442 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child 
) 
2444     /* the window might have been scrolled already, do we 
2445        have to adapt the position */ 
2446     GtkPizza 
*pizza 
= GTK_PIZZA(parent
->m_wxwindow
); 
2447     child
->m_x 
+= pizza
->xoffset
; 
2448     child
->m_y 
+= pizza
->yoffset
; 
2450     gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
), 
2451                      GTK_WIDGET(child
->m_widget
), 
2458 //----------------------------------------------------------------------------- 
2460 //----------------------------------------------------------------------------- 
2462 wxWindow 
*wxGetActiveWindow() 
2464     return wxWindow::FindFocus(); 
2468 wxMouseState 
wxGetMouseState() 
2474     GdkModifierType mask
; 
2476     gdk_window_get_pointer(NULL
, &x
, &y
, &mask
); 
2480     ms
.SetLeftDown(mask 
& GDK_BUTTON1_MASK
); 
2481     ms
.SetMiddleDown(mask 
& GDK_BUTTON2_MASK
); 
2482     ms
.SetRightDown(mask 
& GDK_BUTTON3_MASK
); 
2484     ms
.SetControlDown(mask 
& GDK_CONTROL_MASK
); 
2485     ms
.SetShiftDown(mask 
& GDK_SHIFT_MASK
); 
2486     ms
.SetAltDown(mask 
& GDK_MOD1_MASK
); 
2487     ms
.SetMetaDown(mask 
& GDK_MOD2_MASK
); 
2492 //----------------------------------------------------------------------------- 
2494 //----------------------------------------------------------------------------- 
2496 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu() 
2498 #ifdef __WXUNIVERSAL__ 
2499     IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
) 
2501     IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
) 
2502 #endif // __WXUNIVERSAL__/__WXGTK__ 
2504 void wxWindowGTK::Init() 
2507     m_widget 
= (GtkWidget 
*) NULL
; 
2508     m_wxwindow 
= (GtkWidget 
*) NULL
; 
2509     m_focusWidget 
= (GtkWidget 
*) NULL
; 
2519     m_needParent 
= true; 
2520     m_isBeingDeleted 
= false; 
2523     m_nativeSizeEvent 
= false; 
2525     m_hasScrolling 
= false; 
2526     m_isScrolling 
= false; 
2528     m_hAdjust 
= (GtkAdjustment
*) NULL
; 
2529     m_vAdjust 
= (GtkAdjustment
*) NULL
; 
2530     m_oldHorizontalPos 
= 
2531     m_oldVerticalPos 
= 0.0; 
2533     m_oldClientHeight 
= 0; 
2537     m_insertCallback 
= (wxInsertChildFunction
) NULL
; 
2539     m_acceptsFocus 
= false; 
2542     m_clipPaintRegion 
= false; 
2544     m_needsStyleChange 
= false; 
2546     m_cursor 
= *wxSTANDARD_CURSOR
; 
2549     m_dirtyTabOrder 
= false; 
2552 wxWindowGTK::wxWindowGTK() 
2557 wxWindowGTK::wxWindowGTK( wxWindow 
*parent
, 
2562                           const wxString 
&name  
) 
2566     Create( parent
, id
, pos
, size
, style
, name 
); 
2569 bool wxWindowGTK::Create( wxWindow 
*parent
, 
2574                           const wxString 
&name  
) 
2576     if (!PreCreation( parent
, pos
, size 
) || 
2577         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
2579         wxFAIL_MSG( wxT("wxWindowGTK creation failed") ); 
2583     m_insertCallback 
= wxInsertChildInWindow
; 
2585     m_widget 
= gtk_scrolled_window_new( (GtkAdjustment 
*) NULL
, (GtkAdjustment 
*) NULL 
); 
2586     GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
2588     GtkScrolledWindow 
*scrolledWindow 
= GTK_SCROLLED_WINDOW(m_widget
); 
2590     GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) ); 
2591     scroll_class
->scrollbar_spacing 
= 0; 
2593     gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC 
); 
2595     m_hAdjust 
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) ); 
2596     m_vAdjust 
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) ); 
2598     m_wxwindow 
= gtk_pizza_new(); 
2600 #ifndef __WXUNIVERSAL__ 
2601     GtkPizza 
*pizza 
= GTK_PIZZA(m_wxwindow
); 
2603     if (HasFlag(wxRAISED_BORDER
)) 
2605         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT 
); 
2607     else if (HasFlag(wxSUNKEN_BORDER
)) 
2609         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN 
); 
2611     else if (HasFlag(wxSIMPLE_BORDER
)) 
2613         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN 
); 
2617         gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE 
); 
2619 #endif // __WXUNIVERSAL__ 
2621     gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow 
); 
2623     GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS 
); 
2624     m_acceptsFocus 
= true; 
2626     // I _really_ don't want scrollbars in the beginning 
2627     m_vAdjust
->lower 
= 0.0; 
2628     m_vAdjust
->upper 
= 1.0; 
2629     m_vAdjust
->value 
= 0.0; 
2630     m_vAdjust
->step_increment 
= 1.0; 
2631     m_vAdjust
->page_increment 
= 1.0; 
2632     m_vAdjust
->page_size 
= 5.0; 
2633     g_signal_emit_by_name (m_vAdjust
, "changed"); 
2634     m_hAdjust
->lower 
= 0.0; 
2635     m_hAdjust
->upper 
= 1.0; 
2636     m_hAdjust
->value 
= 0.0; 
2637     m_hAdjust
->step_increment 
= 1.0; 
2638     m_hAdjust
->page_increment 
= 1.0; 
2639     m_hAdjust
->page_size 
= 5.0; 
2640     g_signal_emit_by_name (m_hAdjust
, "changed"); 
2642     // these handlers block mouse events to any window during scrolling such as 
2643     // motion events and prevent GTK and wxWidgets from fighting over where the 
2645     g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event", 
2646                       G_CALLBACK (gtk_scrollbar_button_press_callback
), this); 
2647     g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event", 
2648                       G_CALLBACK (gtk_scrollbar_button_press_callback
), this); 
2649     g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event", 
2650                       G_CALLBACK (gtk_scrollbar_button_release_callback
), this); 
2651     g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event", 
2652                       G_CALLBACK (gtk_scrollbar_button_release_callback
), this); 
2654     // these handlers get notified when screen updates are required either when 
2655     // scrolling or when the window size (and therefore scrollbar configuration) 
2658     g_signal_connect (m_hAdjust
, "value_changed", 
2659                       G_CALLBACK (gtk_window_hscroll_callback
), this); 
2660     g_signal_connect (m_vAdjust
, "value_changed", 
2661                       G_CALLBACK (gtk_window_vscroll_callback
), this); 
2663     gtk_widget_show( m_wxwindow 
); 
2666         m_parent
->DoAddChild( this ); 
2668     m_focusWidget 
= m_wxwindow
; 
2675 wxWindowGTK::~wxWindowGTK() 
2679     if (g_focusWindow 
== this) 
2680         g_focusWindow 
= NULL
; 
2682     if ( g_delayedFocus 
== this ) 
2683         g_delayedFocus 
= NULL
; 
2685     m_isBeingDeleted 
= true; 
2688     // destroy children before destroying this window itself 
2691     // unhook focus handlers to prevent stray events being 
2692     // propagated to this (soon to be) dead object 
2693     if (m_focusWidget 
!= NULL
) 
2695         g_signal_handlers_disconnect_by_func (m_focusWidget
, 
2696                                               (gpointer
) gtk_window_focus_in_callback
, 
2698         g_signal_handlers_disconnect_by_func (m_focusWidget
, 
2699                                               (gpointer
) gtk_window_focus_out_callback
, 
2708         gdk_ic_destroy (m_ic
); 
2710         gdk_ic_attr_destroy (m_icattr
); 
2713     // delete before the widgets to avoid a crash on solaris 
2718         gtk_widget_destroy( m_wxwindow 
); 
2719         m_wxwindow 
= (GtkWidget
*) NULL
; 
2724         gtk_widget_destroy( m_widget 
); 
2725         m_widget 
= (GtkWidget
*) NULL
; 
2729 bool wxWindowGTK::PreCreation( wxWindowGTK 
*parent
, const wxPoint 
&pos
,  const wxSize 
&size 
) 
2731     wxCHECK_MSG( !m_needParent 
|| parent
, false, wxT("Need complete parent.") ); 
2733     // Use either the given size, or the default if -1 is given. 
2734     // See wxWindowBase for these functions. 
2735     m_width 
= WidthDefault(size
.x
) ; 
2736     m_height 
= HeightDefault(size
.y
); 
2744 void wxWindowGTK::PostCreation() 
2746     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2752             // these get reported to wxWidgets -> wxPaintEvent 
2754             gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE 
); 
2756             g_signal_connect (m_wxwindow
, "expose_event", 
2757                               G_CALLBACK (gtk_window_expose_callback
), this); 
2759             gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE 
) ); 
2762         // Create input method handler 
2763         m_imData 
= new wxGtkIMData
; 
2765         // Cannot handle drawing preedited text yet 
2766         gtk_im_context_set_use_preedit( m_imData
->context
, FALSE 
); 
2768         g_signal_connect (m_imData
->context
, "commit", 
2769                           G_CALLBACK (gtk_wxwindow_commit_cb
), this); 
2771         // these are called when the "sunken" or "raised" borders are drawn 
2772         g_signal_connect (m_widget
, "expose_event", 
2773                           G_CALLBACK (gtk_window_own_expose_callback
), this); 
2778     if (!GTK_IS_WINDOW(m_widget
)) 
2780         if (m_focusWidget 
== NULL
) 
2781             m_focusWidget 
= m_widget
; 
2785             g_signal_connect (m_focusWidget
, "focus_in_event", 
2786                           G_CALLBACK (gtk_window_focus_in_callback
), this); 
2787             g_signal_connect (m_focusWidget
, "focus_out_event", 
2788                                 G_CALLBACK (gtk_window_focus_out_callback
), this); 
2792             g_signal_connect_after (m_focusWidget
, "focus_in_event", 
2793                           G_CALLBACK (gtk_window_focus_in_callback
), this); 
2794             g_signal_connect_after (m_focusWidget
, "focus_out_event", 
2795                                 G_CALLBACK (gtk_window_focus_out_callback
), this); 
2799     // connect to the various key and mouse handlers 
2801     GtkWidget 
*connect_widget 
= GetConnectWidget(); 
2803     ConnectWidget( connect_widget 
); 
2805     /* We cannot set colours, fonts and cursors before the widget has 
2806        been realized, so we do this directly after realization */ 
2807     g_signal_connect (connect_widget
, "realize", 
2808                       G_CALLBACK (gtk_window_realized_callback
), this); 
2812         // Catch native resize events 
2813         g_signal_connect (m_wxwindow
, "size_allocate", 
2814                           G_CALLBACK (gtk_window_size_callback
), this); 
2816         // Initialize XIM support 
2817         g_signal_connect (m_wxwindow
, "realize", 
2818                           G_CALLBACK (gtk_wxwindow_realized_callback
), this); 
2820         // And resize XIM window 
2821         g_signal_connect (m_wxwindow
, "size_allocate", 
2822                           G_CALLBACK (gtk_wxwindow_size_callback
), this); 
2825     if (GTK_IS_COMBO(m_widget
)) 
2827         GtkCombo 
*gcombo 
= GTK_COMBO(m_widget
); 
2829         g_signal_connect (gcombo
->entry
, "size_request", 
2830                           G_CALLBACK (wxgtk_combo_size_request_callback
), 
2835         // This is needed if we want to add our windows into native 
2836         // GTK controls, such as the toolbar. With this callback, the 
2837         // toolbar gets to know the correct size (the one set by the 
2838         // programmer). Sadly, it misbehaves for wxComboBox. 
2839         g_signal_connect (m_widget
, "size_request", 
2840                           G_CALLBACK (wxgtk_window_size_request_callback
), 
2844     InheritAttributes(); 
2848     // unless the window was created initially hidden (i.e. Hide() had been 
2849     // called before Create()), we should show it at GTK+ level as well 
2851         gtk_widget_show( m_widget 
); 
2854 void wxWindowGTK::ConnectWidget( GtkWidget 
*widget 
) 
2856     g_signal_connect (widget
, "key_press_event", 
2857                       G_CALLBACK (gtk_window_key_press_callback
), this); 
2858     g_signal_connect (widget
, "key_release_event", 
2859                       G_CALLBACK (gtk_window_key_release_callback
), this); 
2860     g_signal_connect (widget
, "button_press_event", 
2861                       G_CALLBACK (gtk_window_button_press_callback
), this); 
2862     g_signal_connect (widget
, "button_release_event", 
2863                       G_CALLBACK (gtk_window_button_release_callback
), this); 
2864     g_signal_connect (widget
, "motion_notify_event", 
2865                       G_CALLBACK (gtk_window_motion_notify_callback
), this); 
2866     g_signal_connect (widget
, "scroll_event", 
2867                       G_CALLBACK (gtk_window_wheel_callback
), this); 
2868     g_signal_connect (widget
, "popup_menu", 
2869                      G_CALLBACK (wxgtk_window_popup_menu_callback
), this); 
2870     g_signal_connect (widget
, "enter_notify_event", 
2871                       G_CALLBACK (gtk_window_enter_callback
), this); 
2872     g_signal_connect (widget
, "leave_notify_event", 
2873                       G_CALLBACK (gtk_window_leave_callback
), this); 
2876 bool wxWindowGTK::Destroy() 
2878     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2882     return wxWindowBase::Destroy(); 
2885 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
) 
2887     gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height 
); 
2890 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
2892     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
2893     wxASSERT_MSG( (m_parent 
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") ); 
2896     printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height ); 
2899     if (m_resizing
) return; /* I don't like recursions */ 
2902     int currentX
, currentY
; 
2903     GetPosition(¤tX
, ¤tY
); 
2904     if (x 
== -1 && !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
2906     if (y 
== -1 && !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
2908     AdjustForParentClientOrigin(x
, y
, sizeFlags
); 
2910     // calculate the best size if we should auto size the window 
2911     if ( ((sizeFlags 
& wxSIZE_AUTO_WIDTH
) && width 
== -1) || 
2912          ((sizeFlags 
& wxSIZE_AUTO_HEIGHT
) && height 
== -1) ) 
2914         const wxSize sizeBest 
= GetBestSize(); 
2915         if ( (sizeFlags 
& wxSIZE_AUTO_WIDTH
) && width 
== -1 ) 
2917         if ( (sizeFlags 
& wxSIZE_AUTO_HEIGHT
) && height 
== -1 ) 
2918             height 
= sizeBest
.y
; 
2926     int minWidth  
= GetMinWidth(), 
2927         minHeight 
= GetMinHeight(), 
2928         maxWidth  
= GetMaxWidth(), 
2929         maxHeight 
= GetMaxHeight(); 
2931     if ((minWidth  
!= -1) && (m_width  
< minWidth 
)) m_width  
= minWidth
; 
2932     if ((minHeight 
!= -1) && (m_height 
< minHeight
)) m_height 
= minHeight
; 
2933     if ((maxWidth  
!= -1) && (m_width  
> maxWidth 
)) m_width  
= maxWidth
; 
2934     if ((maxHeight 
!= -1) && (m_height 
> maxHeight
)) m_height 
= maxHeight
; 
2936 #if wxUSE_TOOLBAR_NATIVE 
2937     if (wxDynamicCast(GetParent(), wxToolBar
)) 
2939        // don't take the x,y values, they're wrong because toolbar sets them 
2940        GtkWidget  
*widget 
= GTK_WIDGET(m_widget
); 
2941        gtk_widget_set_size_request (widget
, m_width
, m_height
); 
2942        if (GTK_WIDGET_VISIBLE (widget
)) 
2943             gtk_widget_queue_resize (widget
); 
2947     if (m_parent
->m_wxwindow 
== NULL
) // i.e. wxNotebook 
2949         // don't set the size for children of wxNotebook, just take the values. 
2957         GtkPizza 
*pizza 
= GTK_PIZZA(m_parent
->m_wxwindow
); 
2958         if ((sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
) == 0) 
2960             if (x 
!= -1) m_x 
= x 
+ pizza
->xoffset
; 
2961             if (y 
!= -1) m_y 
= y 
+ pizza
->yoffset
; 
2965             m_x 
= x 
+ pizza
->xoffset
; 
2966             m_y 
= y 
+ pizza
->yoffset
; 
2969         int left_border 
= 0; 
2970         int right_border 
= 0; 
2972         int bottom_border 
= 0; 
2974         /* the default button has a border around it */ 
2975         if (GTK_WIDGET_CAN_DEFAULT(m_widget
)) 
2977             GtkBorder 
*default_border 
= NULL
; 
2978             gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL 
); 
2981                 left_border 
+= default_border
->left
; 
2982                 right_border 
+= default_border
->right
; 
2983                 top_border 
+= default_border
->top
; 
2984                 bottom_border 
+= default_border
->bottom
; 
2985                 g_free( default_border 
); 
2989         DoMoveWindow( m_x
-top_border
, 
2991                       m_width
+left_border
+right_border
, 
2992                       m_height
+top_border
+bottom_border 
); 
2997         /* Sometimes the client area changes size without the 
2998            whole windows's size changing, but if the whole 
2999            windows's size doesn't change, no wxSizeEvent will 
3000            normally be sent. Here we add an extra test if 
3001            the client test has been changed and this will 
3003         GetClientSize( &m_oldClientWidth
, &m_oldClientHeight 
); 
3007     wxPrintf( "OnSize sent from " ); 
3008     if (GetClassInfo() && GetClassInfo()->GetClassName()) 
3009         wxPrintf( GetClassInfo()->GetClassName() ); 
3010     wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height ); 
3013     if (!m_nativeSizeEvent
) 
3015         wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
3016         event
.SetEventObject( this ); 
3017         GetEventHandler()->ProcessEvent( event 
); 
3023 void wxWindowGTK::OnInternalIdle() 
3025     if ( m_dirtyTabOrder 
) 
3027         m_dirtyTabOrder 
= false; 
3031     // Update style if the window was not yet realized 
3032     // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called 
3033     if (m_needsStyleChange
) 
3035         SetBackgroundStyle(GetBackgroundStyle()); 
3036         m_needsStyleChange 
= false; 
3039     // Update invalidated regions. 
3042     wxCursor cursor 
= m_cursor
; 
3043     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
3047         /* I now set the cursor anew in every OnInternalIdle call 
3048            as setting the cursor in a parent window also effects the 
3049            windows above so that checking for the current cursor is 
3054             GdkWindow 
*window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3056                 gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
3058             if (!g_globalCursor
.Ok()) 
3059                 cursor 
= *wxSTANDARD_CURSOR
; 
3061             window 
= m_widget
->window
; 
3062             if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
))) 
3063                 gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
3069             GdkWindow 
*window 
= m_widget
->window
; 
3070             if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
))) 
3071                gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
3076     if (wxUpdateUIEvent::CanUpdate(this)) 
3077         UpdateWindowUI(wxUPDATE_UI_FROMIDLE
); 
3080 void wxWindowGTK::DoGetSize( int *width
, int *height 
) const 
3082     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3084     if (width
) (*width
) = m_width
; 
3085     if (height
) (*height
) = m_height
; 
3088 void wxWindowGTK::DoSetClientSize( int width
, int height 
) 
3090     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3094         SetSize( width
, height 
); 
3101 #ifndef __WXUNIVERSAL__ 
3102         if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
)) 
3104             /* when using GTK 1.2 we set the shadow border size to 2 */ 
3108         if (HasFlag(wxSIMPLE_BORDER
)) 
3110             /* when using GTK 1.2 we set the simple border size to 1 */ 
3114 #endif // __WXUNIVERSAL__ 
3118             GtkScrolledWindow 
*scroll_window 
= GTK_SCROLLED_WINDOW(m_widget
); 
3120             GtkRequisition vscroll_req
; 
3121             vscroll_req
.width 
= 2; 
3122             vscroll_req
.height 
= 2; 
3123             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request 
) 
3124                 (scroll_window
->vscrollbar
, &vscroll_req 
); 
3126             GtkRequisition hscroll_req
; 
3127             hscroll_req
.width 
= 2; 
3128             hscroll_req
.height 
= 2; 
3129             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request 
) 
3130                 (scroll_window
->hscrollbar
, &hscroll_req 
); 
3132             GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) ); 
3134             if (scroll_window
->vscrollbar_visible
) 
3136                 dw 
+= vscroll_req
.width
; 
3137                 dw 
+= scroll_class
->scrollbar_spacing
; 
3140             if (scroll_window
->hscrollbar_visible
) 
3142                 dh 
+= hscroll_req
.height
; 
3143                 dh 
+= scroll_class
->scrollbar_spacing
; 
3147        SetSize( width
+dw
, height
+dh 
); 
3151 void wxWindowGTK::DoGetClientSize( int *width
, int *height 
) const 
3153     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3157         if (width
) (*width
) = m_width
; 
3158         if (height
) (*height
) = m_height
; 
3165 #ifndef __WXUNIVERSAL__ 
3166         if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
)) 
3168             /* when using GTK 1.2 we set the shadow border size to 2 */ 
3172         if (HasFlag(wxSIMPLE_BORDER
)) 
3174             /* when using GTK 1.2 we set the simple border size to 1 */ 
3178 #endif // __WXUNIVERSAL__ 
3182             GtkScrolledWindow 
*scroll_window 
= GTK_SCROLLED_WINDOW(m_widget
); 
3184             GtkRequisition vscroll_req
; 
3185             vscroll_req
.width 
= 2; 
3186             vscroll_req
.height 
= 2; 
3187             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request 
) 
3188                 (scroll_window
->vscrollbar
, &vscroll_req 
); 
3190             GtkRequisition hscroll_req
; 
3191             hscroll_req
.width 
= 2; 
3192             hscroll_req
.height 
= 2; 
3193             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request 
) 
3194                 (scroll_window
->hscrollbar
, &hscroll_req 
); 
3196             GtkScrolledWindowClass 
*scroll_class 
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) ); 
3198             if (scroll_window
->vscrollbar_visible
) 
3200                 dw 
+= vscroll_req
.width
; 
3201                 dw 
+= scroll_class
->scrollbar_spacing
; 
3204             if (scroll_window
->hscrollbar_visible
) 
3206                 dh 
+= hscroll_req
.height
; 
3207                 dh 
+= scroll_class
->scrollbar_spacing
; 
3211         if (width
) (*width
) = m_width 
- dw
; 
3212         if (height
) (*height
) = m_height 
- dh
; 
3216     printf( "GetClientSize, name %s ", GetName().c_str() ); 
3217     if (width) printf( " width = %d", (*width) ); 
3218     if (height) printf( " height = %d", (*height) ); 
3223 void wxWindowGTK::DoGetPosition( int *x
, int *y 
) const 
3225     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3229     if (m_parent 
&& m_parent
->m_wxwindow
) 
3231         GtkPizza 
*pizza 
= GTK_PIZZA(m_parent
->m_wxwindow
); 
3232         dx 
= pizza
->xoffset
; 
3233         dy 
= pizza
->yoffset
; 
3236     if (x
) (*x
) = m_x 
- dx
; 
3237     if (y
) (*y
) = m_y 
- dy
; 
3240 void wxWindowGTK::DoClientToScreen( int *x
, int *y 
) const 
3242     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3244     if (!m_widget
->window
) return; 
3246     GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
3248         source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3250         source 
= m_widget
->window
; 
3254     gdk_window_get_origin( source
, &org_x
, &org_y 
); 
3258         if (GTK_WIDGET_NO_WINDOW (m_widget
)) 
3260             org_x 
+= m_widget
->allocation
.x
; 
3261             org_y 
+= m_widget
->allocation
.y
; 
3269 void wxWindowGTK::DoScreenToClient( int *x
, int *y 
) const 
3271     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3273     if (!m_widget
->window
) return; 
3275     GdkWindow 
*source 
= (GdkWindow 
*) NULL
; 
3277         source 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3279         source 
= m_widget
->window
; 
3283     gdk_window_get_origin( source
, &org_x
, &org_y 
); 
3287         if (GTK_WIDGET_NO_WINDOW (m_widget
)) 
3289             org_x 
+= m_widget
->allocation
.x
; 
3290             org_y 
+= m_widget
->allocation
.y
; 
3298 bool wxWindowGTK::Show( bool show 
) 
3300     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3302     if (!wxWindowBase::Show(show
)) 
3309         gtk_widget_show( m_widget 
); 
3311         gtk_widget_hide( m_widget 
); 
3313     wxShowEvent 
eventShow(GetId(), show
); 
3314     eventShow
.SetEventObject(this); 
3316     GetEventHandler()->ProcessEvent(eventShow
); 
3321 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
) 
3323     win
->OnParentEnable(enable
); 
3325     // Recurse, so that children have the opportunity to Do The Right Thing 
3326     // and reset colours that have been messed up by a parent's (really ancestor's) 
3328     for ( wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
3330           node 
= node
->GetNext() ) 
3332         wxWindow 
*child 
= node
->GetData(); 
3333         if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
))) 
3334             wxWindowNotifyEnable(child
, enable
); 
3338 bool wxWindowGTK::Enable( bool enable 
) 
3340     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3342     if (!wxWindowBase::Enable(enable
)) 
3348     gtk_widget_set_sensitive( m_widget
, enable 
); 
3350         gtk_widget_set_sensitive( m_wxwindow
, enable 
); 
3352     wxWindowNotifyEnable(this, enable
); 
3357 int wxWindowGTK::GetCharHeight() const 
3359     wxCHECK_MSG( (m_widget 
!= NULL
), 12, wxT("invalid window") ); 
3361     wxFont font 
= GetFont(); 
3362     wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") ); 
3364     PangoContext 
*context 
= NULL
; 
3366         context 
= gtk_widget_get_pango_context( m_widget 
); 
3371     PangoFontDescription 
*desc 
= font
.GetNativeFontInfo()->description
; 
3372     PangoLayout 
*layout 
= pango_layout_new(context
); 
3373     pango_layout_set_font_description(layout
, desc
); 
3374     pango_layout_set_text(layout
, "H", 1); 
3375     PangoLayoutLine 
*line 
= (PangoLayoutLine 
*)pango_layout_get_lines(layout
)->data
; 
3377     PangoRectangle rect
; 
3378     pango_layout_line_get_extents(line
, NULL
, &rect
); 
3380     g_object_unref( G_OBJECT( layout 
) ); 
3382     return (int) PANGO_PIXELS(rect
.height
); 
3385 int wxWindowGTK::GetCharWidth() const 
3387     wxCHECK_MSG( (m_widget 
!= NULL
), 8, wxT("invalid window") ); 
3389     wxFont font 
= GetFont(); 
3390     wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") ); 
3392     PangoContext 
*context 
= NULL
; 
3394         context 
= gtk_widget_get_pango_context( m_widget 
); 
3399     PangoFontDescription 
*desc 
= font
.GetNativeFontInfo()->description
; 
3400     PangoLayout 
*layout 
= pango_layout_new(context
); 
3401     pango_layout_set_font_description(layout
, desc
); 
3402     pango_layout_set_text(layout
, "g", 1); 
3403     PangoLayoutLine 
*line 
= (PangoLayoutLine 
*)pango_layout_get_lines(layout
)->data
; 
3405     PangoRectangle rect
; 
3406     pango_layout_line_get_extents(line
, NULL
, &rect
); 
3408     g_object_unref( G_OBJECT( layout 
) ); 
3410     return (int) PANGO_PIXELS(rect
.width
); 
3413 void wxWindowGTK::GetTextExtent( const wxString
& string
, 
3417                                  int *externalLeading
, 
3418                                  const wxFont 
*theFont 
) const 
3420     wxFont fontToUse 
= theFont 
? *theFont 
: GetFont(); 
3422     wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") ); 
3431     PangoContext 
*context 
= NULL
; 
3433         context 
= gtk_widget_get_pango_context( m_widget 
); 
3442     PangoFontDescription 
*desc 
= fontToUse
.GetNativeFontInfo()->description
; 
3443     PangoLayout 
*layout 
= pango_layout_new(context
); 
3444     pango_layout_set_font_description(layout
, desc
); 
3447         const wxCharBuffer data 
= wxConvUTF8
.cWC2MB( string 
); 
3448         pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data 
)); 
3450         const wxWCharBuffer wdata 
= wxConvLocal
.cMB2WC( string 
); 
3451         const wxCharBuffer data 
= wxConvUTF8
.cWC2MB( wdata 
); 
3452         pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data 
)); 
3456     PangoRectangle rect
; 
3457     pango_layout_get_extents(layout
, NULL
, &rect
); 
3459     if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
); 
3460     if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
); 
3463         PangoLayoutIter 
*iter 
= pango_layout_get_iter(layout
); 
3464         int baseline 
= pango_layout_iter_get_baseline(iter
); 
3465         pango_layout_iter_free(iter
); 
3466         *descent 
= *y 
- PANGO_PIXELS(baseline
); 
3468     if (externalLeading
) (*externalLeading
) = 0;  // ?? 
3470     g_object_unref( G_OBJECT( layout 
) ); 
3473 void wxWindowGTK::SetFocus() 
3475     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3478         // don't do anything if we already have focus 
3484         if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
)) 
3486             gtk_widget_grab_focus (m_wxwindow
); 
3491         if (GTK_IS_CONTAINER(m_widget
)) 
3493             gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD 
); 
3496         if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) ) 
3499             if (!GTK_WIDGET_REALIZED(m_widget
)) 
3501                 // we can't set the focus to the widget now so we remember that 
3502                 // it should be focused and will do it later, during the idle 
3503                 // time, as soon as we can 
3504                 wxLogTrace(TRACE_FOCUS
, 
3505                            _T("Delaying setting focus to %s(%s)"), 
3506                            GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3508                 g_delayedFocus 
= this; 
3512                 wxLogTrace(TRACE_FOCUS
, 
3513                            _T("Setting focus to %s(%s)"), 
3514                            GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3516                 gtk_widget_grab_focus (m_widget
); 
3521            wxLogTrace(TRACE_FOCUS
, 
3522                       _T("Can't set focus to %s(%s)"), 
3523                       GetClassInfo()->GetClassName(), GetLabel().c_str()); 
3528 bool wxWindowGTK::AcceptsFocus() const 
3530     return m_acceptsFocus 
&& wxWindowBase::AcceptsFocus(); 
3533 bool wxWindowGTK::Reparent( wxWindowBase 
*newParentBase 
) 
3535     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3537     wxWindowGTK 
*oldParent 
= m_parent
, 
3538              *newParent 
= (wxWindowGTK 
*)newParentBase
; 
3540     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3542     if ( !wxWindowBase::Reparent(newParent
) ) 
3545     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3547     /* prevent GTK from deleting the widget arbitrarily */ 
3548     gtk_widget_ref( m_widget 
); 
3552         gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget 
); 
3555     wxASSERT( GTK_IS_WIDGET(m_widget
) ); 
3559         /* insert GTK representation */ 
3560         (*(newParent
->m_insertCallback
))(newParent
, this); 
3563     /* reverse: prevent GTK from deleting the widget arbitrarily */ 
3564     gtk_widget_unref( m_widget 
); 
3569 void wxWindowGTK::DoAddChild(wxWindowGTK 
*child
) 
3571     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid window") ); 
3573     wxASSERT_MSG( (child 
!= NULL
), wxT("invalid child window") ); 
3575     wxASSERT_MSG( (m_insertCallback 
!= NULL
), wxT("invalid child insertion function") ); 
3580     /* insert GTK representation */ 
3581     (*m_insertCallback
)(this, child
); 
3584 void wxWindowGTK::AddChild(wxWindowBase 
*child
) 
3586     wxWindowBase::AddChild(child
); 
3587     m_dirtyTabOrder 
= true; 
3589         wxapp_install_idle_handler(); 
3592 void wxWindowGTK::RemoveChild(wxWindowBase 
*child
) 
3594     wxWindowBase::RemoveChild(child
); 
3595     m_dirtyTabOrder 
= true; 
3597         wxapp_install_idle_handler(); 
3600 void wxWindowGTK::DoMoveInTabOrder(wxWindow 
*win
, MoveKind move
) 
3602     wxWindowBase::DoMoveInTabOrder(win
, move
); 
3603     m_dirtyTabOrder 
= true; 
3605         wxapp_install_idle_handler(); 
3608 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const 
3610     // none needed by default 
3614 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
)) 
3616     // nothing to do by default since none is needed 
3619 void wxWindowGTK::RealizeTabOrder() 
3623         if ( !m_children
.empty() ) 
3625             // we don't only construct the correct focus chain but also use 
3626             // this opportunity to update the mnemonic widgets for the widgets 
3629             GList 
*chain 
= NULL
; 
3630             wxWindowGTK
* mnemonicWindow 
= NULL
; 
3632             for ( wxWindowList::const_iterator i 
= m_children
.begin(); 
3633                   i 
!= m_children
.end(); 
3636                 wxWindowGTK 
*win 
= *i
; 
3638                 if ( mnemonicWindow 
) 
3640                     if ( win
->AcceptsFocusFromKeyboard() ) 
3642                         // wxComboBox et al. needs to focus on on a different 
3643                         // widget than m_widget, so if the main widget isn't 
3644                         // focusable try the connect widget 
3645                         GtkWidget
* w 
= win
->m_widget
; 
3646                         if ( !GTK_WIDGET_CAN_FOCUS(w
) ) 
3648                             w 
= win
->GetConnectWidget(); 
3649                             if ( !GTK_WIDGET_CAN_FOCUS(w
) ) 
3655                             mnemonicWindow
->GTKWidgetDoSetMnemonic(w
); 
3656                             mnemonicWindow 
= NULL
; 
3660                 else if ( win
->GTKWidgetNeedsMnemonic() ) 
3662                     mnemonicWindow 
= win
; 
3665                 chain 
= g_list_prepend(chain
, win
->m_widget
); 
3668             chain 
= g_list_reverse(chain
); 
3670             gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
); 
3675             gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
)); 
3680 void wxWindowGTK::Raise() 
3682     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3684     if (m_wxwindow 
&& m_wxwindow
->window
) 
3686         gdk_window_raise( m_wxwindow
->window 
); 
3688     else if (m_widget
->window
) 
3690         gdk_window_raise( m_widget
->window 
); 
3694 void wxWindowGTK::Lower() 
3696     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3698     if (m_wxwindow 
&& m_wxwindow
->window
) 
3700         gdk_window_lower( m_wxwindow
->window 
); 
3702     else if (m_widget
->window
) 
3704         gdk_window_lower( m_widget
->window 
); 
3708 bool wxWindowGTK::SetCursor( const wxCursor 
&cursor 
) 
3710     wxCHECK_MSG( (m_widget 
!= NULL
), false, wxT("invalid window") ); 
3712     if (cursor 
== m_cursor
) 
3716         wxapp_install_idle_handler(); 
3718     if (cursor 
== wxNullCursor
) 
3719        return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR 
); 
3721        return wxWindowBase::SetCursor( cursor 
); 
3724 void wxWindowGTK::WarpPointer( int x
, int y 
) 
3726     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid window") ); 
3728     // We provide this function ourselves as it is 
3729     // missing in GDK (top of this file). 
3731     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
3733         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
3735         window 
= GetConnectWidget()->window
; 
3738         gdk_window_warp_pointer( window
, x
, y 
); 
3741 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
) 
3743     double value_start 
= adj
->value
; 
3744     double value 
= value_start 
+ change
; 
3745     double upper 
= adj
->upper 
- adj
->page_size
; 
3750     // Lower bound will be checked by gtk_adjustment_set_value 
3751     gtk_adjustment_set_value(adj
, value
); 
3752     return adj
->value 
!= value_start
; 
3755 bool wxWindowGTK::ScrollLines(int lines
) 
3758         m_vAdjust 
!= NULL 
&& 
3759         wxScrollAdjust(m_vAdjust
, lines 
* m_vAdjust
->step_increment
); 
3762 bool wxWindowGTK::ScrollPages(int pages
) 
3765         m_vAdjust 
!= NULL 
&& 
3766         wxScrollAdjust(m_vAdjust
, pages 
* m_vAdjust
->page_increment
); 
3769 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
) 
3771     wxASSERT(m_vAdjust 
== NULL
); 
3775 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect 
*rect 
) 
3779     if (!m_widget
->window
) 
3784         GdkRectangle gdk_rect
, 
3788             gdk_rect
.x 
= rect
->x
; 
3789             gdk_rect
.y 
= rect
->y
; 
3790             gdk_rect
.width 
= rect
->width
; 
3791             gdk_rect
.height 
= rect
->height
; 
3794         else // invalidate everything 
3799         gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE 
); 
3803 void wxWindowGTK::Update() 
3807     // when we call Update() we really want to update the window immediately on 
3808     // screen, even if it means flushing the entire queue and hence slowing down 
3809     // everything -- but it should still be done, it's just that Update() should 
3810     // be called very rarely 
3814 void wxWindowGTK::GtkUpdate() 
3816     if (m_wxwindow 
&& GTK_PIZZA(m_wxwindow
)->bin_window
) 
3817         gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE 
); 
3819     // for consistency with other platforms (and also because it's convenient 
3820     // to be able to update an entire TLW by calling Update() only once), we 
3821     // should also update all our children here 
3822     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
3824           node 
= node
->GetNext() ) 
3826         node
->GetData()->GtkUpdate(); 
3830 void wxWindowGTK::GtkSendPaintEvents() 
3834         m_updateRegion
.Clear(); 
3838     // Clip to paint region in wxClientDC 
3839     m_clipPaintRegion 
= true; 
3841     // widget to draw on 
3842     GtkPizza 
*pizza 
= GTK_PIZZA (m_wxwindow
); 
3844     if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)) 
3846         // find ancestor from which to steal background 
3847         wxWindow 
*parent 
= wxGetTopLevelParent((wxWindow 
*)this); 
3849             parent 
= (wxWindow
*)this; 
3851         if (GTK_WIDGET_MAPPED(parent
->m_widget
)) 
3853             wxRegionIterator 
upd( m_updateRegion 
); 
3857                 rect
.x 
= upd
.GetX(); 
3858                 rect
.y 
= upd
.GetY(); 
3859                 rect
.width 
= upd
.GetWidth(); 
3860                 rect
.height 
= upd
.GetHeight(); 
3862                 gtk_paint_flat_box( parent
->m_widget
->style
, 
3864                             (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
), 
3878         wxWindowDC 
dc( (wxWindow
*)this ); 
3879         dc
.SetClippingRegion( m_updateRegion 
); 
3881         wxEraseEvent 
erase_event( GetId(), &dc 
); 
3882         erase_event
.SetEventObject( this ); 
3884         GetEventHandler()->ProcessEvent(erase_event
); 
3887     wxNcPaintEvent 
nc_paint_event( GetId() ); 
3888     nc_paint_event
.SetEventObject( this ); 
3889     GetEventHandler()->ProcessEvent( nc_paint_event 
); 
3891     wxPaintEvent 
paint_event( GetId() ); 
3892     paint_event
.SetEventObject( this ); 
3893     GetEventHandler()->ProcessEvent( paint_event 
); 
3895     m_clipPaintRegion 
= false; 
3897     m_updateRegion
.Clear(); 
3900 void wxWindowGTK::ClearBackground() 
3902     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
3906 void wxWindowGTK::DoSetToolTip( wxToolTip 
*tip 
) 
3908     wxWindowBase::DoSetToolTip(tip
); 
3911         m_tooltip
->Apply( (wxWindow 
*)this ); 
3914 void wxWindowGTK::ApplyToolTip( GtkTooltips 
*tips
, const wxChar 
*tip 
) 
3916     wxString 
tmp( tip 
); 
3917     gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL 
); 
3919 #endif // wxUSE_TOOLTIPS 
3921 bool wxWindowGTK::SetBackgroundColour( const wxColour 
&colour 
) 
3923     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3925     if (!wxWindowBase::SetBackgroundColour(colour
)) 
3930         // We need the pixel value e.g. for background clearing. 
3931         m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
)); 
3934     // apply style change (forceStyle=true so that new style is applied 
3935     // even if the bg colour changed from valid to wxNullColour) 
3936     if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
) 
3937         ApplyWidgetStyle(true); 
3942 bool wxWindowGTK::SetForegroundColour( const wxColour 
&colour 
) 
3944     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
3946     if (!wxWindowBase::SetForegroundColour(colour
)) 
3953         // We need the pixel value e.g. for background clearing. 
3954         m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
)); 
3957     // apply style change (forceStyle=true so that new style is applied 
3958     // even if the bg colour changed from valid to wxNullColour): 
3959     ApplyWidgetStyle(true); 
3964 PangoContext 
*wxWindowGTK::GtkGetPangoDefaultContext() 
3966     return gtk_widget_get_pango_context( m_widget 
); 
3969 GtkRcStyle 
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
) 
3971     // do we need to apply any changes at all? 
3974          !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() ) 
3979     GtkRcStyle 
*style 
= gtk_rc_style_new(); 
3984             pango_font_description_copy( m_font
.GetNativeFontInfo()->description 
); 
3987     if ( m_foregroundColour
.Ok() ) 
3989         GdkColor 
*fg 
= m_foregroundColour
.GetColor(); 
3991         style
->fg
[GTK_STATE_NORMAL
] = *fg
; 
3992         style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
; 
3994         style
->fg
[GTK_STATE_PRELIGHT
] = *fg
; 
3995         style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
; 
3997         style
->fg
[GTK_STATE_ACTIVE
] = *fg
; 
3998         style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
; 
4001     if ( m_backgroundColour
.Ok() ) 
4003         GdkColor 
*bg 
= m_backgroundColour
.GetColor(); 
4005         style
->bg
[GTK_STATE_NORMAL
] = *bg
; 
4006         style
->base
[GTK_STATE_NORMAL
] = *bg
; 
4007         style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
) 
4008             (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG 
| GTK_RC_BASE
); 
4010         style
->bg
[GTK_STATE_PRELIGHT
] = *bg
; 
4011         style
->base
[GTK_STATE_PRELIGHT
] = *bg
; 
4012         style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
) 
4013             (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG 
| GTK_RC_BASE
); 
4015         style
->bg
[GTK_STATE_ACTIVE
] = *bg
; 
4016         style
->base
[GTK_STATE_ACTIVE
] = *bg
; 
4017         style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
) 
4018             (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG 
| GTK_RC_BASE
); 
4020         style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
; 
4021         style
->base
[GTK_STATE_INSENSITIVE
] = *bg
; 
4022         style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
) 
4023             (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG 
| GTK_RC_BASE
); 
4029 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
) 
4031     GtkRcStyle 
*style 
= CreateWidgetStyle(forceStyle
); 
4034         DoApplyWidgetStyle(style
); 
4035         gtk_rc_style_unref(style
); 
4038     // Style change may affect GTK+'s size calculation: 
4039     InvalidateBestSize(); 
4042 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
4045         gtk_widget_modify_style(m_wxwindow
, style
); 
4047         gtk_widget_modify_style(m_widget
, style
); 
4050 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
) 
4052     wxWindowBase::SetBackgroundStyle(style
); 
4054     if (style 
== wxBG_STYLE_CUSTOM
) 
4056         GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4058             window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4060             window 
= GetConnectWidget()->window
; 
4064             // Make sure GDK/X11 doesn't refresh the window 
4066             gdk_window_set_back_pixmap( window
, None
, False 
); 
4068             Display
* display 
= GDK_WINDOW_DISPLAY(window
); 
4071             m_needsStyleChange 
= false; 
4074             // Do in OnIdle, because the window is not yet available 
4075             m_needsStyleChange 
= true; 
4077         // Don't apply widget style, or we get a grey background 
4081         // apply style change (forceStyle=true so that new style is applied 
4082         // even if the bg colour changed from valid to wxNullColour): 
4083         ApplyWidgetStyle(true); 
4088 #if wxUSE_DRAG_AND_DROP 
4090 void wxWindowGTK::SetDropTarget( wxDropTarget 
*dropTarget 
) 
4092     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4094     GtkWidget 
*dnd_widget 
= GetConnectWidget(); 
4096     if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget 
); 
4098     if (m_dropTarget
) delete m_dropTarget
; 
4099     m_dropTarget 
= dropTarget
; 
4101     if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget 
); 
4104 #endif // wxUSE_DRAG_AND_DROP 
4106 GtkWidget
* wxWindowGTK::GetConnectWidget() 
4108     GtkWidget 
*connect_widget 
= m_widget
; 
4109     if (m_wxwindow
) connect_widget 
= m_wxwindow
; 
4111     return connect_widget
; 
4114 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow 
*window 
) 
4117         return (window 
== GTK_PIZZA(m_wxwindow
)->bin_window
); 
4119     return (window 
== m_widget
->window
); 
4122 bool wxWindowGTK::SetFont( const wxFont 
&font 
) 
4124     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid window") ); 
4126     if (!wxWindowBase::SetFont(font
)) 
4129     // apply style change (forceStyle=true so that new style is applied 
4130     // even if the font changed from valid to wxNullFont): 
4131     ApplyWidgetStyle(true); 
4136 void wxWindowGTK::DoCaptureMouse() 
4138     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4140     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4142         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4144         window 
= GetConnectWidget()->window
; 
4146     wxCHECK_RET( window
, _T("CaptureMouse() failed") ); 
4148     wxCursor
* cursor 
= & m_cursor
; 
4150         cursor 
= wxSTANDARD_CURSOR
; 
4152     gdk_pointer_grab( window
, FALSE
, 
4154                          (GDK_BUTTON_PRESS_MASK 
| 
4155                           GDK_BUTTON_RELEASE_MASK 
| 
4156                           GDK_POINTER_MOTION_HINT_MASK 
| 
4157                           GDK_POINTER_MOTION_MASK
), 
4159                       cursor
->GetCursor(), 
4160                       (guint32
)GDK_CURRENT_TIME 
); 
4161     g_captureWindow 
= this; 
4162     g_captureWindowHasMouse 
= true; 
4165 void wxWindowGTK::DoReleaseMouse() 
4167     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4169     wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") ); 
4171     g_captureWindow 
= (wxWindowGTK
*) NULL
; 
4173     GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
4175         window 
= GTK_PIZZA(m_wxwindow
)->bin_window
; 
4177         window 
= GetConnectWidget()->window
; 
4182     gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME 
); 
4186 wxWindow 
*wxWindowBase::GetCapture() 
4188     return (wxWindow 
*)g_captureWindow
; 
4191 bool wxWindowGTK::IsRetained() const 
4196 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
, 
4197       int range
, bool refresh 
) 
4199     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4201     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4203     m_hasScrolling 
= true; 
4205     if (orient 
== wxHORIZONTAL
) 
4207         float fpos 
= (float)pos
; 
4208         float frange 
= (float)range
; 
4209         float fthumb 
= (float)thumbVisible
; 
4210         if (fpos 
> frange
-fthumb
) fpos 
= frange
-fthumb
; 
4211         if (fpos 
< 0.0) fpos 
= 0.0; 
4213         if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) && 
4214             (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2)) 
4216             SetScrollPos( orient
, pos
, refresh 
); 
4220         m_oldHorizontalPos 
= fpos
; 
4222         m_hAdjust
->lower 
= 0.0; 
4223         m_hAdjust
->upper 
= frange
; 
4224         m_hAdjust
->value 
= fpos
; 
4225         m_hAdjust
->step_increment 
= 1.0; 
4226         m_hAdjust
->page_increment 
= (float)(wxMax(fthumb
,0)); 
4227         m_hAdjust
->page_size 
= fthumb
; 
4231         float fpos 
= (float)pos
; 
4232         float frange 
= (float)range
; 
4233         float fthumb 
= (float)thumbVisible
; 
4234         if (fpos 
> frange
-fthumb
) fpos 
= frange
-fthumb
; 
4235         if (fpos 
< 0.0) fpos 
= 0.0; 
4237         if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) && 
4238             (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2)) 
4240             SetScrollPos( orient
, pos
, refresh 
); 
4244         m_oldVerticalPos 
= fpos
; 
4246         m_vAdjust
->lower 
= 0.0; 
4247         m_vAdjust
->upper 
= frange
; 
4248         m_vAdjust
->value 
= fpos
; 
4249         m_vAdjust
->step_increment 
= 1.0; 
4250         m_vAdjust
->page_increment 
= (float)(wxMax(fthumb
,0)); 
4251         m_vAdjust
->page_size 
= fthumb
; 
4254     if (orient 
== wxHORIZONTAL
) 
4255         g_signal_emit_by_name (m_hAdjust
, "changed"); 
4257         g_signal_emit_by_name (m_vAdjust
, "changed"); 
4260 void wxWindowGTK::GtkUpdateScrollbar(int orient
) 
4262     GtkAdjustment 
*adj 
= orient 
== wxHORIZONTAL 
? m_hAdjust 
: m_vAdjust
; 
4263     gpointer fn 
= orient 
== wxHORIZONTAL
 
4264             ? (gpointer
) gtk_window_hscroll_callback
 
4265             : (gpointer
) gtk_window_vscroll_callback
; 
4267     g_signal_handlers_disconnect_by_func (adj
, fn
, this); 
4268     g_signal_emit_by_name (adj
, "value_changed"); 
4269     g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this); 
4272 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) ) 
4274     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4275     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4277     GtkAdjustment 
*adj 
= orient 
== wxHORIZONTAL 
? m_hAdjust 
: m_vAdjust
; 
4279     float fpos 
= (float)pos
; 
4280     if (fpos 
> adj
->upper 
- adj
->page_size
) 
4281         fpos 
= adj
->upper 
- adj
->page_size
; 
4284     *(orient 
== wxHORIZONTAL 
? &m_oldHorizontalPos 
: &m_oldVerticalPos
) = fpos
; 
4286     if (fabs(fpos
-adj
->value
) < 0.2) 
4290     if ( m_wxwindow
->window 
) 
4295 int wxWindowGTK::GetScrollThumb( int orient 
) const 
4297     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4299     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4301     if (orient 
== wxHORIZONTAL
) 
4302         return (int)(m_hAdjust
->page_size
+0.5); 
4304         return (int)(m_vAdjust
->page_size
+0.5); 
4307 int wxWindowGTK::GetScrollPos( int orient 
) const 
4309     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4311     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4313     if (orient 
== wxHORIZONTAL
) 
4314         return (int)(m_hAdjust
->value
+0.5); 
4316         return (int)(m_vAdjust
->value
+0.5); 
4319 int wxWindowGTK::GetScrollRange( int orient 
) const 
4321     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid window") ); 
4323     wxCHECK_MSG( m_wxwindow 
!= NULL
, 0, wxT("window needs client area for scrolling") ); 
4325     if (orient 
== wxHORIZONTAL
) 
4326         return (int)(m_hAdjust
->upper
+0.5); 
4328         return (int)(m_vAdjust
->upper
+0.5); 
4331 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) ) 
4333     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid window") ); 
4335     wxCHECK_RET( m_wxwindow 
!= NULL
, wxT("window needs client area for scrolling") ); 
4337     // No scrolling requested. 
4338     if ((dx 
== 0) && (dy 
== 0)) return; 
4340     m_clipPaintRegion 
= true; 
4342     gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy 
); 
4344     m_clipPaintRegion 
= false; 
4347 void wxWindowGTK::SetWindowStyleFlag( long style 
) 
4349     // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already 
4350     wxWindowBase::SetWindowStyleFlag(style
); 
4353 // Find the wxWindow at the current mouse position, also returning the mouse 
4355 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
) 
4357     pt 
= wxGetMousePosition(); 
4358     wxWindow
* found 
= wxFindWindowAtPoint(pt
); 
4362 // Get the current mouse position. 
4363 wxPoint 
wxGetMousePosition() 
4365   /* This crashes when used within wxHelpContext, 
4366      so we have to use the X-specific implementation below. 
4368     GdkModifierType *mask; 
4369     (void) gdk_window_get_pointer(NULL, &x, &y, mask); 
4371     return wxPoint(x, y); 
4375     GdkWindow
* windowAtPtr 
= gdk_window_at_pointer(& x
, & y
); 
4377     Display 
*display 
= windowAtPtr 
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY(); 
4378     Window rootWindow 
= RootWindowOfScreen (DefaultScreenOfDisplay(display
)); 
4379     Window rootReturn
, childReturn
; 
4380     int rootX
, rootY
, winX
, winY
; 
4381     unsigned int maskReturn
; 
4383     XQueryPointer (display
, 
4387                    &rootX
, &rootY
, &winX
, &winY
, &maskReturn
); 
4388     return wxPoint(rootX
, rootY
); 
4392 // Needed for implementing e.g. combobox on wxGTK within a modal dialog. 
4393 void wxAddGrab(wxWindow
* window
) 
4395     gtk_grab_add( (GtkWidget
*) window
->GetHandle() ); 
4398 void wxRemoveGrab(wxWindow
* window
) 
4400     gtk_grab_remove( (GtkWidget
*) window
->GetHandle() ); 
4403 // ---------------------------------------------------------------------------- 
4405 // ---------------------------------------------------------------------------- 
4407 class wxWinModule 
: public wxModule
 
4414     DECLARE_DYNAMIC_CLASS(wxWinModule
) 
4417 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
) 
4419 bool wxWinModule::OnInit() 
4421     // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() ); 
4422     // gdk_gc_set_fill( g_eraseGC, GDK_SOLID ); 
4427 void wxWinModule::OnExit() 
4430         gdk_gc_unref( g_eraseGC 
);