1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
25 #include "wx/dcclient.h"
27 #include "wx/dialog.h"
28 #include "wx/settings.h"
31 #include "wx/layout.h"
32 #include "wx/msgdlg.h"
33 #include "wx/module.h"
34 #include "wx/combobox.h"
36 #if wxUSE_TOOLBAR_NATIVE
37 #include "wx/toolbar.h"
40 #if wxUSE_DRAG_AND_DROP
45 #include "wx/tooltip.h"
53 #include "wx/textctrl.h"
56 #include "wx/statusbr.h"
57 #include "wx/fontutil.h"
60 #include "wx/thread.h"
66 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
67 #include <gtk/gtkversion.h>
68 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
69 #undef GTK_DISABLE_DEPRECATED
72 #include "wx/gtk/private.h"
73 #include <gdk/gdkprivate.h>
74 #include <gdk/gdkkeysyms.h>
78 #include <gtk/gtkprivate.h>
80 #include "wx/gtk/win_gtk.h"
82 #include <pango/pangox.h>
88 extern GtkContainerClass
*pizza_parent_class
;
90 //-----------------------------------------------------------------------------
91 // documentation on internals
92 //-----------------------------------------------------------------------------
95 I have been asked several times about writing some documentation about
96 the GTK port of wxWidgets, especially its internal structures. Obviously,
97 you cannot understand wxGTK without knowing a little about the GTK, but
98 some more information about what the wxWindow, which is the base class
99 for all other window classes, does seems required as well.
103 What does wxWindow do? It contains the common interface for the following
104 jobs of its descendants:
106 1) Define the rudimentary behaviour common to all window classes, such as
107 resizing, intercepting user input (so as to make it possible to use these
108 events for special purposes in a derived class), window names etc.
110 2) Provide the possibility to contain and manage children, if the derived
111 class is allowed to contain children, which holds true for those window
112 classes which do not display a native GTK widget. To name them, these
113 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
114 work classes are a special case and are handled a bit differently from
115 the rest. The same holds true for the wxNotebook class.
117 3) Provide the possibility to draw into a client area of a window. This,
118 too, only holds true for classes that do not display a native GTK widget
121 4) Provide the entire mechanism for scrolling widgets. This actual inter-
122 face for this is usually in wxScrolledWindow, but the GTK implementation
125 5) A multitude of helper or extra methods for special purposes, such as
126 Drag'n'Drop, managing validators etc.
128 6) Display a border (sunken, raised, simple or none).
130 Normally one might expect, that one wxWidgets window would always correspond
131 to one GTK widget. Under GTK, there is no such allround widget that has all
132 the functionality. Moreover, the GTK defines a client area as a different
133 widget from the actual widget you are handling. Last but not least some
134 special classes (e.g. wxFrame) handle different categories of widgets and
135 still have the possibility to draw something in the client area.
136 It was therefore required to write a special purpose GTK widget, that would
137 represent a client area in the sense of wxWidgets capable to do the jobs
138 2), 3) and 4). I have written this class and it resides in win_gtk.c of
141 All windows must have a widget, with which they interact with other under-
142 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
143 the wxWindow class has a member variable called m_widget which holds a
144 pointer to this widget. When the window class represents a GTK native widget,
145 this is (in most cases) the only GTK widget the class manages. E.g. the
146 wxStaticText class handles only a GtkLabel widget a pointer to which you
147 can find in m_widget (defined in wxWindow)
149 When the class has a client area for drawing into and for containing children
150 it has to handle the client area widget (of the type GtkPizza, defined in
151 win_gtk.c), but there could be any number of widgets, handled by a class
152 The common rule for all windows is only, that the widget that interacts with
153 the rest of GTK must be referenced in m_widget and all other widgets must be
154 children of this widget on the GTK level. The top-most widget, which also
155 represents the client area, must be in the m_wxwindow field and must be of
158 As I said, the window classes that display a GTK native widget only have
159 one widget, so in the case of e.g. the wxButton class m_widget holds a
160 pointer to a GtkButton widget. But windows with client areas (for drawing
161 and children) have a m_widget field that is a pointer to a GtkScrolled-
162 Window and a m_wxwindow field that is pointer to a GtkPizza and this
163 one is (in the GTK sense) a child of the GtkScrolledWindow.
165 If the m_wxwindow field is set, then all input to this widget is inter-
166 cepted and sent to the wxWidgets class. If not, all input to the widget
167 that gets pointed to by m_widget gets intercepted and sent to the class.
171 The design of scrolling in wxWidgets is markedly different from that offered
172 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
173 clicking on a scrollbar belonging to scrolled window will inevitably move
174 the window. In wxWidgets, the scrollbar will only emit an event, send this
175 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
176 which actually moves the window and its subchildren. Note that GtkPizza
177 memorizes how much it has been scrolled but that wxWidgets forgets this
178 so that the two coordinates systems have to be kept in synch. This is done
179 in various places using the pizza->xoffset and pizza->yoffset values.
183 Singularily the most broken code in GTK is the code that is supposed to
184 inform subwindows (child windows) about new positions. Very often, duplicate
185 events are sent without changes in size or position, equally often no
186 events are sent at all (All this is due to a bug in the GtkContainer code
187 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
188 GTK's own system and it simply waits for size events for toplevel windows
189 and then iterates down the respective size events to all window. This has
190 the disadvantage that windows might get size events before the GTK widget
191 actually has the reported size. This doesn't normally pose any problem, but
192 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
193 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
194 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
195 window that is used for OpenGL output really has that size (as reported by
200 If someone at some point of time feels the immense desire to have a look at,
201 change or attempt to optimise the Refresh() logic, this person will need an
202 intimate understanding of what "draw" and "expose" events are and what
203 they are used for, in particular when used in connection with GTK's
204 own windowless widgets. Beware.
208 Cursors, too, have been a constant source of pleasure. The main difficulty
209 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
210 for the parent. To prevent this from doing too much harm, I use idle time
211 to set the cursor over and over again, starting from the toplevel windows
212 and ending with the youngest generation (speaking of parent and child windows).
213 Also don't forget that cursors (like much else) are connected to GdkWindows,
214 not GtkWidgets and that the "window" field of a GtkWidget might very well
215 point to the GdkWindow of the parent widget (-> "window-less widget") and
216 that the two obviously have very different meanings.
220 //-----------------------------------------------------------------------------
222 //-----------------------------------------------------------------------------
224 extern wxList wxPendingDelete
;
225 extern bool g_blockEventsOnDrag
;
226 extern bool g_blockEventsOnScroll
;
227 extern wxCursor g_globalCursor
;
229 static GdkGC
*g_eraseGC
= NULL
;
231 // mouse capture state: the window which has it and if the mouse is currently
233 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
234 static bool g_captureWindowHasMouse
= false;
236 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
238 // the last window which had the focus - this is normally never NULL (except
239 // if we never had focus at all) as even when g_focusWindow is NULL it still
240 // keeps its previous value
241 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
243 // If a window get the focus set but has not been realized
244 // yet, defer setting the focus to idle time.
245 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
247 extern bool g_mainThreadLocked
;
249 //-----------------------------------------------------------------------------
251 //-----------------------------------------------------------------------------
256 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
258 # define DEBUG_MAIN_THREAD
261 #define DEBUG_MAIN_THREAD
264 // the trace mask used for the focus debugging messages
265 #define TRACE_FOCUS _T("focus")
267 //-----------------------------------------------------------------------------
268 // missing gdk functions
269 //-----------------------------------------------------------------------------
272 gdk_window_warp_pointer (GdkWindow
*window
,
277 window
= gdk_get_default_root_window();
279 if (!GDK_WINDOW_DESTROYED(window
))
281 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
282 None
, /* not source window -> move from anywhere */
283 GDK_WINDOW_XID(window
), /* dest window */
284 0, 0, 0, 0, /* not source window -> move from anywhere */
289 //-----------------------------------------------------------------------------
290 // local code (see below)
291 //-----------------------------------------------------------------------------
293 // returns the child of win which currently has focus or NULL if not found
295 // Note: can't be static, needed by textctrl.cpp.
296 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
298 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
300 return (wxWindow
*)NULL
;
302 if ( winFocus
== win
)
303 return (wxWindow
*)win
;
305 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
307 node
= node
->GetNext() )
309 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
314 return (wxWindow
*)NULL
;
317 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
)
319 GtkScrolledWindow
* scroll_window
= GTK_SCROLLED_WINDOW(widget
);
320 GtkScrolledWindowClass
* scroll_class
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
));
321 GtkRequisition scroll_req
;
324 if (scroll_window
->vscrollbar_visible
)
326 scroll_req
.width
= 2;
327 scroll_req
.height
= 2;
328 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
329 (scroll_window
->vscrollbar
, &scroll_req
);
330 w
= scroll_req
.width
+
331 scroll_class
->scrollbar_spacing
;
335 if (scroll_window
->hscrollbar_visible
)
337 scroll_req
.width
= 2;
338 scroll_req
.height
= 2;
339 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
340 (scroll_window
->hscrollbar
, &scroll_req
);
341 h
= scroll_req
.height
+
342 scroll_class
->scrollbar_spacing
;
346 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
348 // wxUniversal widgets draw the borders and scrollbars themselves
349 #ifndef __WXUNIVERSAL__
356 if (win
->m_hasScrolling
)
358 GetScrollbarWidth(widget
, dw
, dh
);
363 if (GTK_WIDGET_NO_WINDOW (widget
))
365 dx
+= widget
->allocation
.x
;
366 dy
+= widget
->allocation
.y
;
369 if (win
->HasFlag(wxRAISED_BORDER
))
371 gtk_paint_shadow (widget
->style
,
375 NULL
, NULL
, NULL
, // FIXME: No clipping?
377 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
381 if (win
->HasFlag(wxSUNKEN_BORDER
))
383 gtk_paint_shadow (widget
->style
,
387 NULL
, NULL
, NULL
, // FIXME: No clipping?
389 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
393 if (win
->HasFlag(wxSIMPLE_BORDER
))
396 gc
= gdk_gc_new( widget
->window
);
397 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
398 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
400 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
404 #endif // __WXUNIVERSAL__
407 //-----------------------------------------------------------------------------
408 // "expose_event" of m_widget
409 //-----------------------------------------------------------------------------
413 gtk_window_own_expose_callback( GtkWidget
*widget
,
414 GdkEventExpose
*gdk_event
,
417 if (gdk_event
->count
> 0) return FALSE
;
419 draw_frame( widget
, win
);
421 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
427 //-----------------------------------------------------------------------------
428 // "size_request" of m_widget
429 //-----------------------------------------------------------------------------
431 // make it extern because wxStaticText needs to disconnect this one
433 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
434 GtkRequisition
*requisition
,
438 win
->GetSize( &w
, &h
);
444 requisition
->height
= h
;
445 requisition
->width
= w
;
451 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
452 GtkRequisition
*requisition
,
455 // This callback is actually hooked into the text entry
456 // of the combo box, not the GtkHBox.
459 win
->GetSize( &w
, &h
);
465 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
467 GtkRequisition entry_req
;
469 entry_req
.height
= 2;
470 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
471 (gcombo
->button
, &entry_req
);
473 requisition
->width
= w
- entry_req
.width
;
474 requisition
->height
= entry_req
.height
;
478 //-----------------------------------------------------------------------------
479 // "expose_event" of m_wxwindow
480 //-----------------------------------------------------------------------------
484 gtk_window_expose_callback( GtkWidget
*widget
,
485 GdkEventExpose
*gdk_event
,
491 wxapp_install_idle_handler();
493 // This callback gets called in drawing-idle time under
494 // GTK 2.0, so we don't need to defer anything to idle
497 GtkPizza
*pizza
= GTK_PIZZA( widget
);
498 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
503 wxPrintf( wxT("OnExpose from ") );
504 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
505 wxPrintf( win
->GetClassInfo()->GetClassName() );
506 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
507 (int)gdk_event
->area
.y
,
508 (int)gdk_event
->area
.width
,
509 (int)gdk_event
->area
.height
);
514 win
->m_wxwindow
->style
,
518 (GdkRectangle
*) NULL
,
520 (char *)"button", // const_cast
525 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
527 win
->GtkSendPaintEvents();
530 // Let parent window draw window-less widgets
531 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
537 //-----------------------------------------------------------------------------
538 // "key_press_event" from any window
539 //-----------------------------------------------------------------------------
541 // set WXTRACE to this to see the key event codes on the console
542 #define TRACE_KEYS _T("keyevent")
544 // translates an X key symbol to WXK_XXX value
546 // if isChar is true it means that the value returned will be used for EVT_CHAR
547 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
548 // for example, while if it is false it means that the value is going to be
549 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
551 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
557 // Shift, Control and Alt don't generate the CHAR events at all
560 key_code
= isChar
? 0 : WXK_SHIFT
;
564 key_code
= isChar
? 0 : WXK_CONTROL
;
572 key_code
= isChar
? 0 : WXK_ALT
;
575 // neither do the toggle modifies
576 case GDK_Scroll_Lock
:
577 key_code
= isChar
? 0 : WXK_SCROLL
;
581 key_code
= isChar
? 0 : WXK_CAPITAL
;
585 key_code
= isChar
? 0 : WXK_NUMLOCK
;
589 // various other special keys
602 case GDK_ISO_Left_Tab
:
609 key_code
= WXK_RETURN
;
613 key_code
= WXK_CLEAR
;
617 key_code
= WXK_PAUSE
;
621 key_code
= WXK_SELECT
;
625 key_code
= WXK_PRINT
;
629 key_code
= WXK_EXECUTE
;
633 key_code
= WXK_ESCAPE
;
636 // cursor and other extended keyboard keys
638 key_code
= WXK_DELETE
;
654 key_code
= WXK_RIGHT
;
661 case GDK_Prior
: // == GDK_Page_Up
662 key_code
= WXK_PAGEUP
;
665 case GDK_Next
: // == GDK_Page_Down
666 key_code
= WXK_PAGEDOWN
;
678 key_code
= WXK_INSERT
;
693 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
697 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
701 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
705 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
709 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
713 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
717 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
721 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
725 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
729 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
733 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
737 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
741 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
744 case GDK_KP_Prior
: // == GDK_KP_Page_Up
745 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
748 case GDK_KP_Next
: // == GDK_KP_Page_Down
749 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
753 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
757 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
761 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
765 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
769 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
772 case GDK_KP_Multiply
:
773 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
777 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
780 case GDK_KP_Separator
:
781 // FIXME: what is this?
782 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
785 case GDK_KP_Subtract
:
786 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
790 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
794 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
811 key_code
= WXK_F1
+ keysym
- GDK_F1
;
821 static inline bool wxIsAsciiKeysym(KeySym ks
)
826 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
828 GdkEventKey
*gdk_event
)
832 GdkModifierType state
;
833 if (gdk_event
->window
)
834 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
836 event
.SetTimestamp( gdk_event
->time
);
837 event
.SetId(win
->GetId());
838 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
839 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
840 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
841 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
842 event
.m_scanCode
= gdk_event
->keyval
;
843 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
844 event
.m_rawFlags
= 0;
846 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
848 wxGetMousePosition( &x
, &y
);
849 win
->ScreenToClient( &x
, &y
);
852 event
.SetEventObject( win
);
857 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
859 GdkEventKey
*gdk_event
)
861 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
862 // but only event->keyval which is quite useless to us, so remember
863 // the last character from GDK_KEY_PRESS and reuse it as last resort
865 // NB: should be MT-safe as we're always called from the main thread only
870 } s_lastKeyPress
= { 0, 0 };
872 KeySym keysym
= gdk_event
->keyval
;
874 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
875 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
879 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
883 // do we have the translation or is it a plain ASCII character?
884 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
886 // we should use keysym if it is ASCII as X does some translations
887 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
888 // which we don't want here (but which we do use for OnChar())
889 if ( !wxIsAsciiKeysym(keysym
) )
891 keysym
= (KeySym
)gdk_event
->string
[0];
894 // we want to always get the same key code when the same key is
895 // pressed regardless of the state of the modifiers, i.e. on a
896 // standard US keyboard pressing '5' or '%' ('5' key with
897 // Shift) should result in the same key code in OnKeyDown():
898 // '5' (although OnChar() will get either '5' or '%').
900 // to do it we first translate keysym to keycode (== scan code)
901 // and then back but always using the lower register
902 Display
*dpy
= (Display
*)wxGetDisplay();
903 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
905 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
907 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
909 // use the normalized, i.e. lower register, keysym if we've
911 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
913 // as explained above, we want to have lower register key codes
914 // normally but for the letter keys we want to have the upper ones
916 // NB: don't use XConvertCase() here, we want to do it for letters
918 key_code
= toupper(key_code
);
920 else // non ASCII key, what to do?
922 // by default, ignore it
925 // but if we have cached information from the last KEY_PRESS
926 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
929 if ( keysym
== s_lastKeyPress
.keysym
)
931 key_code
= s_lastKeyPress
.keycode
;
936 if ( gdk_event
->type
== GDK_KEY_PRESS
)
938 // remember it to be reused for KEY_UP event later
939 s_lastKeyPress
.keysym
= keysym
;
940 s_lastKeyPress
.keycode
= key_code
;
944 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
946 // sending unknown key events doesn't really make sense
950 // now fill all the other fields
951 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
953 event
.m_keyCode
= key_code
;
955 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
957 event
.m_uniChar
= key_code
;
967 GtkIMContext
*context
;
968 GdkEventKey
*lastKeyEvent
;
972 context
= gtk_im_multicontext_new();
977 g_object_unref (context
);
983 gtk_window_key_press_callback( GtkWidget
*widget
,
984 GdkEventKey
*gdk_event
,
990 wxapp_install_idle_handler();
994 if (g_blockEventsOnDrag
)
998 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1000 bool return_after_IM
= false;
1002 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1004 // Emit KEY_DOWN event
1005 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1009 // Return after IM processing as we cannot do
1010 // anything with it anyhow.
1011 return_after_IM
= true;
1014 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1015 // When we get a key_press event here, it could be originate
1016 // from the current widget or its child widgets. However, only the widget
1017 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1018 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1019 // originated from its child widgets and shouldn't be passed to IM context.
1020 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1021 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1022 // widgets has both IM context and input focus, the event should be filtered
1023 // by gtk_im_context_filter_keypress().
1024 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1025 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1027 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1028 // docs, if IM filter returns true, no further processing should be done.
1029 // we should send the key_down event anyway.
1030 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1031 win
->m_imData
->lastKeyEvent
= NULL
;
1032 if (intercepted_by_IM
)
1034 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1039 if (return_after_IM
)
1045 wxWindowGTK
*ancestor
= win
;
1048 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1051 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1052 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1055 if (ancestor
->IsTopLevel())
1057 ancestor
= ancestor
->GetParent();
1060 #endif // wxUSE_ACCEL
1062 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1063 // will only be sent if it is not in an accelerator table.
1067 KeySym keysym
= gdk_event
->keyval
;
1068 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1069 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1072 if ( wxIsAsciiKeysym(keysym
) )
1075 key_code
= (unsigned char)keysym
;
1077 // gdk_event->string is actually deprecated
1078 else if ( gdk_event
->length
== 1 )
1080 key_code
= (unsigned char)gdk_event
->string
[0];
1086 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1088 event
.m_keyCode
= key_code
;
1090 // To conform to the docs we need to translate Ctrl-alpha
1091 // characters to values in the range 1-26.
1092 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1094 event
.m_keyCode
= key_code
- 'a' + 1;
1096 event
.m_uniChar
= event
.m_keyCode
;
1100 // Implement OnCharHook by checking ancestor top level windows
1101 wxWindow
*parent
= win
;
1102 while (parent
&& !parent
->IsTopLevel())
1103 parent
= parent
->GetParent();
1106 event
.SetEventType( wxEVT_CHAR_HOOK
);
1107 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1112 event
.SetEventType(wxEVT_CHAR
);
1113 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1122 // win is a control: tab can be propagated up
1124 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1125 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1126 // have this style, yet choose not to process this particular TAB in which
1127 // case TAB must still work as a navigational character
1128 // JS: enabling again to make consistent with other platforms
1129 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1130 // navigation behaviour)
1132 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1134 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1136 wxNavigationKeyEvent new_event
;
1137 new_event
.SetEventObject( win
->GetParent() );
1138 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1139 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1140 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1141 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1142 new_event
.SetCurrentFocus( win
);
1143 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1146 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1148 (gdk_event
->keyval
== GDK_Escape
) )
1150 // however only do it if we have a Cancel button in the dialog,
1151 // otherwise the user code may get confused by the events from a
1152 // non-existing button and, worse, a wxButton might get button event
1153 // from another button which is not really expected
1154 wxWindow
*winForCancel
= win
,
1156 while ( winForCancel
)
1158 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1161 // found a cancel button
1165 if ( winForCancel
->IsTopLevel() )
1167 // no need to look further
1171 // maybe our parent has a cancel button?
1172 winForCancel
= winForCancel
->GetParent();
1177 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1178 eventClick
.SetEventObject(btnCancel
);
1179 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1185 g_signal_stop_emission_by_name (widget
, "key_press_event");
1195 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1199 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1201 // take modifiers, cursor position, timestamp etc. from the last
1202 // key_press_event that was fed into Input Method:
1203 if (window
->m_imData
->lastKeyEvent
)
1205 wxFillOtherKeyEventFields(event
,
1206 window
, window
->m_imData
->lastKeyEvent
);
1209 const wxWxCharBuffer
data(wxGTK_CONV_BACK(str
));
1215 // Implement OnCharHook by checking ancestor top level windows
1216 wxWindow
*parent
= window
;
1217 while (parent
&& !parent
->IsTopLevel())
1218 parent
= parent
->GetParent();
1220 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1223 event
.m_uniChar
= *pstr
;
1224 // Backward compatible for ISO-8859-1
1225 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1226 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1228 event
.m_keyCode
= *pstr
;
1229 #endif // wxUSE_UNICODE
1231 // To conform to the docs we need to translate Ctrl-alpha
1232 // characters to values in the range 1-26.
1233 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1235 event
.m_keyCode
= *pstr
- 'a' + 1;
1237 event
.m_uniChar
= event
.m_keyCode
;
1243 event
.SetEventType( wxEVT_CHAR_HOOK
);
1244 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1249 event
.SetEventType(wxEVT_CHAR
);
1250 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1257 //-----------------------------------------------------------------------------
1258 // "key_release_event" from any window
1259 //-----------------------------------------------------------------------------
1263 gtk_window_key_release_callback( GtkWidget
*widget
,
1264 GdkEventKey
*gdk_event
,
1270 wxapp_install_idle_handler();
1275 if (g_blockEventsOnDrag
)
1278 wxKeyEvent
event( wxEVT_KEY_UP
);
1279 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1281 // unknown key pressed, ignore (the event would be useless anyhow)
1285 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1288 g_signal_stop_emission_by_name (widget
, "key_release_event");
1293 // ============================================================================
1295 // ============================================================================
1297 // ----------------------------------------------------------------------------
1298 // mouse event processing helpers
1299 // ----------------------------------------------------------------------------
1301 // init wxMouseEvent with the info from GdkEventXXX struct
1302 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1303 wxMouseEvent
& event
,
1306 event
.SetTimestamp( gdk_event
->time
);
1307 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1308 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1309 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1310 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1311 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1312 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1313 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1314 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1316 event
.m_linesPerAction
= 3;
1317 event
.m_wheelDelta
= 120;
1318 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1319 event
.m_wheelRotation
= 120;
1320 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1321 event
.m_wheelRotation
= -120;
1324 wxPoint pt
= win
->GetClientAreaOrigin();
1325 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1326 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1328 event
.SetEventObject( win
);
1329 event
.SetId( win
->GetId() );
1330 event
.SetTimestamp( gdk_event
->time
);
1333 static void AdjustEventButtonState(wxMouseEvent
& event
)
1335 // GDK reports the old state of the button for a button press event, but
1336 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1337 // for a LEFT_DOWN event, not FALSE, so we will invert
1338 // left/right/middleDown for the corresponding click events
1340 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1341 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1342 (event
.GetEventType() == wxEVT_LEFT_UP
))
1344 event
.m_leftDown
= !event
.m_leftDown
;
1348 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1349 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1350 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1352 event
.m_middleDown
= !event
.m_middleDown
;
1356 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1357 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1358 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1360 event
.m_rightDown
= !event
.m_rightDown
;
1365 // find the window to send the mouse event too
1367 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1372 if (win
->m_wxwindow
)
1374 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1375 xx
+= pizza
->xoffset
;
1376 yy
+= pizza
->yoffset
;
1379 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1382 wxWindowGTK
*child
= node
->GetData();
1384 node
= node
->GetNext();
1385 if (!child
->IsShown())
1388 if (child
->IsTransparentForMouse())
1390 // wxStaticBox is transparent in the box itself
1391 int xx1
= child
->m_x
;
1392 int yy1
= child
->m_y
;
1393 int xx2
= child
->m_x
+ child
->m_width
;
1394 int yy2
= child
->m_y
+ child
->m_height
;
1397 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1399 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1401 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1403 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1414 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1415 (child
->m_x
<= xx
) &&
1416 (child
->m_y
<= yy
) &&
1417 (child
->m_x
+child
->m_width
>= xx
) &&
1418 (child
->m_y
+child
->m_height
>= yy
))
1431 //-----------------------------------------------------------------------------
1432 // "button_press_event"
1433 //-----------------------------------------------------------------------------
1437 gtk_window_button_press_callback( GtkWidget
*widget
,
1438 GdkEventButton
*gdk_event
,
1444 wxapp_install_idle_handler();
1447 wxPrintf( wxT("1) OnButtonPress from ") );
1448 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1449 wxPrintf( win->GetClassInfo()->GetClassName() );
1450 wxPrintf( wxT(".\n") );
1452 if (!win
->m_hasVMT
) return FALSE
;
1453 if (g_blockEventsOnDrag
) return TRUE
;
1454 if (g_blockEventsOnScroll
) return TRUE
;
1456 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1458 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1460 gtk_widget_grab_focus( win
->m_wxwindow
);
1462 wxPrintf( wxT("GrabFocus from ") );
1463 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1464 wxPrintf( win->GetClassInfo()->GetClassName() );
1465 wxPrintf( wxT(".\n") );
1469 // GDK sends surplus button down events
1470 // before a double click event. We
1471 // need to filter these out.
1472 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1474 GdkEvent
*peek_event
= gdk_event_peek();
1477 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1478 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1480 gdk_event_free( peek_event
);
1485 gdk_event_free( peek_event
);
1490 wxEventType event_type
= wxEVT_NULL
;
1492 // GdkDisplay is a GTK+ 2.2.0 thing
1493 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1494 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1495 !gtk_check_version(2,2,0) &&
1496 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1498 // Reset GDK internal timestamp variables in order to disable GDK
1499 // triple click events. GDK will then next time believe no button has
1500 // been clicked just before, and send a normal button click event.
1501 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1502 display
->button_click_time
[1] = 0;
1503 display
->button_click_time
[0] = 0;
1507 if (gdk_event
->button
== 1)
1509 // note that GDK generates triple click events which are not supported
1510 // by wxWidgets but still have to be passed to the app as otherwise
1511 // clicks would simply go missing
1512 switch (gdk_event
->type
)
1514 // we shouldn't get triple clicks at all for GTK2 because we
1515 // suppress them artificially using the code above but we still
1516 // should map them to something for GTK1 and not just ignore them
1517 // as this would lose clicks
1518 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1519 case GDK_BUTTON_PRESS
:
1520 event_type
= wxEVT_LEFT_DOWN
;
1523 case GDK_2BUTTON_PRESS
:
1524 event_type
= wxEVT_LEFT_DCLICK
;
1528 // just to silence gcc warnings
1532 else if (gdk_event
->button
== 2)
1534 switch (gdk_event
->type
)
1536 case GDK_3BUTTON_PRESS
:
1537 case GDK_BUTTON_PRESS
:
1538 event_type
= wxEVT_MIDDLE_DOWN
;
1541 case GDK_2BUTTON_PRESS
:
1542 event_type
= wxEVT_MIDDLE_DCLICK
;
1549 else if (gdk_event
->button
== 3)
1551 switch (gdk_event
->type
)
1553 case GDK_3BUTTON_PRESS
:
1554 case GDK_BUTTON_PRESS
:
1555 event_type
= wxEVT_RIGHT_DOWN
;
1558 case GDK_2BUTTON_PRESS
:
1559 event_type
= wxEVT_RIGHT_DCLICK
;
1566 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1568 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1570 event_type
= wxEVT_MOUSEWHEEL
;
1574 if ( event_type
== wxEVT_NULL
)
1576 // unknown mouse button or click type
1580 wxMouseEvent
event( event_type
);
1581 InitMouseEvent( win
, event
, gdk_event
);
1583 AdjustEventButtonState(event
);
1585 // wxListBox actually gets mouse events from the item, so we need to give it
1586 // a chance to correct this
1587 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1589 // find the correct window to send the event to: it may be a different one
1590 // from the one which got it at GTK+ level because some controls don't have
1591 // their own X window and thus cannot get any events.
1592 if ( !g_captureWindow
)
1593 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1595 // reset the event object and id in case win changed.
1596 event
.SetEventObject( win
);
1597 event
.SetId( win
->GetId() );
1599 if (win
->GetEventHandler()->ProcessEvent( event
))
1601 g_signal_stop_emission_by_name (widget
, "button_press_event");
1605 if (event_type
== wxEVT_RIGHT_DOWN
)
1607 // generate a "context menu" event: this is similar to right mouse
1608 // click under many GUIs except that it is generated differently
1609 // (right up under MSW, ctrl-click under Mac, right down here) and
1611 // (a) it's a command event and so is propagated to the parent
1612 // (b) under some ports it can be generated from kbd too
1613 // (c) it uses screen coords (because of (a))
1614 wxContextMenuEvent
evtCtx(
1617 win
->ClientToScreen(event
.GetPosition()));
1618 evtCtx
.SetEventObject(win
);
1619 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1626 //-----------------------------------------------------------------------------
1627 // "button_release_event"
1628 //-----------------------------------------------------------------------------
1632 gtk_window_button_release_callback( GtkWidget
*widget
,
1633 GdkEventButton
*gdk_event
,
1639 wxapp_install_idle_handler();
1641 if (!win
->m_hasVMT
) return FALSE
;
1642 if (g_blockEventsOnDrag
) return FALSE
;
1643 if (g_blockEventsOnScroll
) return FALSE
;
1645 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1647 wxEventType event_type
= wxEVT_NULL
;
1649 switch (gdk_event
->button
)
1652 event_type
= wxEVT_LEFT_UP
;
1656 event_type
= wxEVT_MIDDLE_UP
;
1660 event_type
= wxEVT_RIGHT_UP
;
1664 // unknwon button, don't process
1668 wxMouseEvent
event( event_type
);
1669 InitMouseEvent( win
, event
, gdk_event
);
1671 AdjustEventButtonState(event
);
1673 // same wxListBox hack as above
1674 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1676 if ( !g_captureWindow
)
1677 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1679 // reset the event object and id in case win changed.
1680 event
.SetEventObject( win
);
1681 event
.SetId( win
->GetId() );
1683 if (win
->GetEventHandler()->ProcessEvent( event
))
1685 g_signal_stop_emission_by_name (widget
, "button_release_event");
1693 //-----------------------------------------------------------------------------
1694 // "motion_notify_event"
1695 //-----------------------------------------------------------------------------
1699 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1700 GdkEventMotion
*gdk_event
,
1706 wxapp_install_idle_handler();
1708 if (!win
->m_hasVMT
) return FALSE
;
1709 if (g_blockEventsOnDrag
) return FALSE
;
1710 if (g_blockEventsOnScroll
) return FALSE
;
1712 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1714 if (gdk_event
->is_hint
)
1718 GdkModifierType state
;
1719 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1725 printf( "OnMotion from " );
1726 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1727 printf( win->GetClassInfo()->GetClassName() );
1731 wxMouseEvent
event( wxEVT_MOTION
);
1732 InitMouseEvent(win
, event
, gdk_event
);
1734 if ( g_captureWindow
)
1736 // synthetize a mouse enter or leave event if needed
1737 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1738 // This seems to be necessary and actually been added to
1739 // GDK itself in version 2.0.X
1742 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1743 if ( hasMouse
!= g_captureWindowHasMouse
)
1745 // the mouse changed window
1746 g_captureWindowHasMouse
= hasMouse
;
1748 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1749 : wxEVT_LEAVE_WINDOW
);
1750 InitMouseEvent(win
, eventM
, gdk_event
);
1751 eventM
.SetEventObject(win
);
1752 win
->GetEventHandler()->ProcessEvent(eventM
);
1757 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1759 // reset the event object and id in case win changed.
1760 event
.SetEventObject( win
);
1761 event
.SetId( win
->GetId() );
1764 if ( !g_captureWindow
)
1766 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1767 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1769 // Rewrite cursor handling here (away from idle).
1773 if (win
->GetEventHandler()->ProcessEvent( event
))
1775 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1783 //-----------------------------------------------------------------------------
1784 // "scroll_event", (mouse wheel event)
1785 //-----------------------------------------------------------------------------
1789 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1794 wxapp_install_idle_handler();
1796 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1797 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1802 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1803 // Can't use InitMouse macro because scroll events don't have button
1804 event
.SetTimestamp( gdk_event
->time
);
1805 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1806 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1807 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1808 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1809 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1810 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1811 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1812 event
.m_linesPerAction
= 3;
1813 event
.m_wheelDelta
= 120;
1814 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1815 event
.m_wheelRotation
= 120;
1817 event
.m_wheelRotation
= -120;
1819 wxPoint pt
= win
->GetClientAreaOrigin();
1820 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1821 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1823 event
.SetEventObject( win
);
1824 event
.SetId( win
->GetId() );
1825 event
.SetTimestamp( gdk_event
->time
);
1827 return win
->GetEventHandler()->ProcessEvent(event
);
1831 //-----------------------------------------------------------------------------
1833 //-----------------------------------------------------------------------------
1835 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1837 wxContextMenuEvent
event(
1841 event
.SetEventObject(win
);
1842 return win
->GetEventHandler()->ProcessEvent(event
);
1846 //-----------------------------------------------------------------------------
1848 //-----------------------------------------------------------------------------
1850 // send the wxChildFocusEvent and wxFocusEvent, common code of
1851 // gtk_window_focus_in_callback() and SetFocus()
1852 static bool DoSendFocusEvents(wxWindow
*win
)
1854 // Notify the parent keeping track of focus for the kbd navigation
1855 // purposes that we got it.
1856 wxChildFocusEvent
eventChildFocus(win
);
1857 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1859 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1860 eventFocus
.SetEventObject(win
);
1862 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1867 gtk_window_focus_in_callback( GtkWidget
*widget
,
1868 GdkEventFocus
*WXUNUSED(event
),
1874 wxapp_install_idle_handler();
1877 gtk_im_context_focus_in(win
->m_imData
->context
);
1880 g_focusWindow
= win
;
1882 wxLogTrace(TRACE_FOCUS
,
1883 _T("%s: focus in"), win
->GetName().c_str());
1887 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1891 // caret needs to be informed about focus change
1892 wxCaret
*caret
= win
->GetCaret();
1895 caret
->OnSetFocus();
1897 #endif // wxUSE_CARET
1899 gboolean ret
= FALSE
;
1901 // does the window itself think that it has the focus?
1902 if ( !win
->m_hasFocus
)
1904 // not yet, notify it
1905 win
->m_hasFocus
= true;
1907 (void)DoSendFocusEvents(win
);
1912 // Disable default focus handling for custom windows
1913 // since the default GTK+ handler issues a repaint
1914 if (win
->m_wxwindow
)
1921 //-----------------------------------------------------------------------------
1922 // "focus_out_event"
1923 //-----------------------------------------------------------------------------
1927 gtk_window_focus_out_callback( GtkWidget
*widget
,
1928 GdkEventFocus
*gdk_event
,
1934 wxapp_install_idle_handler();
1937 gtk_im_context_focus_out(win
->m_imData
->context
);
1939 wxLogTrace( TRACE_FOCUS
,
1940 _T("%s: focus out"), win
->GetName().c_str() );
1943 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1947 g_focusWindow
= (wxWindowGTK
*)NULL
;
1955 // caret needs to be informed about focus change
1956 wxCaret
*caret
= win
->GetCaret();
1959 caret
->OnKillFocus();
1961 #endif // wxUSE_CARET
1963 gboolean ret
= FALSE
;
1965 // don't send the window a kill focus event if it thinks that it doesn't
1966 // have focus already
1967 if ( win
->m_hasFocus
)
1969 win
->m_hasFocus
= false;
1971 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1972 event
.SetEventObject( win
);
1974 (void)win
->GetEventHandler()->ProcessEvent( event
);
1979 // Disable default focus handling for custom windows
1980 // since the default GTK+ handler issues a repaint
1981 if (win
->m_wxwindow
)
1988 //-----------------------------------------------------------------------------
1989 // "enter_notify_event"
1990 //-----------------------------------------------------------------------------
1994 gtk_window_enter_callback( GtkWidget
*widget
,
1995 GdkEventCrossing
*gdk_event
,
2001 wxapp_install_idle_handler();
2003 if (!win
->m_hasVMT
) return FALSE
;
2004 if (g_blockEventsOnDrag
) return FALSE
;
2006 // Event was emitted after a grab
2007 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2009 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2013 GdkModifierType state
= (GdkModifierType
)0;
2015 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2017 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2018 InitMouseEvent(win
, event
, gdk_event
);
2019 wxPoint pt
= win
->GetClientAreaOrigin();
2020 event
.m_x
= x
+ pt
.x
;
2021 event
.m_y
= y
+ pt
.y
;
2023 if ( !g_captureWindow
)
2025 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2026 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2028 // Rewrite cursor handling here (away from idle).
2032 if (win
->GetEventHandler()->ProcessEvent( event
))
2034 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2042 //-----------------------------------------------------------------------------
2043 // "leave_notify_event"
2044 //-----------------------------------------------------------------------------
2048 gtk_window_leave_callback( GtkWidget
*widget
,
2049 GdkEventCrossing
*gdk_event
,
2055 wxapp_install_idle_handler();
2057 if (!win
->m_hasVMT
) return FALSE
;
2058 if (g_blockEventsOnDrag
) return FALSE
;
2060 // Event was emitted after an ungrab
2061 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2063 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2065 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2066 event
.SetTimestamp( gdk_event
->time
);
2067 event
.SetEventObject( win
);
2071 GdkModifierType state
= (GdkModifierType
)0;
2073 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2075 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2076 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2077 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2078 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2079 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2080 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2081 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2083 wxPoint pt
= win
->GetClientAreaOrigin();
2084 event
.m_x
= x
+ pt
.x
;
2085 event
.m_y
= y
+ pt
.y
;
2087 if (win
->GetEventHandler()->ProcessEvent( event
))
2089 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2097 //-----------------------------------------------------------------------------
2098 // "value_changed" from scrollbar
2099 //-----------------------------------------------------------------------------
2103 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
2105 wxEventType eventType
= win
->GetScrollEventType(range
);
2106 if (eventType
!= wxEVT_NULL
)
2108 // Convert scroll event type to scrollwin event type
2109 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
2110 const int orient
= range
== win
->m_scrollBar
[0] ? wxHORIZONTAL
: wxVERTICAL
;
2111 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
2112 event
.SetEventObject(win
);
2113 win
->GetEventHandler()->ProcessEvent(event
);
2118 //-----------------------------------------------------------------------------
2119 // "button_press_event" from scrollbar
2120 //-----------------------------------------------------------------------------
2124 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
2129 wxapp_install_idle_handler();
2131 g_blockEventsOnScroll
= true;
2132 win
->m_mouseButtonDown
= true;
2138 //-----------------------------------------------------------------------------
2139 // "button_release_event" from scrollbar
2140 //-----------------------------------------------------------------------------
2144 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
2148 g_blockEventsOnScroll
= false;
2149 win
->m_mouseButtonDown
= false;
2150 // If thumb tracking
2151 if (win
->m_isScrolling
)
2153 win
->m_isScrolling
= false;
2154 const int orient
= range
== win
->m_scrollBar
[0] ? wxHORIZONTAL
: wxVERTICAL
;
2155 wxScrollWinEvent
event(wxEVT_SCROLLWIN_THUMBRELEASE
, win
->GetScrollPos(orient
), orient
);
2156 event
.SetEventObject(win
);
2157 win
->GetEventHandler()->ProcessEvent(event
);
2164 // ----------------------------------------------------------------------------
2165 // this wxWindowBase function is implemented here (in platform-specific file)
2166 // because it is static and so couldn't be made virtual
2167 // ----------------------------------------------------------------------------
2169 wxWindow
*wxWindowBase::DoFindFocus()
2171 // the cast is necessary when we compile in wxUniversal mode
2172 return (wxWindow
*)g_focusWindow
;
2175 //-----------------------------------------------------------------------------
2176 // "realize" from m_widget
2177 //-----------------------------------------------------------------------------
2179 /* We cannot set colours and fonts before the widget has
2180 been realized, so we do this directly after realization. */
2184 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2189 wxapp_install_idle_handler();
2193 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2194 gtk_im_context_set_client_window( win
->m_imData
->context
,
2195 pizza
->bin_window
);
2198 wxWindowCreateEvent
event( win
);
2199 event
.SetEventObject( win
);
2200 win
->GetEventHandler()->ProcessEvent( event
);
2204 //-----------------------------------------------------------------------------
2206 //-----------------------------------------------------------------------------
2210 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2211 GtkAllocation
*WXUNUSED(alloc
),
2215 wxapp_install_idle_handler();
2217 int client_width
= 0;
2218 int client_height
= 0;
2219 win
->GetClientSize( &client_width
, &client_height
);
2220 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2223 win
->m_oldClientWidth
= client_width
;
2224 win
->m_oldClientHeight
= client_height
;
2226 if (!win
->m_nativeSizeEvent
)
2228 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2229 event
.SetEventObject( win
);
2230 win
->GetEventHandler()->ProcessEvent( event
);
2237 #define WXUNUSED_UNLESS_XIM(param) param
2239 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2242 /* Resize XIM window */
2246 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2247 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2248 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2251 wxapp_install_idle_handler();
2257 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2261 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2262 win
->m_icattr
->preedit_area
.width
= width
;
2263 win
->m_icattr
->preedit_area
.height
= height
;
2264 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2270 //-----------------------------------------------------------------------------
2271 // "realize" from m_wxwindow
2272 //-----------------------------------------------------------------------------
2274 /* Initialize XIM support */
2278 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2279 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2282 wxapp_install_idle_handler();
2285 if (win
->m_ic
) return;
2286 if (!widget
) return;
2287 if (!gdk_im_ready()) return;
2289 win
->m_icattr
= gdk_ic_attr_new();
2290 if (!win
->m_icattr
) return;
2294 GdkColormap
*colormap
;
2295 GdkICAttr
*attr
= win
->m_icattr
;
2296 unsigned attrmask
= GDK_IC_ALL_REQ
;
2298 GdkIMStyle supported_style
= (GdkIMStyle
)
2299 (GDK_IM_PREEDIT_NONE
|
2300 GDK_IM_PREEDIT_NOTHING
|
2301 GDK_IM_PREEDIT_POSITION
|
2302 GDK_IM_STATUS_NONE
|
2303 GDK_IM_STATUS_NOTHING
);
2305 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2306 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2308 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2309 attr
->client_window
= widget
->window
;
2311 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2312 gtk_widget_get_default_colormap ())
2314 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2315 attr
->preedit_colormap
= colormap
;
2318 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2319 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2320 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2321 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2323 switch (style
& GDK_IM_PREEDIT_MASK
)
2325 case GDK_IM_PREEDIT_POSITION
:
2326 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2328 g_warning ("over-the-spot style requires fontset");
2332 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2334 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2335 attr
->spot_location
.x
= 0;
2336 attr
->spot_location
.y
= height
;
2337 attr
->preedit_area
.x
= 0;
2338 attr
->preedit_area
.y
= 0;
2339 attr
->preedit_area
.width
= width
;
2340 attr
->preedit_area
.height
= height
;
2341 attr
->preedit_fontset
= widget
->style
->font
;
2346 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2348 if (win
->m_ic
== NULL
)
2349 g_warning ("Can't create input context.");
2352 mask
= gdk_window_get_events (widget
->window
);
2353 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2354 gdk_window_set_events (widget
->window
, mask
);
2356 if (GTK_WIDGET_HAS_FOCUS(widget
))
2357 gdk_im_begin (win
->m_ic
, widget
->window
);
2363 //-----------------------------------------------------------------------------
2364 // InsertChild for wxWindowGTK.
2365 //-----------------------------------------------------------------------------
2367 /* Callback for wxWindowGTK. This very strange beast has to be used because
2368 * C++ has no virtual methods in a constructor. We have to emulate a
2369 * virtual function here as wxNotebook requires a different way to insert
2370 * a child in it. I had opted for creating a wxNotebookPage window class
2371 * which would have made this superfluous (such in the MDI window system),
2372 * but no-one was listening to me... */
2374 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2376 /* the window might have been scrolled already, do we
2377 have to adapt the position */
2378 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2379 child
->m_x
+= pizza
->xoffset
;
2380 child
->m_y
+= pizza
->yoffset
;
2382 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2383 GTK_WIDGET(child
->m_widget
),
2390 //-----------------------------------------------------------------------------
2392 //-----------------------------------------------------------------------------
2394 wxWindow
*wxGetActiveWindow()
2396 return wxWindow::FindFocus();
2400 wxMouseState
wxGetMouseState()
2406 GdkModifierType mask
;
2408 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2412 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2413 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2414 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2416 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2417 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2418 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2419 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2424 //-----------------------------------------------------------------------------
2426 //-----------------------------------------------------------------------------
2428 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2430 #ifdef __WXUNIVERSAL__
2431 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2433 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2434 #endif // __WXUNIVERSAL__/__WXGTK__
2436 void wxWindowGTK::Init()
2439 m_widget
= (GtkWidget
*) NULL
;
2440 m_wxwindow
= (GtkWidget
*) NULL
;
2441 m_focusWidget
= (GtkWidget
*) NULL
;
2451 m_needParent
= true;
2452 m_isBeingDeleted
= false;
2455 m_nativeSizeEvent
= false;
2457 m_hasScrolling
= false;
2458 m_isScrolling
= false;
2459 m_mouseButtonDown
= false;
2460 m_blockScrollEvent
= false;
2463 m_scrollBar
[1] = NULL
;
2468 m_oldClientHeight
= 0;
2472 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2474 m_acceptsFocus
= false;
2477 m_clipPaintRegion
= false;
2479 m_needsStyleChange
= false;
2481 m_cursor
= *wxSTANDARD_CURSOR
;
2484 m_dirtyTabOrder
= false;
2487 wxWindowGTK::wxWindowGTK()
2492 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2497 const wxString
&name
)
2501 Create( parent
, id
, pos
, size
, style
, name
);
2504 bool wxWindowGTK::Create( wxWindow
*parent
,
2509 const wxString
&name
)
2511 if (!PreCreation( parent
, pos
, size
) ||
2512 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2514 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2518 m_insertCallback
= wxInsertChildInWindow
;
2520 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2521 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2523 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2525 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2526 scroll_class
->scrollbar_spacing
= 0;
2528 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2530 m_scrollBar
[0] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2531 m_scrollBar
[1] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2533 m_wxwindow
= gtk_pizza_new();
2535 #ifndef __WXUNIVERSAL__
2536 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2538 if (HasFlag(wxRAISED_BORDER
))
2540 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2542 else if (HasFlag(wxSUNKEN_BORDER
))
2544 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2546 else if (HasFlag(wxSIMPLE_BORDER
))
2548 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2552 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2554 #endif // __WXUNIVERSAL__
2556 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2558 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2559 m_acceptsFocus
= true;
2561 // these handlers block mouse events to any window during scrolling such as
2562 // motion events and prevent GTK and wxWidgets from fighting over where the
2564 g_signal_connect(m_scrollBar
[0], "button_press_event",
2565 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2566 g_signal_connect(m_scrollBar
[1], "button_press_event",
2567 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2568 g_signal_connect(m_scrollBar
[0], "button_release_event",
2569 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2570 g_signal_connect(m_scrollBar
[1], "button_release_event",
2571 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2573 // these handlers get notified when scrollbar slider moves
2575 g_signal_connect(m_scrollBar
[0], "value_changed",
2576 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2577 g_signal_connect(m_scrollBar
[1], "value_changed",
2578 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2580 gtk_widget_show( m_wxwindow
);
2583 m_parent
->DoAddChild( this );
2585 m_focusWidget
= m_wxwindow
;
2592 wxWindowGTK::~wxWindowGTK()
2596 if (g_focusWindow
== this)
2597 g_focusWindow
= NULL
;
2599 if ( g_delayedFocus
== this )
2600 g_delayedFocus
= NULL
;
2602 m_isBeingDeleted
= true;
2605 // destroy children before destroying this window itself
2608 // unhook focus handlers to prevent stray events being
2609 // propagated to this (soon to be) dead object
2610 if (m_focusWidget
!= NULL
)
2612 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2613 (gpointer
) gtk_window_focus_in_callback
,
2615 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2616 (gpointer
) gtk_window_focus_out_callback
,
2625 gdk_ic_destroy (m_ic
);
2627 gdk_ic_attr_destroy (m_icattr
);
2630 // delete before the widgets to avoid a crash on solaris
2635 gtk_widget_destroy( m_wxwindow
);
2636 m_wxwindow
= (GtkWidget
*) NULL
;
2641 gtk_widget_destroy( m_widget
);
2642 m_widget
= (GtkWidget
*) NULL
;
2646 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2648 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2650 // Use either the given size, or the default if -1 is given.
2651 // See wxWindowBase for these functions.
2652 m_width
= WidthDefault(size
.x
) ;
2653 m_height
= HeightDefault(size
.y
);
2661 void wxWindowGTK::PostCreation()
2663 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2669 // these get reported to wxWidgets -> wxPaintEvent
2671 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2673 g_signal_connect (m_wxwindow
, "expose_event",
2674 G_CALLBACK (gtk_window_expose_callback
), this);
2676 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2679 // Create input method handler
2680 m_imData
= new wxGtkIMData
;
2682 // Cannot handle drawing preedited text yet
2683 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2685 g_signal_connect (m_imData
->context
, "commit",
2686 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2688 // these are called when the "sunken" or "raised" borders are drawn
2689 g_signal_connect (m_widget
, "expose_event",
2690 G_CALLBACK (gtk_window_own_expose_callback
), this);
2695 if (!GTK_IS_WINDOW(m_widget
))
2697 if (m_focusWidget
== NULL
)
2698 m_focusWidget
= m_widget
;
2702 g_signal_connect (m_focusWidget
, "focus_in_event",
2703 G_CALLBACK (gtk_window_focus_in_callback
), this);
2704 g_signal_connect (m_focusWidget
, "focus_out_event",
2705 G_CALLBACK (gtk_window_focus_out_callback
), this);
2709 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2710 G_CALLBACK (gtk_window_focus_in_callback
), this);
2711 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2712 G_CALLBACK (gtk_window_focus_out_callback
), this);
2716 // connect to the various key and mouse handlers
2718 GtkWidget
*connect_widget
= GetConnectWidget();
2720 ConnectWidget( connect_widget
);
2722 /* We cannot set colours, fonts and cursors before the widget has
2723 been realized, so we do this directly after realization */
2724 g_signal_connect (connect_widget
, "realize",
2725 G_CALLBACK (gtk_window_realized_callback
), this);
2729 // Catch native resize events
2730 g_signal_connect (m_wxwindow
, "size_allocate",
2731 G_CALLBACK (gtk_window_size_callback
), this);
2733 // Initialize XIM support
2734 g_signal_connect (m_wxwindow
, "realize",
2735 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2737 // And resize XIM window
2738 g_signal_connect (m_wxwindow
, "size_allocate",
2739 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2742 if (GTK_IS_COMBO(m_widget
))
2744 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2746 g_signal_connect (gcombo
->entry
, "size_request",
2747 G_CALLBACK (wxgtk_combo_size_request_callback
),
2752 // This is needed if we want to add our windows into native
2753 // GTK controls, such as the toolbar. With this callback, the
2754 // toolbar gets to know the correct size (the one set by the
2755 // programmer). Sadly, it misbehaves for wxComboBox.
2756 g_signal_connect (m_widget
, "size_request",
2757 G_CALLBACK (wxgtk_window_size_request_callback
),
2761 InheritAttributes();
2765 // unless the window was created initially hidden (i.e. Hide() had been
2766 // called before Create()), we should show it at GTK+ level as well
2768 gtk_widget_show( m_widget
);
2771 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2773 g_signal_connect (widget
, "key_press_event",
2774 G_CALLBACK (gtk_window_key_press_callback
), this);
2775 g_signal_connect (widget
, "key_release_event",
2776 G_CALLBACK (gtk_window_key_release_callback
), this);
2777 g_signal_connect (widget
, "button_press_event",
2778 G_CALLBACK (gtk_window_button_press_callback
), this);
2779 g_signal_connect (widget
, "button_release_event",
2780 G_CALLBACK (gtk_window_button_release_callback
), this);
2781 g_signal_connect (widget
, "motion_notify_event",
2782 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2783 g_signal_connect (widget
, "scroll_event",
2784 G_CALLBACK (window_scroll_event
), this);
2785 g_signal_connect (widget
, "popup_menu",
2786 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2787 g_signal_connect (widget
, "enter_notify_event",
2788 G_CALLBACK (gtk_window_enter_callback
), this);
2789 g_signal_connect (widget
, "leave_notify_event",
2790 G_CALLBACK (gtk_window_leave_callback
), this);
2793 bool wxWindowGTK::Destroy()
2795 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2799 return wxWindowBase::Destroy();
2802 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2804 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2807 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2809 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2810 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2813 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2816 if (m_resizing
) return; /* I don't like recursions */
2819 int currentX
, currentY
;
2820 GetPosition(¤tX
, ¤tY
);
2821 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2823 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2825 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2827 // calculate the best size if we should auto size the window
2828 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2829 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2831 const wxSize sizeBest
= GetBestSize();
2832 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2834 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2835 height
= sizeBest
.y
;
2843 int minWidth
= GetMinWidth(),
2844 minHeight
= GetMinHeight(),
2845 maxWidth
= GetMaxWidth(),
2846 maxHeight
= GetMaxHeight();
2848 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2849 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2850 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2851 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2853 #if wxUSE_TOOLBAR_NATIVE
2854 if (wxDynamicCast(GetParent(), wxToolBar
))
2856 // don't take the x,y values, they're wrong because toolbar sets them
2857 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2858 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2859 if (GTK_WIDGET_VISIBLE (widget
))
2860 gtk_widget_queue_resize (widget
);
2864 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2866 // don't set the size for children of wxNotebook, just take the values.
2874 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2875 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2877 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2878 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2882 m_x
= x
+ pizza
->xoffset
;
2883 m_y
= y
+ pizza
->yoffset
;
2886 int left_border
= 0;
2887 int right_border
= 0;
2889 int bottom_border
= 0;
2891 /* the default button has a border around it */
2892 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2894 GtkBorder
*default_border
= NULL
;
2895 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2898 left_border
+= default_border
->left
;
2899 right_border
+= default_border
->right
;
2900 top_border
+= default_border
->top
;
2901 bottom_border
+= default_border
->bottom
;
2902 g_free( default_border
);
2906 DoMoveWindow( m_x
-top_border
,
2908 m_width
+left_border
+right_border
,
2909 m_height
+top_border
+bottom_border
);
2914 /* Sometimes the client area changes size without the
2915 whole windows's size changing, but if the whole
2916 windows's size doesn't change, no wxSizeEvent will
2917 normally be sent. Here we add an extra test if
2918 the client test has been changed and this will
2920 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2924 wxPrintf( "OnSize sent from " );
2925 if (GetClassInfo() && GetClassInfo()->GetClassName())
2926 wxPrintf( GetClassInfo()->GetClassName() );
2927 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2930 if (!m_nativeSizeEvent
)
2932 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2933 event
.SetEventObject( this );
2934 GetEventHandler()->ProcessEvent( event
);
2940 void wxWindowGTK::OnInternalIdle()
2942 if ( m_dirtyTabOrder
)
2944 m_dirtyTabOrder
= false;
2948 // Update style if the window was not yet realized
2949 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2950 if (m_needsStyleChange
)
2952 SetBackgroundStyle(GetBackgroundStyle());
2953 m_needsStyleChange
= false;
2956 // Update invalidated regions.
2959 wxCursor cursor
= m_cursor
;
2960 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2964 /* I now set the cursor anew in every OnInternalIdle call
2965 as setting the cursor in a parent window also effects the
2966 windows above so that checking for the current cursor is
2971 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2973 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2975 if (!g_globalCursor
.Ok())
2976 cursor
= *wxSTANDARD_CURSOR
;
2978 window
= m_widget
->window
;
2979 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2980 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2986 GdkWindow
*window
= m_widget
->window
;
2987 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2988 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2993 if (wxUpdateUIEvent::CanUpdate(this))
2994 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2997 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2999 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3001 if (width
) (*width
) = m_width
;
3002 if (height
) (*height
) = m_height
;
3005 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3007 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3016 GetScrollbarWidth(m_widget
, dw
, dh
);
3019 #ifndef __WXUNIVERSAL__
3020 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3022 // shadow border size is 2
3026 if (HasFlag(wxSIMPLE_BORDER
))
3028 // simple border size is 1
3032 #endif // __WXUNIVERSAL__
3038 SetSize(width
, height
);
3041 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3043 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3055 GetScrollbarWidth(m_widget
, dw
, dh
);
3058 #ifndef __WXUNIVERSAL__
3059 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3061 // shadow border size is 2
3065 if (HasFlag(wxSIMPLE_BORDER
))
3067 // simple border size is 1
3071 #endif // __WXUNIVERSAL__
3077 if (width
) *width
= w
;
3078 if (height
) *height
= h
;
3081 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3083 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3087 if (m_parent
&& m_parent
->m_wxwindow
)
3089 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3090 dx
= pizza
->xoffset
;
3091 dy
= pizza
->yoffset
;
3094 if (x
) (*x
) = m_x
- dx
;
3095 if (y
) (*y
) = m_y
- dy
;
3098 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3100 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3102 if (!m_widget
->window
) return;
3104 GdkWindow
*source
= (GdkWindow
*) NULL
;
3106 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3108 source
= m_widget
->window
;
3112 gdk_window_get_origin( source
, &org_x
, &org_y
);
3116 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3118 org_x
+= m_widget
->allocation
.x
;
3119 org_y
+= m_widget
->allocation
.y
;
3127 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3129 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3131 if (!m_widget
->window
) return;
3133 GdkWindow
*source
= (GdkWindow
*) NULL
;
3135 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3137 source
= m_widget
->window
;
3141 gdk_window_get_origin( source
, &org_x
, &org_y
);
3145 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3147 org_x
+= m_widget
->allocation
.x
;
3148 org_y
+= m_widget
->allocation
.y
;
3156 bool wxWindowGTK::Show( bool show
)
3158 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3160 if (!wxWindowBase::Show(show
))
3167 gtk_widget_show( m_widget
);
3169 gtk_widget_hide( m_widget
);
3171 wxShowEvent
eventShow(GetId(), show
);
3172 eventShow
.SetEventObject(this);
3174 GetEventHandler()->ProcessEvent(eventShow
);
3179 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3181 win
->OnParentEnable(enable
);
3183 // Recurse, so that children have the opportunity to Do The Right Thing
3184 // and reset colours that have been messed up by a parent's (really ancestor's)
3186 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3188 node
= node
->GetNext() )
3190 wxWindow
*child
= node
->GetData();
3191 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3192 wxWindowNotifyEnable(child
, enable
);
3196 bool wxWindowGTK::Enable( bool enable
)
3198 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3200 if (!wxWindowBase::Enable(enable
))
3206 gtk_widget_set_sensitive( m_widget
, enable
);
3208 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3210 wxWindowNotifyEnable(this, enable
);
3215 int wxWindowGTK::GetCharHeight() const
3217 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3219 wxFont font
= GetFont();
3220 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3222 PangoContext
*context
= NULL
;
3224 context
= gtk_widget_get_pango_context( m_widget
);
3229 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3230 PangoLayout
*layout
= pango_layout_new(context
);
3231 pango_layout_set_font_description(layout
, desc
);
3232 pango_layout_set_text(layout
, "H", 1);
3233 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3235 PangoRectangle rect
;
3236 pango_layout_line_get_extents(line
, NULL
, &rect
);
3238 g_object_unref (layout
);
3240 return (int) PANGO_PIXELS(rect
.height
);
3243 int wxWindowGTK::GetCharWidth() const
3245 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3247 wxFont font
= GetFont();
3248 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3250 PangoContext
*context
= NULL
;
3252 context
= gtk_widget_get_pango_context( m_widget
);
3257 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3258 PangoLayout
*layout
= pango_layout_new(context
);
3259 pango_layout_set_font_description(layout
, desc
);
3260 pango_layout_set_text(layout
, "g", 1);
3261 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3263 PangoRectangle rect
;
3264 pango_layout_line_get_extents(line
, NULL
, &rect
);
3266 g_object_unref (layout
);
3268 return (int) PANGO_PIXELS(rect
.width
);
3271 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3275 int *externalLeading
,
3276 const wxFont
*theFont
) const
3278 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3280 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3289 PangoContext
*context
= NULL
;
3291 context
= gtk_widget_get_pango_context( m_widget
);
3300 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3301 PangoLayout
*layout
= pango_layout_new(context
);
3302 pango_layout_set_font_description(layout
, desc
);
3304 const wxCharBuffer data
= wxGTK_CONV( string
);
3306 pango_layout_set_text(layout
, data
, strlen(data
));
3309 PangoRectangle rect
;
3310 pango_layout_get_extents(layout
, NULL
, &rect
);
3312 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3313 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3316 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3317 int baseline
= pango_layout_iter_get_baseline(iter
);
3318 pango_layout_iter_free(iter
);
3319 *descent
= *y
- PANGO_PIXELS(baseline
);
3321 if (externalLeading
) (*externalLeading
) = 0; // ??
3323 g_object_unref (layout
);
3326 void wxWindowGTK::SetFocus()
3328 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3331 // don't do anything if we already have focus
3337 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3339 gtk_widget_grab_focus (m_wxwindow
);
3344 if (GTK_IS_CONTAINER(m_widget
))
3346 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3349 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3352 if (!GTK_WIDGET_REALIZED(m_widget
))
3354 // we can't set the focus to the widget now so we remember that
3355 // it should be focused and will do it later, during the idle
3356 // time, as soon as we can
3357 wxLogTrace(TRACE_FOCUS
,
3358 _T("Delaying setting focus to %s(%s)"),
3359 GetClassInfo()->GetClassName(), GetLabel().c_str());
3361 g_delayedFocus
= this;
3365 wxLogTrace(TRACE_FOCUS
,
3366 _T("Setting focus to %s(%s)"),
3367 GetClassInfo()->GetClassName(), GetLabel().c_str());
3369 gtk_widget_grab_focus (m_widget
);
3374 wxLogTrace(TRACE_FOCUS
,
3375 _T("Can't set focus to %s(%s)"),
3376 GetClassInfo()->GetClassName(), GetLabel().c_str());
3381 bool wxWindowGTK::AcceptsFocus() const
3383 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3386 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3388 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3390 wxWindowGTK
*oldParent
= m_parent
,
3391 *newParent
= (wxWindowGTK
*)newParentBase
;
3393 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3395 if ( !wxWindowBase::Reparent(newParent
) )
3398 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3400 /* prevent GTK from deleting the widget arbitrarily */
3401 gtk_widget_ref( m_widget
);
3405 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3408 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3412 /* insert GTK representation */
3413 (*(newParent
->m_insertCallback
))(newParent
, this);
3416 /* reverse: prevent GTK from deleting the widget arbitrarily */
3417 gtk_widget_unref( m_widget
);
3422 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3424 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3426 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3428 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3433 /* insert GTK representation */
3434 (*m_insertCallback
)(this, child
);
3437 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3439 wxWindowBase::AddChild(child
);
3440 m_dirtyTabOrder
= true;
3442 wxapp_install_idle_handler();
3445 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3447 wxWindowBase::RemoveChild(child
);
3448 m_dirtyTabOrder
= true;
3450 wxapp_install_idle_handler();
3453 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3455 wxWindowBase::DoMoveInTabOrder(win
, move
);
3456 m_dirtyTabOrder
= true;
3458 wxapp_install_idle_handler();
3461 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3463 // none needed by default
3467 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3469 // nothing to do by default since none is needed
3472 void wxWindowGTK::RealizeTabOrder()
3476 if ( !m_children
.empty() )
3478 // we don't only construct the correct focus chain but also use
3479 // this opportunity to update the mnemonic widgets for the widgets
3482 GList
*chain
= NULL
;
3483 wxWindowGTK
* mnemonicWindow
= NULL
;
3485 for ( wxWindowList::const_iterator i
= m_children
.begin();
3486 i
!= m_children
.end();
3489 wxWindowGTK
*win
= *i
;
3491 if ( mnemonicWindow
)
3493 if ( win
->AcceptsFocusFromKeyboard() )
3495 // wxComboBox et al. needs to focus on on a different
3496 // widget than m_widget, so if the main widget isn't
3497 // focusable try the connect widget
3498 GtkWidget
* w
= win
->m_widget
;
3499 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3501 w
= win
->GetConnectWidget();
3502 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3508 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3509 mnemonicWindow
= NULL
;
3513 else if ( win
->GTKWidgetNeedsMnemonic() )
3515 mnemonicWindow
= win
;
3518 chain
= g_list_prepend(chain
, win
->m_widget
);
3521 chain
= g_list_reverse(chain
);
3523 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3528 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3533 void wxWindowGTK::Raise()
3535 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3537 if (m_wxwindow
&& m_wxwindow
->window
)
3539 gdk_window_raise( m_wxwindow
->window
);
3541 else if (m_widget
->window
)
3543 gdk_window_raise( m_widget
->window
);
3547 void wxWindowGTK::Lower()
3549 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3551 if (m_wxwindow
&& m_wxwindow
->window
)
3553 gdk_window_lower( m_wxwindow
->window
);
3555 else if (m_widget
->window
)
3557 gdk_window_lower( m_widget
->window
);
3561 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3563 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3565 if (cursor
== m_cursor
)
3569 wxapp_install_idle_handler();
3571 if (cursor
== wxNullCursor
)
3572 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3574 return wxWindowBase::SetCursor( cursor
);
3577 void wxWindowGTK::WarpPointer( int x
, int y
)
3579 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3581 // We provide this function ourselves as it is
3582 // missing in GDK (top of this file).
3584 GdkWindow
*window
= (GdkWindow
*) NULL
;
3586 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3588 window
= GetConnectWidget()->window
;
3591 gdk_window_warp_pointer( window
, x
, y
);
3594 bool wxWindowGTK::ScrollLines(int lines
)
3596 bool changed
= false;
3597 GtkRange
* range
= m_scrollBar
[1];
3600 GtkAdjustment
* adj
= range
->adjustment
;
3601 const int pos
= int(adj
->value
+ 0.5);
3602 gtk_range_set_value(range
, pos
+ lines
);
3603 changed
= pos
!= int(adj
->value
+ 0.5);
3608 bool wxWindowGTK::ScrollPages(int pages
)
3610 bool changed
= false;
3611 GtkRange
* range
= m_scrollBar
[1];
3614 GtkAdjustment
* adj
= range
->adjustment
;
3615 const int pos
= int(adj
->value
+ 0.5);
3616 gtk_range_set_value(range
, pos
+ pages
* adj
->page_size
);
3617 changed
= pos
!= int(adj
->value
+ 0.5);
3622 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3626 if (!m_widget
->window
)
3631 GdkRectangle gdk_rect
,
3635 gdk_rect
.x
= rect
->x
;
3636 gdk_rect
.y
= rect
->y
;
3637 gdk_rect
.width
= rect
->width
;
3638 gdk_rect
.height
= rect
->height
;
3641 else // invalidate everything
3646 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3650 void wxWindowGTK::Update()
3654 // when we call Update() we really want to update the window immediately on
3655 // screen, even if it means flushing the entire queue and hence slowing down
3656 // everything -- but it should still be done, it's just that Update() should
3657 // be called very rarely
3661 void wxWindowGTK::GtkUpdate()
3663 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3664 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3666 // for consistency with other platforms (and also because it's convenient
3667 // to be able to update an entire TLW by calling Update() only once), we
3668 // should also update all our children here
3669 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3671 node
= node
->GetNext() )
3673 node
->GetData()->GtkUpdate();
3677 void wxWindowGTK::GtkSendPaintEvents()
3681 m_updateRegion
.Clear();
3685 // Clip to paint region in wxClientDC
3686 m_clipPaintRegion
= true;
3688 // widget to draw on
3689 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3691 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3693 // find ancestor from which to steal background
3694 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3696 parent
= (wxWindow
*)this;
3698 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3700 wxRegionIterator
upd( m_updateRegion
);
3704 rect
.x
= upd
.GetX();
3705 rect
.y
= upd
.GetY();
3706 rect
.width
= upd
.GetWidth();
3707 rect
.height
= upd
.GetHeight();
3709 gtk_paint_flat_box( parent
->m_widget
->style
,
3711 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3725 wxWindowDC
dc( (wxWindow
*)this );
3726 dc
.SetClippingRegion( m_updateRegion
);
3728 wxEraseEvent
erase_event( GetId(), &dc
);
3729 erase_event
.SetEventObject( this );
3731 GetEventHandler()->ProcessEvent(erase_event
);
3734 wxNcPaintEvent
nc_paint_event( GetId() );
3735 nc_paint_event
.SetEventObject( this );
3736 GetEventHandler()->ProcessEvent( nc_paint_event
);
3738 wxPaintEvent
paint_event( GetId() );
3739 paint_event
.SetEventObject( this );
3740 GetEventHandler()->ProcessEvent( paint_event
);
3742 m_clipPaintRegion
= false;
3744 m_updateRegion
.Clear();
3747 void wxWindowGTK::ClearBackground()
3749 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3753 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3755 wxWindowBase::DoSetToolTip(tip
);
3758 m_tooltip
->Apply( (wxWindow
*)this );
3761 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3763 wxString
tmp( tip
);
3764 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3766 #endif // wxUSE_TOOLTIPS
3768 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3770 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3772 if (!wxWindowBase::SetBackgroundColour(colour
))
3777 // We need the pixel value e.g. for background clearing.
3778 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3781 // apply style change (forceStyle=true so that new style is applied
3782 // even if the bg colour changed from valid to wxNullColour)
3783 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3784 ApplyWidgetStyle(true);
3789 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3791 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3793 if (!wxWindowBase::SetForegroundColour(colour
))
3800 // We need the pixel value e.g. for background clearing.
3801 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3804 // apply style change (forceStyle=true so that new style is applied
3805 // even if the bg colour changed from valid to wxNullColour):
3806 ApplyWidgetStyle(true);
3811 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3813 return gtk_widget_get_pango_context( m_widget
);
3816 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3818 // do we need to apply any changes at all?
3821 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3826 GtkRcStyle
*style
= gtk_rc_style_new();
3831 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3834 if ( m_foregroundColour
.Ok() )
3836 GdkColor
*fg
= m_foregroundColour
.GetColor();
3838 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3839 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3841 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3842 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3844 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3845 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3848 if ( m_backgroundColour
.Ok() )
3850 GdkColor
*bg
= m_backgroundColour
.GetColor();
3852 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3853 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3854 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3855 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3857 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3858 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3859 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3860 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3862 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3863 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3864 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3865 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3867 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3868 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3869 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3870 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3876 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3878 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3881 DoApplyWidgetStyle(style
);
3882 gtk_rc_style_unref(style
);
3885 // Style change may affect GTK+'s size calculation:
3886 InvalidateBestSize();
3889 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3892 gtk_widget_modify_style(m_wxwindow
, style
);
3894 gtk_widget_modify_style(m_widget
, style
);
3897 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3899 wxWindowBase::SetBackgroundStyle(style
);
3901 if (style
== wxBG_STYLE_CUSTOM
)
3903 GdkWindow
*window
= (GdkWindow
*) NULL
;
3905 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3907 window
= GetConnectWidget()->window
;
3911 // Make sure GDK/X11 doesn't refresh the window
3913 gdk_window_set_back_pixmap( window
, None
, False
);
3915 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3918 m_needsStyleChange
= false;
3921 // Do in OnIdle, because the window is not yet available
3922 m_needsStyleChange
= true;
3924 // Don't apply widget style, or we get a grey background
3928 // apply style change (forceStyle=true so that new style is applied
3929 // even if the bg colour changed from valid to wxNullColour):
3930 ApplyWidgetStyle(true);
3935 #if wxUSE_DRAG_AND_DROP
3937 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3939 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3941 GtkWidget
*dnd_widget
= GetConnectWidget();
3943 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3945 if (m_dropTarget
) delete m_dropTarget
;
3946 m_dropTarget
= dropTarget
;
3948 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3951 #endif // wxUSE_DRAG_AND_DROP
3953 GtkWidget
* wxWindowGTK::GetConnectWidget()
3955 GtkWidget
*connect_widget
= m_widget
;
3956 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3958 return connect_widget
;
3961 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3964 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3966 return (window
== m_widget
->window
);
3969 bool wxWindowGTK::SetFont( const wxFont
&font
)
3971 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3973 if (!wxWindowBase::SetFont(font
))
3976 // apply style change (forceStyle=true so that new style is applied
3977 // even if the font changed from valid to wxNullFont):
3978 ApplyWidgetStyle(true);
3983 void wxWindowGTK::DoCaptureMouse()
3985 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3987 GdkWindow
*window
= (GdkWindow
*) NULL
;
3989 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3991 window
= GetConnectWidget()->window
;
3993 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3995 const wxCursor
* cursor
= &m_cursor
;
3997 cursor
= wxSTANDARD_CURSOR
;
3999 gdk_pointer_grab( window
, FALSE
,
4001 (GDK_BUTTON_PRESS_MASK
|
4002 GDK_BUTTON_RELEASE_MASK
|
4003 GDK_POINTER_MOTION_HINT_MASK
|
4004 GDK_POINTER_MOTION_MASK
),
4006 cursor
->GetCursor(),
4007 (guint32
)GDK_CURRENT_TIME
);
4008 g_captureWindow
= this;
4009 g_captureWindowHasMouse
= true;
4012 void wxWindowGTK::DoReleaseMouse()
4014 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4016 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4018 g_captureWindow
= (wxWindowGTK
*) NULL
;
4020 GdkWindow
*window
= (GdkWindow
*) NULL
;
4022 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4024 window
= GetConnectWidget()->window
;
4029 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4033 wxWindow
*wxWindowBase::GetCapture()
4035 return (wxWindow
*)g_captureWindow
;
4038 bool wxWindowGTK::IsRetained() const
4043 void wxWindowGTK::BlockScrollEvent()
4045 wxASSERT(!m_blockScrollEvent
);
4046 m_blockScrollEvent
= true;
4049 void wxWindowGTK::UnblockScrollEvent()
4051 wxASSERT(m_blockScrollEvent
);
4052 m_blockScrollEvent
= false;
4055 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4058 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4059 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4063 m_hasScrolling
= true;
4067 // GtkRange requires upper > lower
4072 const int i
= orient
== wxVERTICAL
;
4073 GtkAdjustment
* adj
= m_scrollBar
[i
]->adjustment
;
4075 adj
->step_increment
= 1;
4076 adj
->page_increment
=
4077 adj
->page_size
= thumbVisible
;
4080 // automatically clamps value to [0,range-page_size], and emits change events
4081 gtk_range_set_range(m_scrollBar
[i
], 0, range
);
4082 UnblockScrollEvent();
4083 m_scrollPos
[i
] = adj
->value
;
4086 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4088 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4089 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4091 // This check is more than an optimization. Without it, the slider
4092 // will not move smoothly while tracking when using wxScrollHelper.
4093 if (GetScrollPos(orient
) != pos
)
4095 const int i
= orient
== wxVERTICAL
;
4097 gtk_range_set_value(m_scrollBar
[i
], pos
);
4098 UnblockScrollEvent();
4099 m_scrollPos
[i
] = m_scrollBar
[i
]->adjustment
->value
;
4103 int wxWindowGTK::GetScrollThumb( int orient
) const
4105 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4106 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4108 const int i
= orient
== wxVERTICAL
;
4109 return int(m_scrollBar
[i
]->adjustment
->page_size
);
4112 int wxWindowGTK::GetScrollPos( int orient
) const
4114 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4115 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4117 const int i
= orient
== wxVERTICAL
;
4118 return int(m_scrollBar
[i
]->adjustment
->value
+ 0.5);
4121 int wxWindowGTK::GetScrollRange( int orient
) const
4123 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4124 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4126 const int i
= orient
== wxVERTICAL
;
4127 return int(m_scrollBar
[i
]->adjustment
->upper
);
4130 // Determine if increment is the same as +/-x, allowing for some small
4131 // difference due to possible inexactness in floating point arithmetic
4132 static inline bool IsScrollIncrement(double increment
, double x
)
4134 wxASSERT(increment
> 0);
4135 const double tolerance
= 1.0 / 1024;
4136 return fabs(increment
- fabs(x
)) < tolerance
;
4139 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4144 wxapp_install_idle_handler();
4146 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4148 const int barIndex
= range
== m_scrollBar
[1];
4149 GtkAdjustment
* adj
= range
->adjustment
;
4150 const int value
= int(adj
->value
+ 0.5);
4151 // save previous position
4152 const double oldPos
= m_scrollPos
[barIndex
];
4153 // update current position
4154 m_scrollPos
[barIndex
] = adj
->value
;
4155 // If event should be ignored, or integral position has not changed
4156 if (!m_hasVMT
|| g_blockEventsOnDrag
|| m_blockScrollEvent
|| value
== int(oldPos
+ 0.5))
4161 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4164 // Difference from last change event
4165 const double diff
= adj
->value
- oldPos
;
4166 const bool isDown
= diff
> 0;
4168 if (IsScrollIncrement(adj
->step_increment
, diff
))
4170 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4172 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4174 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4176 else if (m_mouseButtonDown
)
4178 // Assume track event
4179 m_isScrolling
= true;
4185 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4187 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4189 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4191 // No scrolling requested.
4192 if ((dx
== 0) && (dy
== 0)) return;
4194 m_clipPaintRegion
= true;
4196 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4198 m_clipPaintRegion
= false;
4201 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4203 //RN: Note that static controls usually have no border on gtk, so maybe
4204 //it makes sense to treat that as simply no border at the wx level
4206 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4208 GtkShadowType gtkstyle
;
4210 if(wxstyle
& wxBORDER_RAISED
)
4211 gtkstyle
= GTK_SHADOW_OUT
;
4212 else if (wxstyle
& wxBORDER_SUNKEN
)
4213 gtkstyle
= GTK_SHADOW_IN
;
4214 else if (wxstyle
& wxBORDER_DOUBLE
)
4215 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4217 gtkstyle
= GTK_SHADOW_IN
;
4219 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4224 void wxWindowGTK::SetWindowStyleFlag( long style
)
4226 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4227 wxWindowBase::SetWindowStyleFlag(style
);
4230 // Find the wxWindow at the current mouse position, also returning the mouse
4232 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4234 pt
= wxGetMousePosition();
4235 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4239 // Get the current mouse position.
4240 wxPoint
wxGetMousePosition()
4242 /* This crashes when used within wxHelpContext,
4243 so we have to use the X-specific implementation below.
4245 GdkModifierType *mask;
4246 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4248 return wxPoint(x, y);
4252 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4254 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4255 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4256 Window rootReturn
, childReturn
;
4257 int rootX
, rootY
, winX
, winY
;
4258 unsigned int maskReturn
;
4260 XQueryPointer (display
,
4264 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4265 return wxPoint(rootX
, rootY
);
4269 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4270 void wxAddGrab(wxWindow
* window
)
4272 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4275 void wxRemoveGrab(wxWindow
* window
)
4277 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4280 // ----------------------------------------------------------------------------
4282 // ----------------------------------------------------------------------------
4284 class wxWinModule
: public wxModule
4291 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4294 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4296 bool wxWinModule::OnInit()
4298 // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() );
4299 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4304 void wxWinModule::OnExit()
4307 g_object_unref (g_eraseGC
);