1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
25 #include "wx/dcclient.h"
27 #include "wx/dialog.h"
28 #include "wx/settings.h"
29 #include "wx/msgdlg.h"
30 #include "wx/textctrl.h"
33 #include "wx/layout.h"
34 #include "wx/module.h"
35 #include "wx/combobox.h"
37 #if wxUSE_TOOLBAR_NATIVE
38 #include "wx/toolbar.h"
41 #if wxUSE_DRAG_AND_DROP
46 #include "wx/tooltip.h"
53 #include "wx/statusbr.h"
54 #include "wx/fontutil.h"
57 #include "wx/thread.h"
63 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
64 #include <gtk/gtkversion.h>
65 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
66 #undef GTK_DISABLE_DEPRECATED
69 #include "wx/gtk/private.h"
70 #include <gdk/gdkprivate.h>
71 #include <gdk/gdkkeysyms.h>
75 #include <gtk/gtkprivate.h>
77 #include "wx/gtk/win_gtk.h"
79 #include <pango/pangox.h>
85 extern GtkContainerClass
*pizza_parent_class
;
87 //-----------------------------------------------------------------------------
88 // documentation on internals
89 //-----------------------------------------------------------------------------
92 I have been asked several times about writing some documentation about
93 the GTK port of wxWidgets, especially its internal structures. Obviously,
94 you cannot understand wxGTK without knowing a little about the GTK, but
95 some more information about what the wxWindow, which is the base class
96 for all other window classes, does seems required as well.
100 What does wxWindow do? It contains the common interface for the following
101 jobs of its descendants:
103 1) Define the rudimentary behaviour common to all window classes, such as
104 resizing, intercepting user input (so as to make it possible to use these
105 events for special purposes in a derived class), window names etc.
107 2) Provide the possibility to contain and manage children, if the derived
108 class is allowed to contain children, which holds true for those window
109 classes which do not display a native GTK widget. To name them, these
110 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
111 work classes are a special case and are handled a bit differently from
112 the rest. The same holds true for the wxNotebook class.
114 3) Provide the possibility to draw into a client area of a window. This,
115 too, only holds true for classes that do not display a native GTK widget
118 4) Provide the entire mechanism for scrolling widgets. This actual inter-
119 face for this is usually in wxScrolledWindow, but the GTK implementation
122 5) A multitude of helper or extra methods for special purposes, such as
123 Drag'n'Drop, managing validators etc.
125 6) Display a border (sunken, raised, simple or none).
127 Normally one might expect, that one wxWidgets window would always correspond
128 to one GTK widget. Under GTK, there is no such allround widget that has all
129 the functionality. Moreover, the GTK defines a client area as a different
130 widget from the actual widget you are handling. Last but not least some
131 special classes (e.g. wxFrame) handle different categories of widgets and
132 still have the possibility to draw something in the client area.
133 It was therefore required to write a special purpose GTK widget, that would
134 represent a client area in the sense of wxWidgets capable to do the jobs
135 2), 3) and 4). I have written this class and it resides in win_gtk.c of
138 All windows must have a widget, with which they interact with other under-
139 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
140 the wxWindow class has a member variable called m_widget which holds a
141 pointer to this widget. When the window class represents a GTK native widget,
142 this is (in most cases) the only GTK widget the class manages. E.g. the
143 wxStaticText class handles only a GtkLabel widget a pointer to which you
144 can find in m_widget (defined in wxWindow)
146 When the class has a client area for drawing into and for containing children
147 it has to handle the client area widget (of the type GtkPizza, defined in
148 win_gtk.c), but there could be any number of widgets, handled by a class
149 The common rule for all windows is only, that the widget that interacts with
150 the rest of GTK must be referenced in m_widget and all other widgets must be
151 children of this widget on the GTK level. The top-most widget, which also
152 represents the client area, must be in the m_wxwindow field and must be of
155 As I said, the window classes that display a GTK native widget only have
156 one widget, so in the case of e.g. the wxButton class m_widget holds a
157 pointer to a GtkButton widget. But windows with client areas (for drawing
158 and children) have a m_widget field that is a pointer to a GtkScrolled-
159 Window and a m_wxwindow field that is pointer to a GtkPizza and this
160 one is (in the GTK sense) a child of the GtkScrolledWindow.
162 If the m_wxwindow field is set, then all input to this widget is inter-
163 cepted and sent to the wxWidgets class. If not, all input to the widget
164 that gets pointed to by m_widget gets intercepted and sent to the class.
168 The design of scrolling in wxWidgets is markedly different from that offered
169 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
170 clicking on a scrollbar belonging to scrolled window will inevitably move
171 the window. In wxWidgets, the scrollbar will only emit an event, send this
172 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
173 which actually moves the window and its subchildren. Note that GtkPizza
174 memorizes how much it has been scrolled but that wxWidgets forgets this
175 so that the two coordinates systems have to be kept in synch. This is done
176 in various places using the pizza->xoffset and pizza->yoffset values.
180 Singularily the most broken code in GTK is the code that is supposed to
181 inform subwindows (child windows) about new positions. Very often, duplicate
182 events are sent without changes in size or position, equally often no
183 events are sent at all (All this is due to a bug in the GtkContainer code
184 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
185 GTK's own system and it simply waits for size events for toplevel windows
186 and then iterates down the respective size events to all window. This has
187 the disadvantage that windows might get size events before the GTK widget
188 actually has the reported size. This doesn't normally pose any problem, but
189 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
190 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
191 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
192 window that is used for OpenGL output really has that size (as reported by
197 If someone at some point of time feels the immense desire to have a look at,
198 change or attempt to optimise the Refresh() logic, this person will need an
199 intimate understanding of what "draw" and "expose" events are and what
200 they are used for, in particular when used in connection with GTK's
201 own windowless widgets. Beware.
205 Cursors, too, have been a constant source of pleasure. The main difficulty
206 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
207 for the parent. To prevent this from doing too much harm, I use idle time
208 to set the cursor over and over again, starting from the toplevel windows
209 and ending with the youngest generation (speaking of parent and child windows).
210 Also don't forget that cursors (like much else) are connected to GdkWindows,
211 not GtkWidgets and that the "window" field of a GtkWidget might very well
212 point to the GdkWindow of the parent widget (-> "window-less widget") and
213 that the two obviously have very different meanings.
217 //-----------------------------------------------------------------------------
219 //-----------------------------------------------------------------------------
221 extern bool g_blockEventsOnDrag
;
222 extern bool g_blockEventsOnScroll
;
223 extern wxCursor g_globalCursor
;
225 static GdkGC
*g_eraseGC
= NULL
;
227 // mouse capture state: the window which has it and if the mouse is currently
229 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
230 static bool g_captureWindowHasMouse
= false;
232 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
234 // the last window which had the focus - this is normally never NULL (except
235 // if we never had focus at all) as even when g_focusWindow is NULL it still
236 // keeps its previous value
237 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
239 // If a window get the focus set but has not been realized
240 // yet, defer setting the focus to idle time.
241 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
243 extern bool g_mainThreadLocked
;
245 //-----------------------------------------------------------------------------
247 //-----------------------------------------------------------------------------
252 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
254 # define DEBUG_MAIN_THREAD
257 #define DEBUG_MAIN_THREAD
260 // the trace mask used for the focus debugging messages
261 #define TRACE_FOCUS _T("focus")
263 //-----------------------------------------------------------------------------
264 // missing gdk functions
265 //-----------------------------------------------------------------------------
268 gdk_window_warp_pointer (GdkWindow
*window
,
273 window
= gdk_get_default_root_window();
275 if (!GDK_WINDOW_DESTROYED(window
))
277 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
278 None
, /* not source window -> move from anywhere */
279 GDK_WINDOW_XID(window
), /* dest window */
280 0, 0, 0, 0, /* not source window -> move from anywhere */
285 //-----------------------------------------------------------------------------
286 // local code (see below)
287 //-----------------------------------------------------------------------------
289 // returns the child of win which currently has focus or NULL if not found
291 // Note: can't be static, needed by textctrl.cpp.
292 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
294 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
296 return (wxWindow
*)NULL
;
298 if ( winFocus
== win
)
299 return (wxWindow
*)win
;
301 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
303 node
= node
->GetNext() )
305 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
310 return (wxWindow
*)NULL
;
313 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
)
315 GtkScrolledWindow
* scroll_window
= GTK_SCROLLED_WINDOW(widget
);
316 GtkScrolledWindowClass
* scroll_class
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
));
317 GtkRequisition scroll_req
;
320 if (scroll_window
->vscrollbar_visible
)
322 scroll_req
.width
= 2;
323 scroll_req
.height
= 2;
324 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
325 (scroll_window
->vscrollbar
, &scroll_req
);
326 w
= scroll_req
.width
+
327 scroll_class
->scrollbar_spacing
;
331 if (scroll_window
->hscrollbar_visible
)
333 scroll_req
.width
= 2;
334 scroll_req
.height
= 2;
335 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
336 (scroll_window
->hscrollbar
, &scroll_req
);
337 h
= scroll_req
.height
+
338 scroll_class
->scrollbar_spacing
;
342 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
344 // wxUniversal widgets draw the borders and scrollbars themselves
345 #ifndef __WXUNIVERSAL__
352 if (win
->m_hasScrolling
)
354 GetScrollbarWidth(widget
, dw
, dh
);
359 if (GTK_WIDGET_NO_WINDOW (widget
))
361 dx
+= widget
->allocation
.x
;
362 dy
+= widget
->allocation
.y
;
365 if (win
->HasFlag(wxRAISED_BORDER
))
367 gtk_paint_shadow (widget
->style
,
371 NULL
, NULL
, NULL
, // FIXME: No clipping?
373 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
377 if (win
->HasFlag(wxSUNKEN_BORDER
))
379 gtk_paint_shadow (widget
->style
,
383 NULL
, NULL
, NULL
, // FIXME: No clipping?
385 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
389 if (win
->HasFlag(wxSIMPLE_BORDER
))
392 gc
= gdk_gc_new( widget
->window
);
393 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
394 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
396 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
400 #endif // __WXUNIVERSAL__
403 //-----------------------------------------------------------------------------
404 // "expose_event" of m_widget
405 //-----------------------------------------------------------------------------
409 gtk_window_own_expose_callback( GtkWidget
*widget
,
410 GdkEventExpose
*gdk_event
,
413 if (gdk_event
->count
> 0) return FALSE
;
415 draw_frame( widget
, win
);
417 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
423 //-----------------------------------------------------------------------------
424 // "size_request" of m_widget
425 //-----------------------------------------------------------------------------
427 // make it extern because wxStaticText needs to disconnect this one
429 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
430 GtkRequisition
*requisition
,
434 win
->GetSize( &w
, &h
);
440 requisition
->height
= h
;
441 requisition
->width
= w
;
447 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
448 GtkRequisition
*requisition
,
451 // This callback is actually hooked into the text entry
452 // of the combo box, not the GtkHBox.
455 win
->GetSize( &w
, &h
);
461 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
463 GtkRequisition entry_req
;
465 entry_req
.height
= 2;
466 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
467 (gcombo
->button
, &entry_req
);
469 requisition
->width
= w
- entry_req
.width
;
470 requisition
->height
= entry_req
.height
;
474 //-----------------------------------------------------------------------------
475 // "expose_event" of m_wxwindow
476 //-----------------------------------------------------------------------------
480 gtk_window_expose_callback( GtkWidget
*widget
,
481 GdkEventExpose
*gdk_event
,
487 wxapp_install_idle_handler();
489 // This callback gets called in drawing-idle time under
490 // GTK 2.0, so we don't need to defer anything to idle
493 GtkPizza
*pizza
= GTK_PIZZA( widget
);
494 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
499 wxPrintf( wxT("OnExpose from ") );
500 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
501 wxPrintf( win
->GetClassInfo()->GetClassName() );
502 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
503 (int)gdk_event
->area
.y
,
504 (int)gdk_event
->area
.width
,
505 (int)gdk_event
->area
.height
);
510 win
->m_wxwindow
->style
,
514 (GdkRectangle
*) NULL
,
516 (char *)"button", // const_cast
521 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
523 win
->GtkSendPaintEvents();
526 // Let parent window draw window-less widgets
527 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
533 //-----------------------------------------------------------------------------
534 // "key_press_event" from any window
535 //-----------------------------------------------------------------------------
537 // set WXTRACE to this to see the key event codes on the console
538 #define TRACE_KEYS _T("keyevent")
540 // translates an X key symbol to WXK_XXX value
542 // if isChar is true it means that the value returned will be used for EVT_CHAR
543 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
544 // for example, while if it is false it means that the value is going to be
545 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
547 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
553 // Shift, Control and Alt don't generate the CHAR events at all
556 key_code
= isChar
? 0 : WXK_SHIFT
;
560 key_code
= isChar
? 0 : WXK_CONTROL
;
568 key_code
= isChar
? 0 : WXK_ALT
;
571 // neither do the toggle modifies
572 case GDK_Scroll_Lock
:
573 key_code
= isChar
? 0 : WXK_SCROLL
;
577 key_code
= isChar
? 0 : WXK_CAPITAL
;
581 key_code
= isChar
? 0 : WXK_NUMLOCK
;
585 // various other special keys
598 case GDK_ISO_Left_Tab
:
605 key_code
= WXK_RETURN
;
609 key_code
= WXK_CLEAR
;
613 key_code
= WXK_PAUSE
;
617 key_code
= WXK_SELECT
;
621 key_code
= WXK_PRINT
;
625 key_code
= WXK_EXECUTE
;
629 key_code
= WXK_ESCAPE
;
632 // cursor and other extended keyboard keys
634 key_code
= WXK_DELETE
;
650 key_code
= WXK_RIGHT
;
657 case GDK_Prior
: // == GDK_Page_Up
658 key_code
= WXK_PAGEUP
;
661 case GDK_Next
: // == GDK_Page_Down
662 key_code
= WXK_PAGEDOWN
;
674 key_code
= WXK_INSERT
;
689 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
693 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
697 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
701 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
705 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
709 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
713 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
717 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
721 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
725 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
729 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
733 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
737 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
740 case GDK_KP_Prior
: // == GDK_KP_Page_Up
741 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
744 case GDK_KP_Next
: // == GDK_KP_Page_Down
745 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
749 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
753 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
757 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
761 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
765 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
768 case GDK_KP_Multiply
:
769 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
773 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
776 case GDK_KP_Separator
:
777 // FIXME: what is this?
778 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
781 case GDK_KP_Subtract
:
782 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
786 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
790 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
807 key_code
= WXK_F1
+ keysym
- GDK_F1
;
817 static inline bool wxIsAsciiKeysym(KeySym ks
)
822 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
824 GdkEventKey
*gdk_event
)
828 GdkModifierType state
;
829 if (gdk_event
->window
)
830 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
832 event
.SetTimestamp( gdk_event
->time
);
833 event
.SetId(win
->GetId());
834 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
835 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
836 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
837 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
838 event
.m_scanCode
= gdk_event
->keyval
;
839 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
840 event
.m_rawFlags
= 0;
842 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
844 wxGetMousePosition( &x
, &y
);
845 win
->ScreenToClient( &x
, &y
);
848 event
.SetEventObject( win
);
853 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
855 GdkEventKey
*gdk_event
)
857 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
858 // but only event->keyval which is quite useless to us, so remember
859 // the last character from GDK_KEY_PRESS and reuse it as last resort
861 // NB: should be MT-safe as we're always called from the main thread only
866 } s_lastKeyPress
= { 0, 0 };
868 KeySym keysym
= gdk_event
->keyval
;
870 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
871 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
875 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
879 // do we have the translation or is it a plain ASCII character?
880 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
882 // we should use keysym if it is ASCII as X does some translations
883 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
884 // which we don't want here (but which we do use for OnChar())
885 if ( !wxIsAsciiKeysym(keysym
) )
887 keysym
= (KeySym
)gdk_event
->string
[0];
890 // we want to always get the same key code when the same key is
891 // pressed regardless of the state of the modifiers, i.e. on a
892 // standard US keyboard pressing '5' or '%' ('5' key with
893 // Shift) should result in the same key code in OnKeyDown():
894 // '5' (although OnChar() will get either '5' or '%').
896 // to do it we first translate keysym to keycode (== scan code)
897 // and then back but always using the lower register
898 Display
*dpy
= (Display
*)wxGetDisplay();
899 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
901 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
903 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
905 // use the normalized, i.e. lower register, keysym if we've
907 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
909 // as explained above, we want to have lower register key codes
910 // normally but for the letter keys we want to have the upper ones
912 // NB: don't use XConvertCase() here, we want to do it for letters
914 key_code
= toupper(key_code
);
916 else // non ASCII key, what to do?
918 // by default, ignore it
921 // but if we have cached information from the last KEY_PRESS
922 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
925 if ( keysym
== s_lastKeyPress
.keysym
)
927 key_code
= s_lastKeyPress
.keycode
;
932 if ( gdk_event
->type
== GDK_KEY_PRESS
)
934 // remember it to be reused for KEY_UP event later
935 s_lastKeyPress
.keysym
= keysym
;
936 s_lastKeyPress
.keycode
= key_code
;
940 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
942 // sending unknown key events doesn't really make sense
946 // now fill all the other fields
947 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
949 event
.m_keyCode
= key_code
;
951 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
953 event
.m_uniChar
= key_code
;
963 GtkIMContext
*context
;
964 GdkEventKey
*lastKeyEvent
;
968 context
= gtk_im_multicontext_new();
973 g_object_unref (context
);
979 gtk_window_key_press_callback( GtkWidget
*widget
,
980 GdkEventKey
*gdk_event
,
986 wxapp_install_idle_handler();
990 if (g_blockEventsOnDrag
)
994 wxKeyEvent
event( wxEVT_KEY_DOWN
);
996 bool return_after_IM
= false;
998 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1000 // Emit KEY_DOWN event
1001 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1005 // Return after IM processing as we cannot do
1006 // anything with it anyhow.
1007 return_after_IM
= true;
1010 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1011 // When we get a key_press event here, it could be originate
1012 // from the current widget or its child widgets. However, only the widget
1013 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1014 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1015 // originated from its child widgets and shouldn't be passed to IM context.
1016 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1017 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1018 // widgets has both IM context and input focus, the event should be filtered
1019 // by gtk_im_context_filter_keypress().
1020 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1021 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1023 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1024 // docs, if IM filter returns true, no further processing should be done.
1025 // we should send the key_down event anyway.
1026 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1027 win
->m_imData
->lastKeyEvent
= NULL
;
1028 if (intercepted_by_IM
)
1030 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1035 if (return_after_IM
)
1041 wxWindowGTK
*ancestor
= win
;
1044 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1047 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1048 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1051 if (ancestor
->IsTopLevel())
1053 ancestor
= ancestor
->GetParent();
1056 #endif // wxUSE_ACCEL
1058 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1059 // will only be sent if it is not in an accelerator table.
1063 KeySym keysym
= gdk_event
->keyval
;
1064 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1065 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1068 if ( wxIsAsciiKeysym(keysym
) )
1071 key_code
= (unsigned char)keysym
;
1073 // gdk_event->string is actually deprecated
1074 else if ( gdk_event
->length
== 1 )
1076 key_code
= (unsigned char)gdk_event
->string
[0];
1082 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1084 event
.m_keyCode
= key_code
;
1086 // To conform to the docs we need to translate Ctrl-alpha
1087 // characters to values in the range 1-26.
1088 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1090 event
.m_keyCode
= key_code
- 'a' + 1;
1092 event
.m_uniChar
= event
.m_keyCode
;
1096 // Implement OnCharHook by checking ancestor top level windows
1097 wxWindow
*parent
= win
;
1098 while (parent
&& !parent
->IsTopLevel())
1099 parent
= parent
->GetParent();
1102 event
.SetEventType( wxEVT_CHAR_HOOK
);
1103 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1108 event
.SetEventType(wxEVT_CHAR
);
1109 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1118 // win is a control: tab can be propagated up
1120 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1121 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1122 // have this style, yet choose not to process this particular TAB in which
1123 // case TAB must still work as a navigational character
1124 // JS: enabling again to make consistent with other platforms
1125 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1126 // navigation behaviour)
1128 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1130 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1132 wxNavigationKeyEvent new_event
;
1133 new_event
.SetEventObject( win
->GetParent() );
1134 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1135 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1136 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1137 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1138 new_event
.SetCurrentFocus( win
);
1139 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1142 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1144 (gdk_event
->keyval
== GDK_Escape
) )
1146 // however only do it if we have a Cancel button in the dialog,
1147 // otherwise the user code may get confused by the events from a
1148 // non-existing button and, worse, a wxButton might get button event
1149 // from another button which is not really expected
1150 wxWindow
*winForCancel
= win
,
1152 while ( winForCancel
)
1154 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1157 // found a cancel button
1161 if ( winForCancel
->IsTopLevel() )
1163 // no need to look further
1167 // maybe our parent has a cancel button?
1168 winForCancel
= winForCancel
->GetParent();
1173 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1174 eventClick
.SetEventObject(btnCancel
);
1175 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1181 g_signal_stop_emission_by_name (widget
, "key_press_event");
1191 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1195 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1197 // take modifiers, cursor position, timestamp etc. from the last
1198 // key_press_event that was fed into Input Method:
1199 if (window
->m_imData
->lastKeyEvent
)
1201 wxFillOtherKeyEventFields(event
,
1202 window
, window
->m_imData
->lastKeyEvent
);
1205 const wxWxCharBuffer
data(wxGTK_CONV_BACK(str
));
1211 // Implement OnCharHook by checking ancestor top level windows
1212 wxWindow
*parent
= window
;
1213 while (parent
&& !parent
->IsTopLevel())
1214 parent
= parent
->GetParent();
1216 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1219 event
.m_uniChar
= *pstr
;
1220 // Backward compatible for ISO-8859-1
1221 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1222 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1224 event
.m_keyCode
= *pstr
;
1225 #endif // wxUSE_UNICODE
1227 // To conform to the docs we need to translate Ctrl-alpha
1228 // characters to values in the range 1-26.
1229 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1231 event
.m_keyCode
= *pstr
- 'a' + 1;
1233 event
.m_uniChar
= event
.m_keyCode
;
1239 event
.SetEventType( wxEVT_CHAR_HOOK
);
1240 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1245 event
.SetEventType(wxEVT_CHAR
);
1246 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1253 //-----------------------------------------------------------------------------
1254 // "key_release_event" from any window
1255 //-----------------------------------------------------------------------------
1259 gtk_window_key_release_callback( GtkWidget
*widget
,
1260 GdkEventKey
*gdk_event
,
1266 wxapp_install_idle_handler();
1271 if (g_blockEventsOnDrag
)
1274 wxKeyEvent
event( wxEVT_KEY_UP
);
1275 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1277 // unknown key pressed, ignore (the event would be useless anyhow)
1281 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1284 g_signal_stop_emission_by_name (widget
, "key_release_event");
1289 // ============================================================================
1291 // ============================================================================
1293 // ----------------------------------------------------------------------------
1294 // mouse event processing helpers
1295 // ----------------------------------------------------------------------------
1297 // init wxMouseEvent with the info from GdkEventXXX struct
1298 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1299 wxMouseEvent
& event
,
1302 event
.SetTimestamp( gdk_event
->time
);
1303 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1304 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1305 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1306 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1307 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1308 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1309 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1310 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1312 event
.m_linesPerAction
= 3;
1313 event
.m_wheelDelta
= 120;
1314 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1315 event
.m_wheelRotation
= 120;
1316 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1317 event
.m_wheelRotation
= -120;
1320 wxPoint pt
= win
->GetClientAreaOrigin();
1321 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1322 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1324 event
.SetEventObject( win
);
1325 event
.SetId( win
->GetId() );
1326 event
.SetTimestamp( gdk_event
->time
);
1329 static void AdjustEventButtonState(wxMouseEvent
& event
)
1331 // GDK reports the old state of the button for a button press event, but
1332 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1333 // for a LEFT_DOWN event, not FALSE, so we will invert
1334 // left/right/middleDown for the corresponding click events
1336 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1337 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1338 (event
.GetEventType() == wxEVT_LEFT_UP
))
1340 event
.m_leftDown
= !event
.m_leftDown
;
1344 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1345 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1346 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1348 event
.m_middleDown
= !event
.m_middleDown
;
1352 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1353 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1354 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1356 event
.m_rightDown
= !event
.m_rightDown
;
1361 // find the window to send the mouse event too
1363 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1368 if (win
->m_wxwindow
)
1370 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1371 xx
+= pizza
->xoffset
;
1372 yy
+= pizza
->yoffset
;
1375 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1378 wxWindowGTK
*child
= node
->GetData();
1380 node
= node
->GetNext();
1381 if (!child
->IsShown())
1384 if (child
->IsTransparentForMouse())
1386 // wxStaticBox is transparent in the box itself
1387 int xx1
= child
->m_x
;
1388 int yy1
= child
->m_y
;
1389 int xx2
= child
->m_x
+ child
->m_width
;
1390 int yy2
= child
->m_y
+ child
->m_height
;
1393 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1395 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1397 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1399 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1410 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1411 (child
->m_x
<= xx
) &&
1412 (child
->m_y
<= yy
) &&
1413 (child
->m_x
+child
->m_width
>= xx
) &&
1414 (child
->m_y
+child
->m_height
>= yy
))
1427 //-----------------------------------------------------------------------------
1428 // "button_press_event"
1429 //-----------------------------------------------------------------------------
1433 gtk_window_button_press_callback( GtkWidget
*widget
,
1434 GdkEventButton
*gdk_event
,
1440 wxapp_install_idle_handler();
1443 wxPrintf( wxT("1) OnButtonPress from ") );
1444 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1445 wxPrintf( win->GetClassInfo()->GetClassName() );
1446 wxPrintf( wxT(".\n") );
1448 if (!win
->m_hasVMT
) return FALSE
;
1449 if (g_blockEventsOnDrag
) return TRUE
;
1450 if (g_blockEventsOnScroll
) return TRUE
;
1452 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1454 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1456 gtk_widget_grab_focus( win
->m_wxwindow
);
1458 wxPrintf( wxT("GrabFocus from ") );
1459 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1460 wxPrintf( win->GetClassInfo()->GetClassName() );
1461 wxPrintf( wxT(".\n") );
1465 // GDK sends surplus button down events
1466 // before a double click event. We
1467 // need to filter these out.
1468 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1470 GdkEvent
*peek_event
= gdk_event_peek();
1473 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1474 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1476 gdk_event_free( peek_event
);
1481 gdk_event_free( peek_event
);
1486 wxEventType event_type
= wxEVT_NULL
;
1488 // GdkDisplay is a GTK+ 2.2.0 thing
1489 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1490 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1491 !gtk_check_version(2,2,0) &&
1492 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1494 // Reset GDK internal timestamp variables in order to disable GDK
1495 // triple click events. GDK will then next time believe no button has
1496 // been clicked just before, and send a normal button click event.
1497 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1498 display
->button_click_time
[1] = 0;
1499 display
->button_click_time
[0] = 0;
1503 if (gdk_event
->button
== 1)
1505 // note that GDK generates triple click events which are not supported
1506 // by wxWidgets but still have to be passed to the app as otherwise
1507 // clicks would simply go missing
1508 switch (gdk_event
->type
)
1510 // we shouldn't get triple clicks at all for GTK2 because we
1511 // suppress them artificially using the code above but we still
1512 // should map them to something for GTK1 and not just ignore them
1513 // as this would lose clicks
1514 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1515 case GDK_BUTTON_PRESS
:
1516 event_type
= wxEVT_LEFT_DOWN
;
1519 case GDK_2BUTTON_PRESS
:
1520 event_type
= wxEVT_LEFT_DCLICK
;
1524 // just to silence gcc warnings
1528 else if (gdk_event
->button
== 2)
1530 switch (gdk_event
->type
)
1532 case GDK_3BUTTON_PRESS
:
1533 case GDK_BUTTON_PRESS
:
1534 event_type
= wxEVT_MIDDLE_DOWN
;
1537 case GDK_2BUTTON_PRESS
:
1538 event_type
= wxEVT_MIDDLE_DCLICK
;
1545 else if (gdk_event
->button
== 3)
1547 switch (gdk_event
->type
)
1549 case GDK_3BUTTON_PRESS
:
1550 case GDK_BUTTON_PRESS
:
1551 event_type
= wxEVT_RIGHT_DOWN
;
1554 case GDK_2BUTTON_PRESS
:
1555 event_type
= wxEVT_RIGHT_DCLICK
;
1562 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1564 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1566 event_type
= wxEVT_MOUSEWHEEL
;
1570 if ( event_type
== wxEVT_NULL
)
1572 // unknown mouse button or click type
1576 wxMouseEvent
event( event_type
);
1577 InitMouseEvent( win
, event
, gdk_event
);
1579 AdjustEventButtonState(event
);
1581 // wxListBox actually gets mouse events from the item, so we need to give it
1582 // a chance to correct this
1583 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1585 // find the correct window to send the event to: it may be a different one
1586 // from the one which got it at GTK+ level because some controls don't have
1587 // their own X window and thus cannot get any events.
1588 if ( !g_captureWindow
)
1589 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1591 // reset the event object and id in case win changed.
1592 event
.SetEventObject( win
);
1593 event
.SetId( win
->GetId() );
1595 if (win
->GetEventHandler()->ProcessEvent( event
))
1597 g_signal_stop_emission_by_name (widget
, "button_press_event");
1601 if (event_type
== wxEVT_RIGHT_DOWN
)
1603 // generate a "context menu" event: this is similar to right mouse
1604 // click under many GUIs except that it is generated differently
1605 // (right up under MSW, ctrl-click under Mac, right down here) and
1607 // (a) it's a command event and so is propagated to the parent
1608 // (b) under some ports it can be generated from kbd too
1609 // (c) it uses screen coords (because of (a))
1610 wxContextMenuEvent
evtCtx(
1613 win
->ClientToScreen(event
.GetPosition()));
1614 evtCtx
.SetEventObject(win
);
1615 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1622 //-----------------------------------------------------------------------------
1623 // "button_release_event"
1624 //-----------------------------------------------------------------------------
1628 gtk_window_button_release_callback( GtkWidget
*widget
,
1629 GdkEventButton
*gdk_event
,
1635 wxapp_install_idle_handler();
1637 if (!win
->m_hasVMT
) return FALSE
;
1638 if (g_blockEventsOnDrag
) return FALSE
;
1639 if (g_blockEventsOnScroll
) return FALSE
;
1641 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1643 wxEventType event_type
= wxEVT_NULL
;
1645 switch (gdk_event
->button
)
1648 event_type
= wxEVT_LEFT_UP
;
1652 event_type
= wxEVT_MIDDLE_UP
;
1656 event_type
= wxEVT_RIGHT_UP
;
1660 // unknwon button, don't process
1664 wxMouseEvent
event( event_type
);
1665 InitMouseEvent( win
, event
, gdk_event
);
1667 AdjustEventButtonState(event
);
1669 // same wxListBox hack as above
1670 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1672 if ( !g_captureWindow
)
1673 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1675 // reset the event object and id in case win changed.
1676 event
.SetEventObject( win
);
1677 event
.SetId( win
->GetId() );
1679 if (win
->GetEventHandler()->ProcessEvent( event
))
1681 g_signal_stop_emission_by_name (widget
, "button_release_event");
1689 //-----------------------------------------------------------------------------
1690 // "motion_notify_event"
1691 //-----------------------------------------------------------------------------
1695 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1696 GdkEventMotion
*gdk_event
,
1702 wxapp_install_idle_handler();
1704 if (!win
->m_hasVMT
) return FALSE
;
1705 if (g_blockEventsOnDrag
) return FALSE
;
1706 if (g_blockEventsOnScroll
) return FALSE
;
1708 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1710 if (gdk_event
->is_hint
)
1714 GdkModifierType state
;
1715 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1721 printf( "OnMotion from " );
1722 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1723 printf( win->GetClassInfo()->GetClassName() );
1727 wxMouseEvent
event( wxEVT_MOTION
);
1728 InitMouseEvent(win
, event
, gdk_event
);
1730 if ( g_captureWindow
)
1732 // synthetize a mouse enter or leave event if needed
1733 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1734 // This seems to be necessary and actually been added to
1735 // GDK itself in version 2.0.X
1738 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1739 if ( hasMouse
!= g_captureWindowHasMouse
)
1741 // the mouse changed window
1742 g_captureWindowHasMouse
= hasMouse
;
1744 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1745 : wxEVT_LEAVE_WINDOW
);
1746 InitMouseEvent(win
, eventM
, gdk_event
);
1747 eventM
.SetEventObject(win
);
1748 win
->GetEventHandler()->ProcessEvent(eventM
);
1753 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1755 // reset the event object and id in case win changed.
1756 event
.SetEventObject( win
);
1757 event
.SetId( win
->GetId() );
1760 if ( !g_captureWindow
)
1762 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1763 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1765 // Rewrite cursor handling here (away from idle).
1769 if (win
->GetEventHandler()->ProcessEvent( event
))
1771 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1779 //-----------------------------------------------------------------------------
1780 // "scroll_event", (mouse wheel event)
1781 //-----------------------------------------------------------------------------
1785 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1790 wxapp_install_idle_handler();
1792 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1793 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1798 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1799 // Can't use InitMouse macro because scroll events don't have button
1800 event
.SetTimestamp( gdk_event
->time
);
1801 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1802 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1803 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1804 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1805 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1806 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1807 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1808 event
.m_linesPerAction
= 3;
1809 event
.m_wheelDelta
= 120;
1810 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1811 event
.m_wheelRotation
= 120;
1813 event
.m_wheelRotation
= -120;
1815 wxPoint pt
= win
->GetClientAreaOrigin();
1816 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1817 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1819 event
.SetEventObject( win
);
1820 event
.SetId( win
->GetId() );
1821 event
.SetTimestamp( gdk_event
->time
);
1823 return win
->GetEventHandler()->ProcessEvent(event
);
1827 //-----------------------------------------------------------------------------
1829 //-----------------------------------------------------------------------------
1831 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1833 wxContextMenuEvent
event(
1837 event
.SetEventObject(win
);
1838 return win
->GetEventHandler()->ProcessEvent(event
);
1842 //-----------------------------------------------------------------------------
1844 //-----------------------------------------------------------------------------
1846 // send the wxChildFocusEvent and wxFocusEvent, common code of
1847 // gtk_window_focus_in_callback() and SetFocus()
1848 static bool DoSendFocusEvents(wxWindow
*win
)
1850 // Notify the parent keeping track of focus for the kbd navigation
1851 // purposes that we got it.
1852 wxChildFocusEvent
eventChildFocus(win
);
1853 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1855 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1856 eventFocus
.SetEventObject(win
);
1858 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1863 gtk_window_focus_in_callback( GtkWidget
*widget
,
1864 GdkEventFocus
*WXUNUSED(event
),
1870 wxapp_install_idle_handler();
1873 gtk_im_context_focus_in(win
->m_imData
->context
);
1876 g_focusWindow
= win
;
1878 wxLogTrace(TRACE_FOCUS
,
1879 _T("%s: focus in"), win
->GetName().c_str());
1883 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1887 // caret needs to be informed about focus change
1888 wxCaret
*caret
= win
->GetCaret();
1891 caret
->OnSetFocus();
1893 #endif // wxUSE_CARET
1895 gboolean ret
= FALSE
;
1897 // does the window itself think that it has the focus?
1898 if ( !win
->m_hasFocus
)
1900 // not yet, notify it
1901 win
->m_hasFocus
= true;
1903 (void)DoSendFocusEvents(win
);
1908 // Disable default focus handling for custom windows
1909 // since the default GTK+ handler issues a repaint
1910 if (win
->m_wxwindow
)
1917 //-----------------------------------------------------------------------------
1918 // "focus_out_event"
1919 //-----------------------------------------------------------------------------
1923 gtk_window_focus_out_callback( GtkWidget
*widget
,
1924 GdkEventFocus
*gdk_event
,
1930 wxapp_install_idle_handler();
1933 gtk_im_context_focus_out(win
->m_imData
->context
);
1935 wxLogTrace( TRACE_FOCUS
,
1936 _T("%s: focus out"), win
->GetName().c_str() );
1939 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1943 g_focusWindow
= (wxWindowGTK
*)NULL
;
1951 // caret needs to be informed about focus change
1952 wxCaret
*caret
= win
->GetCaret();
1955 caret
->OnKillFocus();
1957 #endif // wxUSE_CARET
1959 gboolean ret
= FALSE
;
1961 // don't send the window a kill focus event if it thinks that it doesn't
1962 // have focus already
1963 if ( win
->m_hasFocus
)
1965 win
->m_hasFocus
= false;
1967 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1968 event
.SetEventObject( win
);
1970 (void)win
->GetEventHandler()->ProcessEvent( event
);
1975 // Disable default focus handling for custom windows
1976 // since the default GTK+ handler issues a repaint
1977 if (win
->m_wxwindow
)
1984 //-----------------------------------------------------------------------------
1985 // "enter_notify_event"
1986 //-----------------------------------------------------------------------------
1990 gtk_window_enter_callback( GtkWidget
*widget
,
1991 GdkEventCrossing
*gdk_event
,
1997 wxapp_install_idle_handler();
1999 if (!win
->m_hasVMT
) return FALSE
;
2000 if (g_blockEventsOnDrag
) return FALSE
;
2002 // Event was emitted after a grab
2003 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2005 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2009 GdkModifierType state
= (GdkModifierType
)0;
2011 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2013 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2014 InitMouseEvent(win
, event
, gdk_event
);
2015 wxPoint pt
= win
->GetClientAreaOrigin();
2016 event
.m_x
= x
+ pt
.x
;
2017 event
.m_y
= y
+ pt
.y
;
2019 if ( !g_captureWindow
)
2021 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2022 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2024 // Rewrite cursor handling here (away from idle).
2028 if (win
->GetEventHandler()->ProcessEvent( event
))
2030 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2038 //-----------------------------------------------------------------------------
2039 // "leave_notify_event"
2040 //-----------------------------------------------------------------------------
2044 gtk_window_leave_callback( GtkWidget
*widget
,
2045 GdkEventCrossing
*gdk_event
,
2051 wxapp_install_idle_handler();
2053 if (!win
->m_hasVMT
) return FALSE
;
2054 if (g_blockEventsOnDrag
) return FALSE
;
2056 // Event was emitted after an ungrab
2057 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2059 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2061 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2062 event
.SetTimestamp( gdk_event
->time
);
2063 event
.SetEventObject( win
);
2067 GdkModifierType state
= (GdkModifierType
)0;
2069 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2071 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2072 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2073 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2074 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2075 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2076 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2077 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2079 wxPoint pt
= win
->GetClientAreaOrigin();
2080 event
.m_x
= x
+ pt
.x
;
2081 event
.m_y
= y
+ pt
.y
;
2083 if (win
->GetEventHandler()->ProcessEvent( event
))
2085 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2093 //-----------------------------------------------------------------------------
2094 // "value_changed" from scrollbar
2095 //-----------------------------------------------------------------------------
2099 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
2101 wxEventType eventType
= win
->GetScrollEventType(range
);
2102 if (eventType
!= wxEVT_NULL
)
2104 // Convert scroll event type to scrollwin event type
2105 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
2106 const int orient
= range
== win
->m_scrollBar
[0] ? wxHORIZONTAL
: wxVERTICAL
;
2107 const int i
= orient
== wxVERTICAL
;
2108 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
2109 event
.SetEventObject(win
);
2110 win
->m_blockValueChanged
[i
] = true;
2111 win
->GetEventHandler()->ProcessEvent(event
);
2112 win
->m_blockValueChanged
[i
] = false;
2117 //-----------------------------------------------------------------------------
2118 // "button_press_event" from scrollbar
2119 //-----------------------------------------------------------------------------
2123 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
2128 wxapp_install_idle_handler();
2130 g_blockEventsOnScroll
= true;
2131 win
->m_mouseButtonDown
= true;
2137 //-----------------------------------------------------------------------------
2138 // "button_release_event" from scrollbar
2139 //-----------------------------------------------------------------------------
2143 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
2147 g_blockEventsOnScroll
= false;
2148 win
->m_mouseButtonDown
= false;
2149 // If thumb tracking
2150 if (win
->m_isScrolling
)
2152 win
->m_isScrolling
= false;
2153 const int orient
= range
== win
->m_scrollBar
[0] ? wxHORIZONTAL
: wxVERTICAL
;
2154 wxScrollWinEvent
event(wxEVT_SCROLLWIN_THUMBRELEASE
, win
->GetScrollPos(orient
), orient
);
2155 event
.SetEventObject(win
);
2156 // To allow setting scroll position from event handler, sending event must
2157 // be deferred until after the GtkRange handler for this signal has run
2158 win
->GetEventHandler()->AddPendingEvent(event
);
2165 // ----------------------------------------------------------------------------
2166 // this wxWindowBase function is implemented here (in platform-specific file)
2167 // because it is static and so couldn't be made virtual
2168 // ----------------------------------------------------------------------------
2170 wxWindow
*wxWindowBase::DoFindFocus()
2172 // the cast is necessary when we compile in wxUniversal mode
2173 return (wxWindow
*)g_focusWindow
;
2176 //-----------------------------------------------------------------------------
2177 // "realize" from m_widget
2178 //-----------------------------------------------------------------------------
2180 /* We cannot set colours and fonts before the widget has
2181 been realized, so we do this directly after realization. */
2185 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2190 wxapp_install_idle_handler();
2194 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2195 gtk_im_context_set_client_window( win
->m_imData
->context
,
2196 pizza
->bin_window
);
2199 wxWindowCreateEvent
event( win
);
2200 event
.SetEventObject( win
);
2201 win
->GetEventHandler()->ProcessEvent( event
);
2205 //-----------------------------------------------------------------------------
2207 //-----------------------------------------------------------------------------
2211 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2212 GtkAllocation
*WXUNUSED(alloc
),
2216 wxapp_install_idle_handler();
2218 int client_width
= 0;
2219 int client_height
= 0;
2220 win
->GetClientSize( &client_width
, &client_height
);
2221 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2224 win
->m_oldClientWidth
= client_width
;
2225 win
->m_oldClientHeight
= client_height
;
2227 if (!win
->m_nativeSizeEvent
)
2229 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2230 event
.SetEventObject( win
);
2231 win
->GetEventHandler()->ProcessEvent( event
);
2238 #define WXUNUSED_UNLESS_XIM(param) param
2240 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2243 /* Resize XIM window */
2247 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2248 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2249 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2252 wxapp_install_idle_handler();
2258 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2262 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2263 win
->m_icattr
->preedit_area
.width
= width
;
2264 win
->m_icattr
->preedit_area
.height
= height
;
2265 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2271 //-----------------------------------------------------------------------------
2272 // "realize" from m_wxwindow
2273 //-----------------------------------------------------------------------------
2275 /* Initialize XIM support */
2279 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2280 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2283 wxapp_install_idle_handler();
2286 if (win
->m_ic
) return;
2287 if (!widget
) return;
2288 if (!gdk_im_ready()) return;
2290 win
->m_icattr
= gdk_ic_attr_new();
2291 if (!win
->m_icattr
) return;
2295 GdkColormap
*colormap
;
2296 GdkICAttr
*attr
= win
->m_icattr
;
2297 unsigned attrmask
= GDK_IC_ALL_REQ
;
2299 GdkIMStyle supported_style
= (GdkIMStyle
)
2300 (GDK_IM_PREEDIT_NONE
|
2301 GDK_IM_PREEDIT_NOTHING
|
2302 GDK_IM_PREEDIT_POSITION
|
2303 GDK_IM_STATUS_NONE
|
2304 GDK_IM_STATUS_NOTHING
);
2306 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2307 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2309 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2310 attr
->client_window
= widget
->window
;
2312 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2313 gtk_widget_get_default_colormap ())
2315 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2316 attr
->preedit_colormap
= colormap
;
2319 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2320 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2321 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2322 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2324 switch (style
& GDK_IM_PREEDIT_MASK
)
2326 case GDK_IM_PREEDIT_POSITION
:
2327 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2329 g_warning ("over-the-spot style requires fontset");
2333 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2335 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2336 attr
->spot_location
.x
= 0;
2337 attr
->spot_location
.y
= height
;
2338 attr
->preedit_area
.x
= 0;
2339 attr
->preedit_area
.y
= 0;
2340 attr
->preedit_area
.width
= width
;
2341 attr
->preedit_area
.height
= height
;
2342 attr
->preedit_fontset
= widget
->style
->font
;
2347 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2349 if (win
->m_ic
== NULL
)
2350 g_warning ("Can't create input context.");
2353 mask
= gdk_window_get_events (widget
->window
);
2354 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2355 gdk_window_set_events (widget
->window
, mask
);
2357 if (GTK_WIDGET_HAS_FOCUS(widget
))
2358 gdk_im_begin (win
->m_ic
, widget
->window
);
2364 //-----------------------------------------------------------------------------
2365 // InsertChild for wxWindowGTK.
2366 //-----------------------------------------------------------------------------
2368 /* Callback for wxWindowGTK. This very strange beast has to be used because
2369 * C++ has no virtual methods in a constructor. We have to emulate a
2370 * virtual function here as wxNotebook requires a different way to insert
2371 * a child in it. I had opted for creating a wxNotebookPage window class
2372 * which would have made this superfluous (such in the MDI window system),
2373 * but no-one was listening to me... */
2375 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2377 /* the window might have been scrolled already, do we
2378 have to adapt the position */
2379 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2380 child
->m_x
+= pizza
->xoffset
;
2381 child
->m_y
+= pizza
->yoffset
;
2383 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2384 GTK_WIDGET(child
->m_widget
),
2391 //-----------------------------------------------------------------------------
2393 //-----------------------------------------------------------------------------
2395 wxWindow
*wxGetActiveWindow()
2397 return wxWindow::FindFocus();
2401 wxMouseState
wxGetMouseState()
2407 GdkModifierType mask
;
2409 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2413 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2414 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2415 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2417 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2418 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2419 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2420 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2425 //-----------------------------------------------------------------------------
2427 //-----------------------------------------------------------------------------
2429 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2431 #ifdef __WXUNIVERSAL__
2432 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2434 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2435 #endif // __WXUNIVERSAL__/__WXGTK__
2437 void wxWindowGTK::Init()
2440 m_widget
= (GtkWidget
*) NULL
;
2441 m_wxwindow
= (GtkWidget
*) NULL
;
2442 m_focusWidget
= (GtkWidget
*) NULL
;
2452 m_needParent
= true;
2453 m_isBeingDeleted
= false;
2456 m_nativeSizeEvent
= false;
2458 m_hasScrolling
= false;
2459 m_isScrolling
= false;
2460 m_mouseButtonDown
= false;
2461 m_blockScrollEvent
= false;
2464 m_scrollBar
[1] = NULL
;
2467 m_blockValueChanged
[0] =
2468 m_blockValueChanged
[1] = false;
2471 m_oldClientHeight
= 0;
2475 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2477 m_acceptsFocus
= false;
2480 m_clipPaintRegion
= false;
2482 m_needsStyleChange
= false;
2484 m_cursor
= *wxSTANDARD_CURSOR
;
2487 m_dirtyTabOrder
= false;
2490 wxWindowGTK::wxWindowGTK()
2495 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2500 const wxString
&name
)
2504 Create( parent
, id
, pos
, size
, style
, name
);
2507 bool wxWindowGTK::Create( wxWindow
*parent
,
2512 const wxString
&name
)
2514 if (!PreCreation( parent
, pos
, size
) ||
2515 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2517 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2521 m_insertCallback
= wxInsertChildInWindow
;
2523 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2524 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2526 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2528 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2529 scroll_class
->scrollbar_spacing
= 0;
2531 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2533 m_scrollBar
[0] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2534 m_scrollBar
[1] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2536 m_wxwindow
= gtk_pizza_new();
2538 #ifndef __WXUNIVERSAL__
2539 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2541 if (HasFlag(wxRAISED_BORDER
))
2543 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2545 else if (HasFlag(wxSUNKEN_BORDER
))
2547 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2549 else if (HasFlag(wxSIMPLE_BORDER
))
2551 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2555 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2557 #endif // __WXUNIVERSAL__
2559 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2561 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2562 m_acceptsFocus
= true;
2564 // these handlers block mouse events to any window during scrolling such as
2565 // motion events and prevent GTK and wxWidgets from fighting over where the
2567 g_signal_connect(m_scrollBar
[0], "button_press_event",
2568 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2569 g_signal_connect(m_scrollBar
[1], "button_press_event",
2570 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2571 g_signal_connect(m_scrollBar
[0], "button_release_event",
2572 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2573 g_signal_connect(m_scrollBar
[1], "button_release_event",
2574 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2576 // these handlers get notified when scrollbar slider moves
2578 g_signal_connect(m_scrollBar
[0], "value_changed",
2579 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2580 g_signal_connect(m_scrollBar
[1], "value_changed",
2581 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2583 gtk_widget_show( m_wxwindow
);
2586 m_parent
->DoAddChild( this );
2588 m_focusWidget
= m_wxwindow
;
2595 wxWindowGTK::~wxWindowGTK()
2599 if (g_focusWindow
== this)
2600 g_focusWindow
= NULL
;
2602 if ( g_delayedFocus
== this )
2603 g_delayedFocus
= NULL
;
2605 m_isBeingDeleted
= true;
2608 // destroy children before destroying this window itself
2611 // unhook focus handlers to prevent stray events being
2612 // propagated to this (soon to be) dead object
2613 if (m_focusWidget
!= NULL
)
2615 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2616 (gpointer
) gtk_window_focus_in_callback
,
2618 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2619 (gpointer
) gtk_window_focus_out_callback
,
2628 gdk_ic_destroy (m_ic
);
2630 gdk_ic_attr_destroy (m_icattr
);
2633 // delete before the widgets to avoid a crash on solaris
2638 gtk_widget_destroy( m_wxwindow
);
2639 m_wxwindow
= (GtkWidget
*) NULL
;
2644 gtk_widget_destroy( m_widget
);
2645 m_widget
= (GtkWidget
*) NULL
;
2649 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2651 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2653 // Use either the given size, or the default if -1 is given.
2654 // See wxWindowBase for these functions.
2655 m_width
= WidthDefault(size
.x
) ;
2656 m_height
= HeightDefault(size
.y
);
2664 void wxWindowGTK::PostCreation()
2666 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2672 // these get reported to wxWidgets -> wxPaintEvent
2674 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2676 g_signal_connect (m_wxwindow
, "expose_event",
2677 G_CALLBACK (gtk_window_expose_callback
), this);
2679 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2682 // Create input method handler
2683 m_imData
= new wxGtkIMData
;
2685 // Cannot handle drawing preedited text yet
2686 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2688 g_signal_connect (m_imData
->context
, "commit",
2689 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2691 // these are called when the "sunken" or "raised" borders are drawn
2692 g_signal_connect (m_widget
, "expose_event",
2693 G_CALLBACK (gtk_window_own_expose_callback
), this);
2698 if (!GTK_IS_WINDOW(m_widget
))
2700 if (m_focusWidget
== NULL
)
2701 m_focusWidget
= m_widget
;
2705 g_signal_connect (m_focusWidget
, "focus_in_event",
2706 G_CALLBACK (gtk_window_focus_in_callback
), this);
2707 g_signal_connect (m_focusWidget
, "focus_out_event",
2708 G_CALLBACK (gtk_window_focus_out_callback
), this);
2712 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2713 G_CALLBACK (gtk_window_focus_in_callback
), this);
2714 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2715 G_CALLBACK (gtk_window_focus_out_callback
), this);
2719 // connect to the various key and mouse handlers
2721 GtkWidget
*connect_widget
= GetConnectWidget();
2723 ConnectWidget( connect_widget
);
2725 /* We cannot set colours, fonts and cursors before the widget has
2726 been realized, so we do this directly after realization */
2727 g_signal_connect (connect_widget
, "realize",
2728 G_CALLBACK (gtk_window_realized_callback
), this);
2732 // Catch native resize events
2733 g_signal_connect (m_wxwindow
, "size_allocate",
2734 G_CALLBACK (gtk_window_size_callback
), this);
2736 // Initialize XIM support
2737 g_signal_connect (m_wxwindow
, "realize",
2738 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2740 // And resize XIM window
2741 g_signal_connect (m_wxwindow
, "size_allocate",
2742 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2745 if (GTK_IS_COMBO(m_widget
))
2747 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2749 g_signal_connect (gcombo
->entry
, "size_request",
2750 G_CALLBACK (wxgtk_combo_size_request_callback
),
2753 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2754 else if (GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2756 // If we connect to the "size_request" signal of a GtkFileChooserButton
2757 // then that control won't be sized properly when placed inside sizers
2758 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2759 // FIXME: what should be done here ?
2764 // This is needed if we want to add our windows into native
2765 // GTK controls, such as the toolbar. With this callback, the
2766 // toolbar gets to know the correct size (the one set by the
2767 // programmer). Sadly, it misbehaves for wxComboBox.
2768 g_signal_connect (m_widget
, "size_request",
2769 G_CALLBACK (wxgtk_window_size_request_callback
),
2773 InheritAttributes();
2777 // unless the window was created initially hidden (i.e. Hide() had been
2778 // called before Create()), we should show it at GTK+ level as well
2780 gtk_widget_show( m_widget
);
2783 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2785 g_signal_connect (widget
, "key_press_event",
2786 G_CALLBACK (gtk_window_key_press_callback
), this);
2787 g_signal_connect (widget
, "key_release_event",
2788 G_CALLBACK (gtk_window_key_release_callback
), this);
2789 g_signal_connect (widget
, "button_press_event",
2790 G_CALLBACK (gtk_window_button_press_callback
), this);
2791 g_signal_connect (widget
, "button_release_event",
2792 G_CALLBACK (gtk_window_button_release_callback
), this);
2793 g_signal_connect (widget
, "motion_notify_event",
2794 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2795 g_signal_connect (widget
, "scroll_event",
2796 G_CALLBACK (window_scroll_event
), this);
2797 g_signal_connect (widget
, "popup_menu",
2798 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2799 g_signal_connect (widget
, "enter_notify_event",
2800 G_CALLBACK (gtk_window_enter_callback
), this);
2801 g_signal_connect (widget
, "leave_notify_event",
2802 G_CALLBACK (gtk_window_leave_callback
), this);
2805 bool wxWindowGTK::Destroy()
2807 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2811 return wxWindowBase::Destroy();
2814 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2816 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2819 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2821 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2822 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2825 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2828 if (m_resizing
) return; /* I don't like recursions */
2831 int currentX
, currentY
;
2832 GetPosition(¤tX
, ¤tY
);
2833 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2835 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2837 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2839 // calculate the best size if we should auto size the window
2840 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2841 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2843 const wxSize sizeBest
= GetBestSize();
2844 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2846 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2847 height
= sizeBest
.y
;
2855 int minWidth
= GetMinWidth(),
2856 minHeight
= GetMinHeight(),
2857 maxWidth
= GetMaxWidth(),
2858 maxHeight
= GetMaxHeight();
2860 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2861 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2862 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2863 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2865 #if wxUSE_TOOLBAR_NATIVE
2866 if (wxDynamicCast(GetParent(), wxToolBar
))
2868 // don't take the x,y values, they're wrong because toolbar sets them
2869 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2870 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2871 if (GTK_WIDGET_VISIBLE (widget
))
2872 gtk_widget_queue_resize (widget
);
2876 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2878 // don't set the size for children of wxNotebook, just take the values.
2886 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2887 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2889 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2890 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2894 m_x
= x
+ pizza
->xoffset
;
2895 m_y
= y
+ pizza
->yoffset
;
2898 int left_border
= 0;
2899 int right_border
= 0;
2901 int bottom_border
= 0;
2903 /* the default button has a border around it */
2904 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2906 GtkBorder
*default_border
= NULL
;
2907 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2910 left_border
+= default_border
->left
;
2911 right_border
+= default_border
->right
;
2912 top_border
+= default_border
->top
;
2913 bottom_border
+= default_border
->bottom
;
2914 g_free( default_border
);
2918 DoMoveWindow( m_x
-top_border
,
2920 m_width
+left_border
+right_border
,
2921 m_height
+top_border
+bottom_border
);
2926 /* Sometimes the client area changes size without the
2927 whole windows's size changing, but if the whole
2928 windows's size doesn't change, no wxSizeEvent will
2929 normally be sent. Here we add an extra test if
2930 the client test has been changed and this will
2932 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2936 wxPrintf( "OnSize sent from " );
2937 if (GetClassInfo() && GetClassInfo()->GetClassName())
2938 wxPrintf( GetClassInfo()->GetClassName() );
2939 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2942 if (!m_nativeSizeEvent
)
2944 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2945 event
.SetEventObject( this );
2946 GetEventHandler()->ProcessEvent( event
);
2952 void wxWindowGTK::OnInternalIdle()
2954 if ( m_dirtyTabOrder
)
2956 m_dirtyTabOrder
= false;
2960 // Update style if the window was not yet realized
2961 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2962 if (m_needsStyleChange
)
2964 SetBackgroundStyle(GetBackgroundStyle());
2965 m_needsStyleChange
= false;
2968 // Update invalidated regions.
2971 wxCursor cursor
= m_cursor
;
2972 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2976 /* I now set the cursor anew in every OnInternalIdle call
2977 as setting the cursor in a parent window also effects the
2978 windows above so that checking for the current cursor is
2983 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2985 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2987 if (!g_globalCursor
.Ok())
2988 cursor
= *wxSTANDARD_CURSOR
;
2990 window
= m_widget
->window
;
2991 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2992 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2998 GdkWindow
*window
= m_widget
->window
;
2999 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3000 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3005 if (wxUpdateUIEvent::CanUpdate(this))
3006 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3009 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3011 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3013 if (width
) (*width
) = m_width
;
3014 if (height
) (*height
) = m_height
;
3017 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3019 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3028 GetScrollbarWidth(m_widget
, dw
, dh
);
3031 #ifndef __WXUNIVERSAL__
3032 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3034 // shadow border size is 2
3038 if (HasFlag(wxSIMPLE_BORDER
))
3040 // simple border size is 1
3044 #endif // __WXUNIVERSAL__
3050 SetSize(width
, height
);
3053 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3055 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3067 GetScrollbarWidth(m_widget
, dw
, dh
);
3070 #ifndef __WXUNIVERSAL__
3071 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3073 // shadow border size is 2
3077 if (HasFlag(wxSIMPLE_BORDER
))
3079 // simple border size is 1
3083 #endif // __WXUNIVERSAL__
3089 if (width
) *width
= w
;
3090 if (height
) *height
= h
;
3093 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3095 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3099 if (m_parent
&& m_parent
->m_wxwindow
)
3101 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3102 dx
= pizza
->xoffset
;
3103 dy
= pizza
->yoffset
;
3106 if (x
) (*x
) = m_x
- dx
;
3107 if (y
) (*y
) = m_y
- dy
;
3110 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3112 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3114 if (!m_widget
->window
) return;
3116 GdkWindow
*source
= (GdkWindow
*) NULL
;
3118 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3120 source
= m_widget
->window
;
3124 gdk_window_get_origin( source
, &org_x
, &org_y
);
3128 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3130 org_x
+= m_widget
->allocation
.x
;
3131 org_y
+= m_widget
->allocation
.y
;
3139 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3141 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3143 if (!m_widget
->window
) return;
3145 GdkWindow
*source
= (GdkWindow
*) NULL
;
3147 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3149 source
= m_widget
->window
;
3153 gdk_window_get_origin( source
, &org_x
, &org_y
);
3157 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3159 org_x
+= m_widget
->allocation
.x
;
3160 org_y
+= m_widget
->allocation
.y
;
3168 bool wxWindowGTK::Show( bool show
)
3170 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3172 if (!wxWindowBase::Show(show
))
3179 gtk_widget_show( m_widget
);
3181 gtk_widget_hide( m_widget
);
3183 wxShowEvent
eventShow(GetId(), show
);
3184 eventShow
.SetEventObject(this);
3186 GetEventHandler()->ProcessEvent(eventShow
);
3191 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3193 win
->OnParentEnable(enable
);
3195 // Recurse, so that children have the opportunity to Do The Right Thing
3196 // and reset colours that have been messed up by a parent's (really ancestor's)
3198 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3200 node
= node
->GetNext() )
3202 wxWindow
*child
= node
->GetData();
3203 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3204 wxWindowNotifyEnable(child
, enable
);
3208 bool wxWindowGTK::Enable( bool enable
)
3210 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3212 if (!wxWindowBase::Enable(enable
))
3218 gtk_widget_set_sensitive( m_widget
, enable
);
3220 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3222 wxWindowNotifyEnable(this, enable
);
3227 int wxWindowGTK::GetCharHeight() const
3229 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3231 wxFont font
= GetFont();
3232 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3234 PangoContext
*context
= NULL
;
3236 context
= gtk_widget_get_pango_context( m_widget
);
3241 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3242 PangoLayout
*layout
= pango_layout_new(context
);
3243 pango_layout_set_font_description(layout
, desc
);
3244 pango_layout_set_text(layout
, "H", 1);
3245 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3247 PangoRectangle rect
;
3248 pango_layout_line_get_extents(line
, NULL
, &rect
);
3250 g_object_unref (layout
);
3252 return (int) PANGO_PIXELS(rect
.height
);
3255 int wxWindowGTK::GetCharWidth() const
3257 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3259 wxFont font
= GetFont();
3260 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3262 PangoContext
*context
= NULL
;
3264 context
= gtk_widget_get_pango_context( m_widget
);
3269 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3270 PangoLayout
*layout
= pango_layout_new(context
);
3271 pango_layout_set_font_description(layout
, desc
);
3272 pango_layout_set_text(layout
, "g", 1);
3273 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3275 PangoRectangle rect
;
3276 pango_layout_line_get_extents(line
, NULL
, &rect
);
3278 g_object_unref (layout
);
3280 return (int) PANGO_PIXELS(rect
.width
);
3283 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3287 int *externalLeading
,
3288 const wxFont
*theFont
) const
3290 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3292 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3301 PangoContext
*context
= NULL
;
3303 context
= gtk_widget_get_pango_context( m_widget
);
3312 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3313 PangoLayout
*layout
= pango_layout_new(context
);
3314 pango_layout_set_font_description(layout
, desc
);
3316 const wxCharBuffer data
= wxGTK_CONV( string
);
3318 pango_layout_set_text(layout
, data
, strlen(data
));
3321 PangoRectangle rect
;
3322 pango_layout_get_extents(layout
, NULL
, &rect
);
3324 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3325 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3328 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3329 int baseline
= pango_layout_iter_get_baseline(iter
);
3330 pango_layout_iter_free(iter
);
3331 *descent
= *y
- PANGO_PIXELS(baseline
);
3333 if (externalLeading
) (*externalLeading
) = 0; // ??
3335 g_object_unref (layout
);
3338 void wxWindowGTK::SetFocus()
3340 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3343 // don't do anything if we already have focus
3349 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3351 gtk_widget_grab_focus (m_wxwindow
);
3356 if (GTK_IS_CONTAINER(m_widget
))
3358 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3361 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3364 if (!GTK_WIDGET_REALIZED(m_widget
))
3366 // we can't set the focus to the widget now so we remember that
3367 // it should be focused and will do it later, during the idle
3368 // time, as soon as we can
3369 wxLogTrace(TRACE_FOCUS
,
3370 _T("Delaying setting focus to %s(%s)"),
3371 GetClassInfo()->GetClassName(), GetLabel().c_str());
3373 g_delayedFocus
= this;
3377 wxLogTrace(TRACE_FOCUS
,
3378 _T("Setting focus to %s(%s)"),
3379 GetClassInfo()->GetClassName(), GetLabel().c_str());
3381 gtk_widget_grab_focus (m_widget
);
3386 wxLogTrace(TRACE_FOCUS
,
3387 _T("Can't set focus to %s(%s)"),
3388 GetClassInfo()->GetClassName(), GetLabel().c_str());
3393 bool wxWindowGTK::AcceptsFocus() const
3395 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3398 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3400 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3402 wxWindowGTK
*oldParent
= m_parent
,
3403 *newParent
= (wxWindowGTK
*)newParentBase
;
3405 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3407 if ( !wxWindowBase::Reparent(newParent
) )
3410 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3412 /* prevent GTK from deleting the widget arbitrarily */
3413 gtk_widget_ref( m_widget
);
3417 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3420 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3424 /* insert GTK representation */
3425 (*(newParent
->m_insertCallback
))(newParent
, this);
3428 /* reverse: prevent GTK from deleting the widget arbitrarily */
3429 gtk_widget_unref( m_widget
);
3434 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3436 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3438 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3440 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3445 /* insert GTK representation */
3446 (*m_insertCallback
)(this, child
);
3449 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3451 wxWindowBase::AddChild(child
);
3452 m_dirtyTabOrder
= true;
3454 wxapp_install_idle_handler();
3457 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3459 wxWindowBase::RemoveChild(child
);
3460 m_dirtyTabOrder
= true;
3462 wxapp_install_idle_handler();
3465 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3467 wxWindowBase::DoMoveInTabOrder(win
, move
);
3468 m_dirtyTabOrder
= true;
3470 wxapp_install_idle_handler();
3473 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3475 // none needed by default
3479 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3481 // nothing to do by default since none is needed
3484 void wxWindowGTK::RealizeTabOrder()
3488 if ( !m_children
.empty() )
3490 // we don't only construct the correct focus chain but also use
3491 // this opportunity to update the mnemonic widgets for the widgets
3494 GList
*chain
= NULL
;
3495 wxWindowGTK
* mnemonicWindow
= NULL
;
3497 for ( wxWindowList::const_iterator i
= m_children
.begin();
3498 i
!= m_children
.end();
3501 wxWindowGTK
*win
= *i
;
3503 if ( mnemonicWindow
)
3505 if ( win
->AcceptsFocusFromKeyboard() )
3507 // wxComboBox et al. needs to focus on on a different
3508 // widget than m_widget, so if the main widget isn't
3509 // focusable try the connect widget
3510 GtkWidget
* w
= win
->m_widget
;
3511 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3513 w
= win
->GetConnectWidget();
3514 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3520 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3521 mnemonicWindow
= NULL
;
3525 else if ( win
->GTKWidgetNeedsMnemonic() )
3527 mnemonicWindow
= win
;
3530 chain
= g_list_prepend(chain
, win
->m_widget
);
3533 chain
= g_list_reverse(chain
);
3535 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3540 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3545 void wxWindowGTK::Raise()
3547 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3549 if (m_wxwindow
&& m_wxwindow
->window
)
3551 gdk_window_raise( m_wxwindow
->window
);
3553 else if (m_widget
->window
)
3555 gdk_window_raise( m_widget
->window
);
3559 void wxWindowGTK::Lower()
3561 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3563 if (m_wxwindow
&& m_wxwindow
->window
)
3565 gdk_window_lower( m_wxwindow
->window
);
3567 else if (m_widget
->window
)
3569 gdk_window_lower( m_widget
->window
);
3573 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3575 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3577 if (cursor
== m_cursor
)
3581 wxapp_install_idle_handler();
3583 if (cursor
== wxNullCursor
)
3584 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3586 return wxWindowBase::SetCursor( cursor
);
3589 void wxWindowGTK::WarpPointer( int x
, int y
)
3591 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3593 // We provide this function ourselves as it is
3594 // missing in GDK (top of this file).
3596 GdkWindow
*window
= (GdkWindow
*) NULL
;
3598 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3600 window
= GetConnectWidget()->window
;
3603 gdk_window_warp_pointer( window
, x
, y
);
3606 bool wxWindowGTK::ScrollLines(int lines
)
3608 bool changed
= false;
3609 GtkRange
* range
= m_scrollBar
[1];
3612 GtkAdjustment
* adj
= range
->adjustment
;
3613 const int pos
= int(adj
->value
+ 0.5);
3614 gtk_range_set_value(range
, pos
+ lines
);
3615 changed
= pos
!= int(adj
->value
+ 0.5);
3620 bool wxWindowGTK::ScrollPages(int pages
)
3622 bool changed
= false;
3623 GtkRange
* range
= m_scrollBar
[1];
3626 GtkAdjustment
* adj
= range
->adjustment
;
3627 const int pos
= int(adj
->value
+ 0.5);
3628 gtk_range_set_value(range
, pos
+ pages
* adj
->page_size
);
3629 changed
= pos
!= int(adj
->value
+ 0.5);
3634 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3638 if (!m_widget
->window
)
3643 GdkRectangle gdk_rect
,
3647 gdk_rect
.x
= rect
->x
;
3648 gdk_rect
.y
= rect
->y
;
3649 gdk_rect
.width
= rect
->width
;
3650 gdk_rect
.height
= rect
->height
;
3653 else // invalidate everything
3658 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3662 void wxWindowGTK::Update()
3666 // when we call Update() we really want to update the window immediately on
3667 // screen, even if it means flushing the entire queue and hence slowing down
3668 // everything -- but it should still be done, it's just that Update() should
3669 // be called very rarely
3673 void wxWindowGTK::GtkUpdate()
3675 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3676 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3678 // for consistency with other platforms (and also because it's convenient
3679 // to be able to update an entire TLW by calling Update() only once), we
3680 // should also update all our children here
3681 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3683 node
= node
->GetNext() )
3685 node
->GetData()->GtkUpdate();
3689 void wxWindowGTK::GtkSendPaintEvents()
3693 m_updateRegion
.Clear();
3697 // Clip to paint region in wxClientDC
3698 m_clipPaintRegion
= true;
3700 // widget to draw on
3701 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3703 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3705 // find ancestor from which to steal background
3706 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3708 parent
= (wxWindow
*)this;
3710 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3712 wxRegionIterator
upd( m_updateRegion
);
3716 rect
.x
= upd
.GetX();
3717 rect
.y
= upd
.GetY();
3718 rect
.width
= upd
.GetWidth();
3719 rect
.height
= upd
.GetHeight();
3721 gtk_paint_flat_box( parent
->m_widget
->style
,
3723 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3737 wxWindowDC
dc( (wxWindow
*)this );
3738 dc
.SetClippingRegion( m_updateRegion
);
3740 wxEraseEvent
erase_event( GetId(), &dc
);
3741 erase_event
.SetEventObject( this );
3743 GetEventHandler()->ProcessEvent(erase_event
);
3746 wxNcPaintEvent
nc_paint_event( GetId() );
3747 nc_paint_event
.SetEventObject( this );
3748 GetEventHandler()->ProcessEvent( nc_paint_event
);
3750 wxPaintEvent
paint_event( GetId() );
3751 paint_event
.SetEventObject( this );
3752 GetEventHandler()->ProcessEvent( paint_event
);
3754 m_clipPaintRegion
= false;
3756 m_updateRegion
.Clear();
3759 void wxWindowGTK::SetDoubleBuffered( bool on
)
3761 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3764 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3767 void wxWindowGTK::ClearBackground()
3769 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3773 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3775 wxWindowBase::DoSetToolTip(tip
);
3778 m_tooltip
->Apply( (wxWindow
*)this );
3781 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3783 wxString
tmp( tip
);
3784 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3786 #endif // wxUSE_TOOLTIPS
3788 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3790 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3792 if (!wxWindowBase::SetBackgroundColour(colour
))
3797 // We need the pixel value e.g. for background clearing.
3798 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3801 // apply style change (forceStyle=true so that new style is applied
3802 // even if the bg colour changed from valid to wxNullColour)
3803 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3804 ApplyWidgetStyle(true);
3809 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3811 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3813 if (!wxWindowBase::SetForegroundColour(colour
))
3820 // We need the pixel value e.g. for background clearing.
3821 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3824 // apply style change (forceStyle=true so that new style is applied
3825 // even if the bg colour changed from valid to wxNullColour):
3826 ApplyWidgetStyle(true);
3831 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3833 return gtk_widget_get_pango_context( m_widget
);
3836 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3838 // do we need to apply any changes at all?
3841 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3846 GtkRcStyle
*style
= gtk_rc_style_new();
3851 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3854 if ( m_foregroundColour
.Ok() )
3856 GdkColor
*fg
= m_foregroundColour
.GetColor();
3858 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3859 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3861 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3862 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3864 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3865 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3868 if ( m_backgroundColour
.Ok() )
3870 GdkColor
*bg
= m_backgroundColour
.GetColor();
3872 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3873 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3874 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3875 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3877 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3878 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3879 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3880 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3882 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3883 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3884 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3885 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3887 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3888 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3889 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3890 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3896 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3898 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3901 DoApplyWidgetStyle(style
);
3902 gtk_rc_style_unref(style
);
3905 // Style change may affect GTK+'s size calculation:
3906 InvalidateBestSize();
3909 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3912 gtk_widget_modify_style(m_wxwindow
, style
);
3914 gtk_widget_modify_style(m_widget
, style
);
3917 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3919 wxWindowBase::SetBackgroundStyle(style
);
3921 if (style
== wxBG_STYLE_CUSTOM
)
3923 GdkWindow
*window
= (GdkWindow
*) NULL
;
3925 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3927 window
= GetConnectWidget()->window
;
3931 // Make sure GDK/X11 doesn't refresh the window
3933 gdk_window_set_back_pixmap( window
, None
, False
);
3935 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3938 m_needsStyleChange
= false;
3941 // Do in OnIdle, because the window is not yet available
3942 m_needsStyleChange
= true;
3944 // Don't apply widget style, or we get a grey background
3948 // apply style change (forceStyle=true so that new style is applied
3949 // even if the bg colour changed from valid to wxNullColour):
3950 ApplyWidgetStyle(true);
3955 #if wxUSE_DRAG_AND_DROP
3957 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3959 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3961 GtkWidget
*dnd_widget
= GetConnectWidget();
3963 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3965 if (m_dropTarget
) delete m_dropTarget
;
3966 m_dropTarget
= dropTarget
;
3968 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3971 #endif // wxUSE_DRAG_AND_DROP
3973 GtkWidget
* wxWindowGTK::GetConnectWidget()
3975 GtkWidget
*connect_widget
= m_widget
;
3976 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3978 return connect_widget
;
3981 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3984 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3986 return (window
== m_widget
->window
);
3989 bool wxWindowGTK::SetFont( const wxFont
&font
)
3991 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3993 if (!wxWindowBase::SetFont(font
))
3996 // apply style change (forceStyle=true so that new style is applied
3997 // even if the font changed from valid to wxNullFont):
3998 ApplyWidgetStyle(true);
4003 void wxWindowGTK::DoCaptureMouse()
4005 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4007 GdkWindow
*window
= (GdkWindow
*) NULL
;
4009 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4011 window
= GetConnectWidget()->window
;
4013 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4015 const wxCursor
* cursor
= &m_cursor
;
4017 cursor
= wxSTANDARD_CURSOR
;
4019 gdk_pointer_grab( window
, FALSE
,
4021 (GDK_BUTTON_PRESS_MASK
|
4022 GDK_BUTTON_RELEASE_MASK
|
4023 GDK_POINTER_MOTION_HINT_MASK
|
4024 GDK_POINTER_MOTION_MASK
),
4026 cursor
->GetCursor(),
4027 (guint32
)GDK_CURRENT_TIME
);
4028 g_captureWindow
= this;
4029 g_captureWindowHasMouse
= true;
4032 void wxWindowGTK::DoReleaseMouse()
4034 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4036 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4038 g_captureWindow
= (wxWindowGTK
*) NULL
;
4040 GdkWindow
*window
= (GdkWindow
*) NULL
;
4042 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4044 window
= GetConnectWidget()->window
;
4049 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4053 wxWindow
*wxWindowBase::GetCapture()
4055 return (wxWindow
*)g_captureWindow
;
4058 bool wxWindowGTK::IsRetained() const
4063 void wxWindowGTK::BlockScrollEvent()
4065 wxASSERT(!m_blockScrollEvent
);
4066 m_blockScrollEvent
= true;
4069 void wxWindowGTK::UnblockScrollEvent()
4071 wxASSERT(m_blockScrollEvent
);
4072 m_blockScrollEvent
= false;
4075 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4078 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4079 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4083 m_hasScrolling
= true;
4087 // GtkRange requires upper > lower
4092 if (pos
> range
- thumbVisible
)
4093 pos
= range
- thumbVisible
;
4096 const int i
= orient
== wxVERTICAL
;
4097 GtkAdjustment
* adj
= m_scrollBar
[i
]->adjustment
;
4098 adj
->step_increment
= 1;
4099 adj
->page_increment
=
4100 adj
->page_size
= thumbVisible
;
4102 SetScrollPos(orient
, pos
);
4103 gtk_adjustment_changed(adj
);
4106 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4108 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4109 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4111 // This check is more than an optimization. Without it, the slider
4112 // will not move smoothly while tracking when using wxScrollHelper.
4113 if (GetScrollPos(orient
) != pos
)
4115 const int i
= orient
== wxVERTICAL
;
4116 GtkAdjustment
* adj
= m_scrollBar
[i
]->adjustment
;
4117 const int max
= int(adj
->upper
- adj
->page_size
);
4124 // If a "value_changed" signal emission is not already in progress
4125 if (!m_blockValueChanged
[i
])
4127 gtk_adjustment_value_changed(adj
);
4132 int wxWindowGTK::GetScrollThumb( int orient
) const
4134 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4135 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4137 const int i
= orient
== wxVERTICAL
;
4138 return int(m_scrollBar
[i
]->adjustment
->page_size
);
4141 int wxWindowGTK::GetScrollPos( int orient
) const
4143 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4144 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4146 const int i
= orient
== wxVERTICAL
;
4147 return int(m_scrollBar
[i
]->adjustment
->value
+ 0.5);
4150 int wxWindowGTK::GetScrollRange( int orient
) const
4152 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4153 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4155 const int i
= orient
== wxVERTICAL
;
4156 return int(m_scrollBar
[i
]->adjustment
->upper
);
4159 // Determine if increment is the same as +/-x, allowing for some small
4160 // difference due to possible inexactness in floating point arithmetic
4161 static inline bool IsScrollIncrement(double increment
, double x
)
4163 wxASSERT(increment
> 0);
4164 const double tolerance
= 1.0 / 1024;
4165 return fabs(increment
- fabs(x
)) < tolerance
;
4168 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4173 wxapp_install_idle_handler();
4175 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4177 const int barIndex
= range
== m_scrollBar
[1];
4178 GtkAdjustment
* adj
= range
->adjustment
;
4179 const int value
= int(adj
->value
+ 0.5);
4180 // save previous position
4181 const double oldPos
= m_scrollPos
[barIndex
];
4182 // update current position
4183 m_scrollPos
[barIndex
] = adj
->value
;
4184 // If event should be ignored, or integral position has not changed
4185 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4190 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4193 // Difference from last change event
4194 const double diff
= adj
->value
- oldPos
;
4195 const bool isDown
= diff
> 0;
4197 if (IsScrollIncrement(adj
->step_increment
, diff
))
4199 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4201 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4203 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4205 else if (m_mouseButtonDown
)
4207 // Assume track event
4208 m_isScrolling
= true;
4214 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4216 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4218 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4220 // No scrolling requested.
4221 if ((dx
== 0) && (dy
== 0)) return;
4223 m_clipPaintRegion
= true;
4225 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4227 m_clipPaintRegion
= false;
4230 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4232 //RN: Note that static controls usually have no border on gtk, so maybe
4233 //it makes sense to treat that as simply no border at the wx level
4235 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4237 GtkShadowType gtkstyle
;
4239 if(wxstyle
& wxBORDER_RAISED
)
4240 gtkstyle
= GTK_SHADOW_OUT
;
4241 else if (wxstyle
& wxBORDER_SUNKEN
)
4242 gtkstyle
= GTK_SHADOW_IN
;
4243 else if (wxstyle
& wxBORDER_DOUBLE
)
4244 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4246 gtkstyle
= GTK_SHADOW_IN
;
4248 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4253 void wxWindowGTK::SetWindowStyleFlag( long style
)
4255 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4256 wxWindowBase::SetWindowStyleFlag(style
);
4259 // Find the wxWindow at the current mouse position, also returning the mouse
4261 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4263 pt
= wxGetMousePosition();
4264 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4268 // Get the current mouse position.
4269 wxPoint
wxGetMousePosition()
4271 /* This crashes when used within wxHelpContext,
4272 so we have to use the X-specific implementation below.
4274 GdkModifierType *mask;
4275 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4277 return wxPoint(x, y);
4281 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4283 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4284 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4285 Window rootReturn
, childReturn
;
4286 int rootX
, rootY
, winX
, winY
;
4287 unsigned int maskReturn
;
4289 XQueryPointer (display
,
4293 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4294 return wxPoint(rootX
, rootY
);
4298 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4299 void wxAddGrab(wxWindow
* window
)
4301 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4304 void wxRemoveGrab(wxWindow
* window
)
4306 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4309 // ----------------------------------------------------------------------------
4311 // ----------------------------------------------------------------------------
4313 class wxWinModule
: public wxModule
4320 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4323 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4325 bool wxWinModule::OnInit()
4327 // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() );
4328 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4333 void wxWinModule::OnExit()
4336 g_object_unref (g_eraseGC
);