1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
25 #include "wx/dcclient.h"
27 #include "wx/dialog.h"
28 #include "wx/settings.h"
29 #include "wx/msgdlg.h"
30 #include "wx/textctrl.h"
31 #include "wx/toolbar.h"
32 #include "wx/combobox.h"
35 #include "wx/layout.h"
36 #include "wx/module.h"
38 #if wxUSE_DRAG_AND_DROP
43 #include "wx/tooltip.h"
50 #include "wx/statusbr.h"
51 #include "wx/fontutil.h"
54 #include "wx/thread.h"
60 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
61 #include <gtk/gtkversion.h>
62 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
63 #undef GTK_DISABLE_DEPRECATED
66 #include "wx/gtk/private.h"
67 #include <gdk/gdkprivate.h>
68 #include <gdk/gdkkeysyms.h>
72 #include <gtk/gtkprivate.h>
74 #include "wx/gtk/win_gtk.h"
76 #include <pango/pangox.h>
82 extern GtkContainerClass
*pizza_parent_class
;
84 //-----------------------------------------------------------------------------
85 // documentation on internals
86 //-----------------------------------------------------------------------------
89 I have been asked several times about writing some documentation about
90 the GTK port of wxWidgets, especially its internal structures. Obviously,
91 you cannot understand wxGTK without knowing a little about the GTK, but
92 some more information about what the wxWindow, which is the base class
93 for all other window classes, does seems required as well.
97 What does wxWindow do? It contains the common interface for the following
98 jobs of its descendants:
100 1) Define the rudimentary behaviour common to all window classes, such as
101 resizing, intercepting user input (so as to make it possible to use these
102 events for special purposes in a derived class), window names etc.
104 2) Provide the possibility to contain and manage children, if the derived
105 class is allowed to contain children, which holds true for those window
106 classes which do not display a native GTK widget. To name them, these
107 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
108 work classes are a special case and are handled a bit differently from
109 the rest. The same holds true for the wxNotebook class.
111 3) Provide the possibility to draw into a client area of a window. This,
112 too, only holds true for classes that do not display a native GTK widget
115 4) Provide the entire mechanism for scrolling widgets. This actual inter-
116 face for this is usually in wxScrolledWindow, but the GTK implementation
119 5) A multitude of helper or extra methods for special purposes, such as
120 Drag'n'Drop, managing validators etc.
122 6) Display a border (sunken, raised, simple or none).
124 Normally one might expect, that one wxWidgets window would always correspond
125 to one GTK widget. Under GTK, there is no such allround widget that has all
126 the functionality. Moreover, the GTK defines a client area as a different
127 widget from the actual widget you are handling. Last but not least some
128 special classes (e.g. wxFrame) handle different categories of widgets and
129 still have the possibility to draw something in the client area.
130 It was therefore required to write a special purpose GTK widget, that would
131 represent a client area in the sense of wxWidgets capable to do the jobs
132 2), 3) and 4). I have written this class and it resides in win_gtk.c of
135 All windows must have a widget, with which they interact with other under-
136 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
137 the wxWindow class has a member variable called m_widget which holds a
138 pointer to this widget. When the window class represents a GTK native widget,
139 this is (in most cases) the only GTK widget the class manages. E.g. the
140 wxStaticText class handles only a GtkLabel widget a pointer to which you
141 can find in m_widget (defined in wxWindow)
143 When the class has a client area for drawing into and for containing children
144 it has to handle the client area widget (of the type GtkPizza, defined in
145 win_gtk.c), but there could be any number of widgets, handled by a class
146 The common rule for all windows is only, that the widget that interacts with
147 the rest of GTK must be referenced in m_widget and all other widgets must be
148 children of this widget on the GTK level. The top-most widget, which also
149 represents the client area, must be in the m_wxwindow field and must be of
152 As I said, the window classes that display a GTK native widget only have
153 one widget, so in the case of e.g. the wxButton class m_widget holds a
154 pointer to a GtkButton widget. But windows with client areas (for drawing
155 and children) have a m_widget field that is a pointer to a GtkScrolled-
156 Window and a m_wxwindow field that is pointer to a GtkPizza and this
157 one is (in the GTK sense) a child of the GtkScrolledWindow.
159 If the m_wxwindow field is set, then all input to this widget is inter-
160 cepted and sent to the wxWidgets class. If not, all input to the widget
161 that gets pointed to by m_widget gets intercepted and sent to the class.
165 The design of scrolling in wxWidgets is markedly different from that offered
166 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
167 clicking on a scrollbar belonging to scrolled window will inevitably move
168 the window. In wxWidgets, the scrollbar will only emit an event, send this
169 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
170 which actually moves the window and its subchildren. Note that GtkPizza
171 memorizes how much it has been scrolled but that wxWidgets forgets this
172 so that the two coordinates systems have to be kept in synch. This is done
173 in various places using the pizza->xoffset and pizza->yoffset values.
177 Singularily the most broken code in GTK is the code that is supposed to
178 inform subwindows (child windows) about new positions. Very often, duplicate
179 events are sent without changes in size or position, equally often no
180 events are sent at all (All this is due to a bug in the GtkContainer code
181 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
182 GTK's own system and it simply waits for size events for toplevel windows
183 and then iterates down the respective size events to all window. This has
184 the disadvantage that windows might get size events before the GTK widget
185 actually has the reported size. This doesn't normally pose any problem, but
186 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
187 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
188 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
189 window that is used for OpenGL output really has that size (as reported by
194 If someone at some point of time feels the immense desire to have a look at,
195 change or attempt to optimise the Refresh() logic, this person will need an
196 intimate understanding of what "draw" and "expose" events are and what
197 they are used for, in particular when used in connection with GTK's
198 own windowless widgets. Beware.
202 Cursors, too, have been a constant source of pleasure. The main difficulty
203 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
204 for the parent. To prevent this from doing too much harm, I use idle time
205 to set the cursor over and over again, starting from the toplevel windows
206 and ending with the youngest generation (speaking of parent and child windows).
207 Also don't forget that cursors (like much else) are connected to GdkWindows,
208 not GtkWidgets and that the "window" field of a GtkWidget might very well
209 point to the GdkWindow of the parent widget (-> "window-less widget") and
210 that the two obviously have very different meanings.
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 extern bool g_blockEventsOnDrag
;
219 extern bool g_blockEventsOnScroll
;
220 extern wxCursor g_globalCursor
;
222 static GdkGC
*g_eraseGC
= NULL
;
224 // mouse capture state: the window which has it and if the mouse is currently
226 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
227 static bool g_captureWindowHasMouse
= false;
229 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
231 // the last window which had the focus - this is normally never NULL (except
232 // if we never had focus at all) as even when g_focusWindow is NULL it still
233 // keeps its previous value
234 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
236 // If a window get the focus set but has not been realized
237 // yet, defer setting the focus to idle time.
238 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
240 extern bool g_mainThreadLocked
;
242 //-----------------------------------------------------------------------------
244 //-----------------------------------------------------------------------------
249 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
251 # define DEBUG_MAIN_THREAD
254 #define DEBUG_MAIN_THREAD
257 // the trace mask used for the focus debugging messages
258 #define TRACE_FOCUS _T("focus")
260 //-----------------------------------------------------------------------------
261 // missing gdk functions
262 //-----------------------------------------------------------------------------
265 gdk_window_warp_pointer (GdkWindow
*window
,
270 window
= gdk_get_default_root_window();
272 if (!GDK_WINDOW_DESTROYED(window
))
274 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
275 None
, /* not source window -> move from anywhere */
276 GDK_WINDOW_XID(window
), /* dest window */
277 0, 0, 0, 0, /* not source window -> move from anywhere */
282 //-----------------------------------------------------------------------------
283 // local code (see below)
284 //-----------------------------------------------------------------------------
286 // returns the child of win which currently has focus or NULL if not found
288 // Note: can't be static, needed by textctrl.cpp.
289 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
291 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
293 return (wxWindow
*)NULL
;
295 if ( winFocus
== win
)
296 return (wxWindow
*)win
;
298 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
300 node
= node
->GetNext() )
302 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
307 return (wxWindow
*)NULL
;
310 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
)
312 GtkScrolledWindow
* scroll_window
= GTK_SCROLLED_WINDOW(widget
);
313 GtkScrolledWindowClass
* scroll_class
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
));
314 GtkRequisition scroll_req
;
317 if (scroll_window
->vscrollbar_visible
)
319 scroll_req
.width
= 2;
320 scroll_req
.height
= 2;
321 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
322 (scroll_window
->vscrollbar
, &scroll_req
);
323 w
= scroll_req
.width
+
324 scroll_class
->scrollbar_spacing
;
328 if (scroll_window
->hscrollbar_visible
)
330 scroll_req
.width
= 2;
331 scroll_req
.height
= 2;
332 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
333 (scroll_window
->hscrollbar
, &scroll_req
);
334 h
= scroll_req
.height
+
335 scroll_class
->scrollbar_spacing
;
339 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
341 // wxUniversal widgets draw the borders and scrollbars themselves
342 #ifndef __WXUNIVERSAL__
349 if (win
->m_hasScrolling
)
351 GetScrollbarWidth(widget
, dw
, dh
);
356 if (GTK_WIDGET_NO_WINDOW (widget
))
358 dx
+= widget
->allocation
.x
;
359 dy
+= widget
->allocation
.y
;
362 if (win
->HasFlag(wxRAISED_BORDER
))
364 gtk_paint_shadow (widget
->style
,
368 NULL
, NULL
, NULL
, // FIXME: No clipping?
370 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
374 if (win
->HasFlag(wxSUNKEN_BORDER
))
376 gtk_paint_shadow (widget
->style
,
380 NULL
, NULL
, NULL
, // FIXME: No clipping?
382 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
386 if (win
->HasFlag(wxSIMPLE_BORDER
))
389 gc
= gdk_gc_new( widget
->window
);
390 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
391 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
393 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
397 #endif // __WXUNIVERSAL__
400 //-----------------------------------------------------------------------------
401 // "expose_event" of m_widget
402 //-----------------------------------------------------------------------------
406 gtk_window_own_expose_callback( GtkWidget
*widget
,
407 GdkEventExpose
*gdk_event
,
410 if (gdk_event
->count
> 0) return FALSE
;
412 draw_frame( widget
, win
);
414 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
420 //-----------------------------------------------------------------------------
421 // "size_request" of m_widget
422 //-----------------------------------------------------------------------------
424 // make it extern because wxStaticText needs to disconnect this one
426 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
427 GtkRequisition
*requisition
,
431 win
->GetSize( &w
, &h
);
437 requisition
->height
= h
;
438 requisition
->width
= w
;
444 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
445 GtkRequisition
*requisition
,
448 // This callback is actually hooked into the text entry
449 // of the combo box, not the GtkHBox.
452 win
->GetSize( &w
, &h
);
458 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
460 GtkRequisition entry_req
;
462 entry_req
.height
= 2;
463 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
464 (gcombo
->button
, &entry_req
);
466 requisition
->width
= w
- entry_req
.width
;
467 requisition
->height
= entry_req
.height
;
471 //-----------------------------------------------------------------------------
472 // "expose_event" of m_wxwindow
473 //-----------------------------------------------------------------------------
477 gtk_window_expose_callback( GtkWidget
*widget
,
478 GdkEventExpose
*gdk_event
,
484 wxapp_install_idle_handler();
486 // This callback gets called in drawing-idle time under
487 // GTK 2.0, so we don't need to defer anything to idle
490 GtkPizza
*pizza
= GTK_PIZZA( widget
);
491 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
496 wxPrintf( wxT("OnExpose from ") );
497 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
498 wxPrintf( win
->GetClassInfo()->GetClassName() );
499 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
500 (int)gdk_event
->area
.y
,
501 (int)gdk_event
->area
.width
,
502 (int)gdk_event
->area
.height
);
507 win
->m_wxwindow
->style
,
511 (GdkRectangle
*) NULL
,
513 (char *)"button", // const_cast
518 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
520 win
->GtkSendPaintEvents();
523 // Let parent window draw window-less widgets
524 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
530 //-----------------------------------------------------------------------------
531 // "key_press_event" from any window
532 //-----------------------------------------------------------------------------
534 // set WXTRACE to this to see the key event codes on the console
535 #define TRACE_KEYS _T("keyevent")
537 // translates an X key symbol to WXK_XXX value
539 // if isChar is true it means that the value returned will be used for EVT_CHAR
540 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
541 // for example, while if it is false it means that the value is going to be
542 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
544 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
550 // Shift, Control and Alt don't generate the CHAR events at all
553 key_code
= isChar
? 0 : WXK_SHIFT
;
557 key_code
= isChar
? 0 : WXK_CONTROL
;
565 key_code
= isChar
? 0 : WXK_ALT
;
568 // neither do the toggle modifies
569 case GDK_Scroll_Lock
:
570 key_code
= isChar
? 0 : WXK_SCROLL
;
574 key_code
= isChar
? 0 : WXK_CAPITAL
;
578 key_code
= isChar
? 0 : WXK_NUMLOCK
;
582 // various other special keys
595 case GDK_ISO_Left_Tab
:
602 key_code
= WXK_RETURN
;
606 key_code
= WXK_CLEAR
;
610 key_code
= WXK_PAUSE
;
614 key_code
= WXK_SELECT
;
618 key_code
= WXK_PRINT
;
622 key_code
= WXK_EXECUTE
;
626 key_code
= WXK_ESCAPE
;
629 // cursor and other extended keyboard keys
631 key_code
= WXK_DELETE
;
647 key_code
= WXK_RIGHT
;
654 case GDK_Prior
: // == GDK_Page_Up
655 key_code
= WXK_PAGEUP
;
658 case GDK_Next
: // == GDK_Page_Down
659 key_code
= WXK_PAGEDOWN
;
671 key_code
= WXK_INSERT
;
686 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
690 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
694 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
698 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
702 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
706 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
710 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
714 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
718 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
722 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
726 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
730 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
734 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
737 case GDK_KP_Prior
: // == GDK_KP_Page_Up
738 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
741 case GDK_KP_Next
: // == GDK_KP_Page_Down
742 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
746 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
750 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
754 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
758 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
762 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
765 case GDK_KP_Multiply
:
766 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
770 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
773 case GDK_KP_Separator
:
774 // FIXME: what is this?
775 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
778 case GDK_KP_Subtract
:
779 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
783 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
787 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
804 key_code
= WXK_F1
+ keysym
- GDK_F1
;
814 static inline bool wxIsAsciiKeysym(KeySym ks
)
819 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
821 GdkEventKey
*gdk_event
)
825 GdkModifierType state
;
826 if (gdk_event
->window
)
827 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
829 event
.SetTimestamp( gdk_event
->time
);
830 event
.SetId(win
->GetId());
831 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
832 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
833 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
834 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
835 event
.m_scanCode
= gdk_event
->keyval
;
836 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
837 event
.m_rawFlags
= 0;
839 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
841 wxGetMousePosition( &x
, &y
);
842 win
->ScreenToClient( &x
, &y
);
845 event
.SetEventObject( win
);
850 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
852 GdkEventKey
*gdk_event
)
854 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
855 // but only event->keyval which is quite useless to us, so remember
856 // the last character from GDK_KEY_PRESS and reuse it as last resort
858 // NB: should be MT-safe as we're always called from the main thread only
863 } s_lastKeyPress
= { 0, 0 };
865 KeySym keysym
= gdk_event
->keyval
;
867 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
868 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
872 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
876 // do we have the translation or is it a plain ASCII character?
877 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
879 // we should use keysym if it is ASCII as X does some translations
880 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
881 // which we don't want here (but which we do use for OnChar())
882 if ( !wxIsAsciiKeysym(keysym
) )
884 keysym
= (KeySym
)gdk_event
->string
[0];
887 // we want to always get the same key code when the same key is
888 // pressed regardless of the state of the modifiers, i.e. on a
889 // standard US keyboard pressing '5' or '%' ('5' key with
890 // Shift) should result in the same key code in OnKeyDown():
891 // '5' (although OnChar() will get either '5' or '%').
893 // to do it we first translate keysym to keycode (== scan code)
894 // and then back but always using the lower register
895 Display
*dpy
= (Display
*)wxGetDisplay();
896 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
898 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
900 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
902 // use the normalized, i.e. lower register, keysym if we've
904 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
906 // as explained above, we want to have lower register key codes
907 // normally but for the letter keys we want to have the upper ones
909 // NB: don't use XConvertCase() here, we want to do it for letters
911 key_code
= toupper(key_code
);
913 else // non ASCII key, what to do?
915 // by default, ignore it
918 // but if we have cached information from the last KEY_PRESS
919 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
922 if ( keysym
== s_lastKeyPress
.keysym
)
924 key_code
= s_lastKeyPress
.keycode
;
929 if ( gdk_event
->type
== GDK_KEY_PRESS
)
931 // remember it to be reused for KEY_UP event later
932 s_lastKeyPress
.keysym
= keysym
;
933 s_lastKeyPress
.keycode
= key_code
;
937 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
939 // sending unknown key events doesn't really make sense
943 // now fill all the other fields
944 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
946 event
.m_keyCode
= key_code
;
948 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
950 event
.m_uniChar
= key_code
;
960 GtkIMContext
*context
;
961 GdkEventKey
*lastKeyEvent
;
965 context
= gtk_im_multicontext_new();
970 g_object_unref (context
);
976 gtk_window_key_press_callback( GtkWidget
*widget
,
977 GdkEventKey
*gdk_event
,
983 wxapp_install_idle_handler();
987 if (g_blockEventsOnDrag
)
991 wxKeyEvent
event( wxEVT_KEY_DOWN
);
993 bool return_after_IM
= false;
995 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
997 // Emit KEY_DOWN event
998 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1002 // Return after IM processing as we cannot do
1003 // anything with it anyhow.
1004 return_after_IM
= true;
1007 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1008 // When we get a key_press event here, it could be originate
1009 // from the current widget or its child widgets. However, only the widget
1010 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1011 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1012 // originated from its child widgets and shouldn't be passed to IM context.
1013 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1014 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1015 // widgets has both IM context and input focus, the event should be filtered
1016 // by gtk_im_context_filter_keypress().
1017 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1018 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1020 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1021 // docs, if IM filter returns true, no further processing should be done.
1022 // we should send the key_down event anyway.
1023 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1024 win
->m_imData
->lastKeyEvent
= NULL
;
1025 if (intercepted_by_IM
)
1027 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1032 if (return_after_IM
)
1038 wxWindowGTK
*ancestor
= win
;
1041 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1044 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1045 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1048 if (ancestor
->IsTopLevel())
1050 ancestor
= ancestor
->GetParent();
1053 #endif // wxUSE_ACCEL
1055 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1056 // will only be sent if it is not in an accelerator table.
1060 KeySym keysym
= gdk_event
->keyval
;
1061 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1062 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1065 if ( wxIsAsciiKeysym(keysym
) )
1068 key_code
= (unsigned char)keysym
;
1070 // gdk_event->string is actually deprecated
1071 else if ( gdk_event
->length
== 1 )
1073 key_code
= (unsigned char)gdk_event
->string
[0];
1079 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1081 event
.m_keyCode
= key_code
;
1083 // To conform to the docs we need to translate Ctrl-alpha
1084 // characters to values in the range 1-26.
1085 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1087 event
.m_keyCode
= key_code
- 'a' + 1;
1089 event
.m_uniChar
= event
.m_keyCode
;
1093 // Implement OnCharHook by checking ancestor top level windows
1094 wxWindow
*parent
= win
;
1095 while (parent
&& !parent
->IsTopLevel())
1096 parent
= parent
->GetParent();
1099 event
.SetEventType( wxEVT_CHAR_HOOK
);
1100 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1105 event
.SetEventType(wxEVT_CHAR
);
1106 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1115 // win is a control: tab can be propagated up
1117 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1118 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1119 // have this style, yet choose not to process this particular TAB in which
1120 // case TAB must still work as a navigational character
1121 // JS: enabling again to make consistent with other platforms
1122 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1123 // navigation behaviour)
1125 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1127 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1129 wxNavigationKeyEvent new_event
;
1130 new_event
.SetEventObject( win
->GetParent() );
1131 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1132 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1133 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1134 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1135 new_event
.SetCurrentFocus( win
);
1136 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1139 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1141 (gdk_event
->keyval
== GDK_Escape
) )
1143 // however only do it if we have a Cancel button in the dialog,
1144 // otherwise the user code may get confused by the events from a
1145 // non-existing button and, worse, a wxButton might get button event
1146 // from another button which is not really expected
1147 wxWindow
*winForCancel
= win
,
1149 while ( winForCancel
)
1151 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1154 // found a cancel button
1158 if ( winForCancel
->IsTopLevel() )
1160 // no need to look further
1164 // maybe our parent has a cancel button?
1165 winForCancel
= winForCancel
->GetParent();
1170 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1171 eventClick
.SetEventObject(btnCancel
);
1172 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1178 g_signal_stop_emission_by_name (widget
, "key_press_event");
1188 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1192 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1194 // take modifiers, cursor position, timestamp etc. from the last
1195 // key_press_event that was fed into Input Method:
1196 if (window
->m_imData
->lastKeyEvent
)
1198 wxFillOtherKeyEventFields(event
,
1199 window
, window
->m_imData
->lastKeyEvent
);
1202 const wxWxCharBuffer
data(wxGTK_CONV_BACK(str
));
1208 // Implement OnCharHook by checking ancestor top level windows
1209 wxWindow
*parent
= window
;
1210 while (parent
&& !parent
->IsTopLevel())
1211 parent
= parent
->GetParent();
1213 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1216 event
.m_uniChar
= *pstr
;
1217 // Backward compatible for ISO-8859-1
1218 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1219 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1221 event
.m_keyCode
= *pstr
;
1222 #endif // wxUSE_UNICODE
1224 // To conform to the docs we need to translate Ctrl-alpha
1225 // characters to values in the range 1-26.
1226 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1228 event
.m_keyCode
= *pstr
- 'a' + 1;
1230 event
.m_uniChar
= event
.m_keyCode
;
1236 event
.SetEventType( wxEVT_CHAR_HOOK
);
1237 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1242 event
.SetEventType(wxEVT_CHAR
);
1243 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1250 //-----------------------------------------------------------------------------
1251 // "key_release_event" from any window
1252 //-----------------------------------------------------------------------------
1256 gtk_window_key_release_callback( GtkWidget
*widget
,
1257 GdkEventKey
*gdk_event
,
1263 wxapp_install_idle_handler();
1268 if (g_blockEventsOnDrag
)
1271 wxKeyEvent
event( wxEVT_KEY_UP
);
1272 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1274 // unknown key pressed, ignore (the event would be useless anyhow)
1278 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1281 g_signal_stop_emission_by_name (widget
, "key_release_event");
1286 // ============================================================================
1288 // ============================================================================
1290 // ----------------------------------------------------------------------------
1291 // mouse event processing helpers
1292 // ----------------------------------------------------------------------------
1294 // init wxMouseEvent with the info from GdkEventXXX struct
1295 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1296 wxMouseEvent
& event
,
1299 event
.SetTimestamp( gdk_event
->time
);
1300 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1301 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1302 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1303 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1304 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1305 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1306 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1307 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1309 event
.m_linesPerAction
= 3;
1310 event
.m_wheelDelta
= 120;
1311 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1312 event
.m_wheelRotation
= 120;
1313 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1314 event
.m_wheelRotation
= -120;
1317 wxPoint pt
= win
->GetClientAreaOrigin();
1318 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1319 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1321 event
.SetEventObject( win
);
1322 event
.SetId( win
->GetId() );
1323 event
.SetTimestamp( gdk_event
->time
);
1326 static void AdjustEventButtonState(wxMouseEvent
& event
)
1328 // GDK reports the old state of the button for a button press event, but
1329 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1330 // for a LEFT_DOWN event, not FALSE, so we will invert
1331 // left/right/middleDown for the corresponding click events
1333 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1334 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1335 (event
.GetEventType() == wxEVT_LEFT_UP
))
1337 event
.m_leftDown
= !event
.m_leftDown
;
1341 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1342 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1343 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1345 event
.m_middleDown
= !event
.m_middleDown
;
1349 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1350 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1351 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1353 event
.m_rightDown
= !event
.m_rightDown
;
1358 // find the window to send the mouse event too
1360 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1365 if (win
->m_wxwindow
)
1367 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1368 xx
+= pizza
->xoffset
;
1369 yy
+= pizza
->yoffset
;
1372 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1375 wxWindowGTK
*child
= node
->GetData();
1377 node
= node
->GetNext();
1378 if (!child
->IsShown())
1381 if (child
->IsTransparentForMouse())
1383 // wxStaticBox is transparent in the box itself
1384 int xx1
= child
->m_x
;
1385 int yy1
= child
->m_y
;
1386 int xx2
= child
->m_x
+ child
->m_width
;
1387 int yy2
= child
->m_y
+ child
->m_height
;
1390 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1392 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1394 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1396 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1407 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1408 (child
->m_x
<= xx
) &&
1409 (child
->m_y
<= yy
) &&
1410 (child
->m_x
+child
->m_width
>= xx
) &&
1411 (child
->m_y
+child
->m_height
>= yy
))
1424 //-----------------------------------------------------------------------------
1425 // "button_press_event"
1426 //-----------------------------------------------------------------------------
1430 gtk_window_button_press_callback( GtkWidget
*widget
,
1431 GdkEventButton
*gdk_event
,
1437 wxapp_install_idle_handler();
1440 wxPrintf( wxT("1) OnButtonPress from ") );
1441 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1442 wxPrintf( win->GetClassInfo()->GetClassName() );
1443 wxPrintf( wxT(".\n") );
1445 if (!win
->m_hasVMT
) return FALSE
;
1446 if (g_blockEventsOnDrag
) return TRUE
;
1447 if (g_blockEventsOnScroll
) return TRUE
;
1449 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1451 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1453 gtk_widget_grab_focus( win
->m_wxwindow
);
1455 wxPrintf( wxT("GrabFocus from ") );
1456 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1457 wxPrintf( win->GetClassInfo()->GetClassName() );
1458 wxPrintf( wxT(".\n") );
1462 // GDK sends surplus button down events
1463 // before a double click event. We
1464 // need to filter these out.
1465 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1467 GdkEvent
*peek_event
= gdk_event_peek();
1470 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1471 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1473 gdk_event_free( peek_event
);
1478 gdk_event_free( peek_event
);
1483 wxEventType event_type
= wxEVT_NULL
;
1485 // GdkDisplay is a GTK+ 2.2.0 thing
1486 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1487 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1488 !gtk_check_version(2,2,0) &&
1489 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1491 // Reset GDK internal timestamp variables in order to disable GDK
1492 // triple click events. GDK will then next time believe no button has
1493 // been clicked just before, and send a normal button click event.
1494 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1495 display
->button_click_time
[1] = 0;
1496 display
->button_click_time
[0] = 0;
1500 if (gdk_event
->button
== 1)
1502 // note that GDK generates triple click events which are not supported
1503 // by wxWidgets but still have to be passed to the app as otherwise
1504 // clicks would simply go missing
1505 switch (gdk_event
->type
)
1507 // we shouldn't get triple clicks at all for GTK2 because we
1508 // suppress them artificially using the code above but we still
1509 // should map them to something for GTK1 and not just ignore them
1510 // as this would lose clicks
1511 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1512 case GDK_BUTTON_PRESS
:
1513 event_type
= wxEVT_LEFT_DOWN
;
1516 case GDK_2BUTTON_PRESS
:
1517 event_type
= wxEVT_LEFT_DCLICK
;
1521 // just to silence gcc warnings
1525 else if (gdk_event
->button
== 2)
1527 switch (gdk_event
->type
)
1529 case GDK_3BUTTON_PRESS
:
1530 case GDK_BUTTON_PRESS
:
1531 event_type
= wxEVT_MIDDLE_DOWN
;
1534 case GDK_2BUTTON_PRESS
:
1535 event_type
= wxEVT_MIDDLE_DCLICK
;
1542 else if (gdk_event
->button
== 3)
1544 switch (gdk_event
->type
)
1546 case GDK_3BUTTON_PRESS
:
1547 case GDK_BUTTON_PRESS
:
1548 event_type
= wxEVT_RIGHT_DOWN
;
1551 case GDK_2BUTTON_PRESS
:
1552 event_type
= wxEVT_RIGHT_DCLICK
;
1559 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1561 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1563 event_type
= wxEVT_MOUSEWHEEL
;
1567 if ( event_type
== wxEVT_NULL
)
1569 // unknown mouse button or click type
1573 wxMouseEvent
event( event_type
);
1574 InitMouseEvent( win
, event
, gdk_event
);
1576 AdjustEventButtonState(event
);
1578 // wxListBox actually gets mouse events from the item, so we need to give it
1579 // a chance to correct this
1580 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1582 // find the correct window to send the event to: it may be a different one
1583 // from the one which got it at GTK+ level because some controls don't have
1584 // their own X window and thus cannot get any events.
1585 if ( !g_captureWindow
)
1586 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1588 // reset the event object and id in case win changed.
1589 event
.SetEventObject( win
);
1590 event
.SetId( win
->GetId() );
1592 if (win
->GetEventHandler()->ProcessEvent( event
))
1594 g_signal_stop_emission_by_name (widget
, "button_press_event");
1598 if (event_type
== wxEVT_RIGHT_DOWN
)
1600 // generate a "context menu" event: this is similar to right mouse
1601 // click under many GUIs except that it is generated differently
1602 // (right up under MSW, ctrl-click under Mac, right down here) and
1604 // (a) it's a command event and so is propagated to the parent
1605 // (b) under some ports it can be generated from kbd too
1606 // (c) it uses screen coords (because of (a))
1607 wxContextMenuEvent
evtCtx(
1610 win
->ClientToScreen(event
.GetPosition()));
1611 evtCtx
.SetEventObject(win
);
1612 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1619 //-----------------------------------------------------------------------------
1620 // "button_release_event"
1621 //-----------------------------------------------------------------------------
1625 gtk_window_button_release_callback( GtkWidget
*widget
,
1626 GdkEventButton
*gdk_event
,
1632 wxapp_install_idle_handler();
1634 if (!win
->m_hasVMT
) return FALSE
;
1635 if (g_blockEventsOnDrag
) return FALSE
;
1636 if (g_blockEventsOnScroll
) return FALSE
;
1638 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1640 wxEventType event_type
= wxEVT_NULL
;
1642 switch (gdk_event
->button
)
1645 event_type
= wxEVT_LEFT_UP
;
1649 event_type
= wxEVT_MIDDLE_UP
;
1653 event_type
= wxEVT_RIGHT_UP
;
1657 // unknwon button, don't process
1661 wxMouseEvent
event( event_type
);
1662 InitMouseEvent( win
, event
, gdk_event
);
1664 AdjustEventButtonState(event
);
1666 // same wxListBox hack as above
1667 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1669 if ( !g_captureWindow
)
1670 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1672 // reset the event object and id in case win changed.
1673 event
.SetEventObject( win
);
1674 event
.SetId( win
->GetId() );
1676 if (win
->GetEventHandler()->ProcessEvent( event
))
1678 g_signal_stop_emission_by_name (widget
, "button_release_event");
1686 //-----------------------------------------------------------------------------
1687 // "motion_notify_event"
1688 //-----------------------------------------------------------------------------
1692 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1693 GdkEventMotion
*gdk_event
,
1699 wxapp_install_idle_handler();
1701 if (!win
->m_hasVMT
) return FALSE
;
1702 if (g_blockEventsOnDrag
) return FALSE
;
1703 if (g_blockEventsOnScroll
) return FALSE
;
1705 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1707 if (gdk_event
->is_hint
)
1711 GdkModifierType state
;
1712 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1718 printf( "OnMotion from " );
1719 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1720 printf( win->GetClassInfo()->GetClassName() );
1724 wxMouseEvent
event( wxEVT_MOTION
);
1725 InitMouseEvent(win
, event
, gdk_event
);
1727 if ( g_captureWindow
)
1729 // synthetize a mouse enter or leave event if needed
1730 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1731 // This seems to be necessary and actually been added to
1732 // GDK itself in version 2.0.X
1735 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1736 if ( hasMouse
!= g_captureWindowHasMouse
)
1738 // the mouse changed window
1739 g_captureWindowHasMouse
= hasMouse
;
1741 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1742 : wxEVT_LEAVE_WINDOW
);
1743 InitMouseEvent(win
, eventM
, gdk_event
);
1744 eventM
.SetEventObject(win
);
1745 win
->GetEventHandler()->ProcessEvent(eventM
);
1750 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1752 // reset the event object and id in case win changed.
1753 event
.SetEventObject( win
);
1754 event
.SetId( win
->GetId() );
1757 if ( !g_captureWindow
)
1759 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1760 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1762 // Rewrite cursor handling here (away from idle).
1766 if (win
->GetEventHandler()->ProcessEvent( event
))
1768 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1776 //-----------------------------------------------------------------------------
1777 // "scroll_event", (mouse wheel event)
1778 //-----------------------------------------------------------------------------
1782 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1787 wxapp_install_idle_handler();
1789 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1790 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1795 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1796 // Can't use InitMouse macro because scroll events don't have button
1797 event
.SetTimestamp( gdk_event
->time
);
1798 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1799 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1800 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1801 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1802 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1803 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1804 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1805 event
.m_linesPerAction
= 3;
1806 event
.m_wheelDelta
= 120;
1807 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1808 event
.m_wheelRotation
= 120;
1810 event
.m_wheelRotation
= -120;
1812 wxPoint pt
= win
->GetClientAreaOrigin();
1813 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1814 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1816 event
.SetEventObject( win
);
1817 event
.SetId( win
->GetId() );
1818 event
.SetTimestamp( gdk_event
->time
);
1820 return win
->GetEventHandler()->ProcessEvent(event
);
1824 //-----------------------------------------------------------------------------
1826 //-----------------------------------------------------------------------------
1828 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1830 wxContextMenuEvent
event(
1834 event
.SetEventObject(win
);
1835 return win
->GetEventHandler()->ProcessEvent(event
);
1839 //-----------------------------------------------------------------------------
1841 //-----------------------------------------------------------------------------
1843 // send the wxChildFocusEvent and wxFocusEvent, common code of
1844 // gtk_window_focus_in_callback() and SetFocus()
1845 static bool DoSendFocusEvents(wxWindow
*win
)
1847 // Notify the parent keeping track of focus for the kbd navigation
1848 // purposes that we got it.
1849 wxChildFocusEvent
eventChildFocus(win
);
1850 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1852 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1853 eventFocus
.SetEventObject(win
);
1855 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1860 gtk_window_focus_in_callback( GtkWidget
*widget
,
1861 GdkEventFocus
*WXUNUSED(event
),
1867 wxapp_install_idle_handler();
1870 gtk_im_context_focus_in(win
->m_imData
->context
);
1873 g_focusWindow
= win
;
1875 wxLogTrace(TRACE_FOCUS
,
1876 _T("%s: focus in"), win
->GetName().c_str());
1880 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1884 // caret needs to be informed about focus change
1885 wxCaret
*caret
= win
->GetCaret();
1888 caret
->OnSetFocus();
1890 #endif // wxUSE_CARET
1892 gboolean ret
= FALSE
;
1894 // does the window itself think that it has the focus?
1895 if ( !win
->m_hasFocus
)
1897 // not yet, notify it
1898 win
->m_hasFocus
= true;
1900 (void)DoSendFocusEvents(win
);
1905 // Disable default focus handling for custom windows
1906 // since the default GTK+ handler issues a repaint
1907 if (win
->m_wxwindow
)
1914 //-----------------------------------------------------------------------------
1915 // "focus_out_event"
1916 //-----------------------------------------------------------------------------
1920 gtk_window_focus_out_callback( GtkWidget
*widget
,
1921 GdkEventFocus
*gdk_event
,
1927 wxapp_install_idle_handler();
1930 gtk_im_context_focus_out(win
->m_imData
->context
);
1932 wxLogTrace( TRACE_FOCUS
,
1933 _T("%s: focus out"), win
->GetName().c_str() );
1936 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1940 g_focusWindow
= (wxWindowGTK
*)NULL
;
1948 // caret needs to be informed about focus change
1949 wxCaret
*caret
= win
->GetCaret();
1952 caret
->OnKillFocus();
1954 #endif // wxUSE_CARET
1956 gboolean ret
= FALSE
;
1958 // don't send the window a kill focus event if it thinks that it doesn't
1959 // have focus already
1960 if ( win
->m_hasFocus
)
1962 win
->m_hasFocus
= false;
1964 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1965 event
.SetEventObject( win
);
1967 (void)win
->GetEventHandler()->ProcessEvent( event
);
1972 // Disable default focus handling for custom windows
1973 // since the default GTK+ handler issues a repaint
1974 if (win
->m_wxwindow
)
1981 //-----------------------------------------------------------------------------
1982 // "enter_notify_event"
1983 //-----------------------------------------------------------------------------
1987 gtk_window_enter_callback( GtkWidget
*widget
,
1988 GdkEventCrossing
*gdk_event
,
1994 wxapp_install_idle_handler();
1996 if (!win
->m_hasVMT
) return FALSE
;
1997 if (g_blockEventsOnDrag
) return FALSE
;
1999 // Event was emitted after a grab
2000 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2002 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2006 GdkModifierType state
= (GdkModifierType
)0;
2008 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2010 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2011 InitMouseEvent(win
, event
, gdk_event
);
2012 wxPoint pt
= win
->GetClientAreaOrigin();
2013 event
.m_x
= x
+ pt
.x
;
2014 event
.m_y
= y
+ pt
.y
;
2016 if ( !g_captureWindow
)
2018 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2019 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2021 // Rewrite cursor handling here (away from idle).
2025 if (win
->GetEventHandler()->ProcessEvent( event
))
2027 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2035 //-----------------------------------------------------------------------------
2036 // "leave_notify_event"
2037 //-----------------------------------------------------------------------------
2041 gtk_window_leave_callback( GtkWidget
*widget
,
2042 GdkEventCrossing
*gdk_event
,
2048 wxapp_install_idle_handler();
2050 if (!win
->m_hasVMT
) return FALSE
;
2051 if (g_blockEventsOnDrag
) return FALSE
;
2053 // Event was emitted after an ungrab
2054 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2056 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2058 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2059 event
.SetTimestamp( gdk_event
->time
);
2060 event
.SetEventObject( win
);
2064 GdkModifierType state
= (GdkModifierType
)0;
2066 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2068 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2069 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2070 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2071 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2072 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2073 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2074 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2076 wxPoint pt
= win
->GetClientAreaOrigin();
2077 event
.m_x
= x
+ pt
.x
;
2078 event
.m_y
= y
+ pt
.y
;
2080 if (win
->GetEventHandler()->ProcessEvent( event
))
2082 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2090 //-----------------------------------------------------------------------------
2091 // "value_changed" from scrollbar
2092 //-----------------------------------------------------------------------------
2096 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
2098 wxEventType eventType
= win
->GetScrollEventType(range
);
2099 if (eventType
!= wxEVT_NULL
)
2101 // Convert scroll event type to scrollwin event type
2102 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
2103 const int orient
= range
== win
->m_scrollBar
[0] ? wxHORIZONTAL
: wxVERTICAL
;
2104 const int i
= orient
== wxVERTICAL
;
2105 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
2106 event
.SetEventObject(win
);
2107 win
->m_blockValueChanged
[i
] = true;
2108 win
->GetEventHandler()->ProcessEvent(event
);
2109 win
->m_blockValueChanged
[i
] = false;
2114 //-----------------------------------------------------------------------------
2115 // "button_press_event" from scrollbar
2116 //-----------------------------------------------------------------------------
2120 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
2125 wxapp_install_idle_handler();
2127 g_blockEventsOnScroll
= true;
2128 win
->m_mouseButtonDown
= true;
2134 //-----------------------------------------------------------------------------
2135 // "button_release_event" from scrollbar
2136 //-----------------------------------------------------------------------------
2140 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
2144 g_blockEventsOnScroll
= false;
2145 win
->m_mouseButtonDown
= false;
2146 // If thumb tracking
2147 if (win
->m_isScrolling
)
2149 win
->m_isScrolling
= false;
2150 const int orient
= range
== win
->m_scrollBar
[0] ? wxHORIZONTAL
: wxVERTICAL
;
2151 wxScrollWinEvent
event(wxEVT_SCROLLWIN_THUMBRELEASE
, win
->GetScrollPos(orient
), orient
);
2152 event
.SetEventObject(win
);
2153 // To allow setting scroll position from event handler, sending event must
2154 // be deferred until after the GtkRange handler for this signal has run
2155 win
->GetEventHandler()->AddPendingEvent(event
);
2162 // ----------------------------------------------------------------------------
2163 // this wxWindowBase function is implemented here (in platform-specific file)
2164 // because it is static and so couldn't be made virtual
2165 // ----------------------------------------------------------------------------
2167 wxWindow
*wxWindowBase::DoFindFocus()
2169 // the cast is necessary when we compile in wxUniversal mode
2170 return (wxWindow
*)g_focusWindow
;
2173 //-----------------------------------------------------------------------------
2174 // "realize" from m_widget
2175 //-----------------------------------------------------------------------------
2177 /* We cannot set colours and fonts before the widget has
2178 been realized, so we do this directly after realization. */
2182 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2187 wxapp_install_idle_handler();
2191 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2192 gtk_im_context_set_client_window( win
->m_imData
->context
,
2193 pizza
->bin_window
);
2196 wxWindowCreateEvent
event( win
);
2197 event
.SetEventObject( win
);
2198 win
->GetEventHandler()->ProcessEvent( event
);
2202 //-----------------------------------------------------------------------------
2204 //-----------------------------------------------------------------------------
2208 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2209 GtkAllocation
*WXUNUSED(alloc
),
2213 wxapp_install_idle_handler();
2215 int client_width
= 0;
2216 int client_height
= 0;
2217 win
->GetClientSize( &client_width
, &client_height
);
2218 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2221 win
->m_oldClientWidth
= client_width
;
2222 win
->m_oldClientHeight
= client_height
;
2224 if (!win
->m_nativeSizeEvent
)
2226 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2227 event
.SetEventObject( win
);
2228 win
->GetEventHandler()->ProcessEvent( event
);
2235 #define WXUNUSED_UNLESS_XIM(param) param
2237 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2240 /* Resize XIM window */
2244 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2245 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2246 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2249 wxapp_install_idle_handler();
2255 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2259 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2260 win
->m_icattr
->preedit_area
.width
= width
;
2261 win
->m_icattr
->preedit_area
.height
= height
;
2262 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2268 //-----------------------------------------------------------------------------
2269 // "realize" from m_wxwindow
2270 //-----------------------------------------------------------------------------
2272 /* Initialize XIM support */
2276 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2277 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2280 wxapp_install_idle_handler();
2283 if (win
->m_ic
) return;
2284 if (!widget
) return;
2285 if (!gdk_im_ready()) return;
2287 win
->m_icattr
= gdk_ic_attr_new();
2288 if (!win
->m_icattr
) return;
2292 GdkColormap
*colormap
;
2293 GdkICAttr
*attr
= win
->m_icattr
;
2294 unsigned attrmask
= GDK_IC_ALL_REQ
;
2296 GdkIMStyle supported_style
= (GdkIMStyle
)
2297 (GDK_IM_PREEDIT_NONE
|
2298 GDK_IM_PREEDIT_NOTHING
|
2299 GDK_IM_PREEDIT_POSITION
|
2300 GDK_IM_STATUS_NONE
|
2301 GDK_IM_STATUS_NOTHING
);
2303 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2304 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2306 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2307 attr
->client_window
= widget
->window
;
2309 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2310 gtk_widget_get_default_colormap ())
2312 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2313 attr
->preedit_colormap
= colormap
;
2316 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2317 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2318 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2319 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2321 switch (style
& GDK_IM_PREEDIT_MASK
)
2323 case GDK_IM_PREEDIT_POSITION
:
2324 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2326 g_warning ("over-the-spot style requires fontset");
2330 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2332 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2333 attr
->spot_location
.x
= 0;
2334 attr
->spot_location
.y
= height
;
2335 attr
->preedit_area
.x
= 0;
2336 attr
->preedit_area
.y
= 0;
2337 attr
->preedit_area
.width
= width
;
2338 attr
->preedit_area
.height
= height
;
2339 attr
->preedit_fontset
= widget
->style
->font
;
2344 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2346 if (win
->m_ic
== NULL
)
2347 g_warning ("Can't create input context.");
2350 mask
= gdk_window_get_events (widget
->window
);
2351 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2352 gdk_window_set_events (widget
->window
, mask
);
2354 if (GTK_WIDGET_HAS_FOCUS(widget
))
2355 gdk_im_begin (win
->m_ic
, widget
->window
);
2361 //-----------------------------------------------------------------------------
2362 // InsertChild for wxWindowGTK.
2363 //-----------------------------------------------------------------------------
2365 /* Callback for wxWindowGTK. This very strange beast has to be used because
2366 * C++ has no virtual methods in a constructor. We have to emulate a
2367 * virtual function here as wxNotebook requires a different way to insert
2368 * a child in it. I had opted for creating a wxNotebookPage window class
2369 * which would have made this superfluous (such in the MDI window system),
2370 * but no-one was listening to me... */
2372 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2374 /* the window might have been scrolled already, do we
2375 have to adapt the position */
2376 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2377 child
->m_x
+= pizza
->xoffset
;
2378 child
->m_y
+= pizza
->yoffset
;
2380 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2381 GTK_WIDGET(child
->m_widget
),
2388 //-----------------------------------------------------------------------------
2390 //-----------------------------------------------------------------------------
2392 wxWindow
*wxGetActiveWindow()
2394 return wxWindow::FindFocus();
2398 wxMouseState
wxGetMouseState()
2404 GdkModifierType mask
;
2406 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2410 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2411 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2412 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2414 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2415 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2416 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2417 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2422 //-----------------------------------------------------------------------------
2424 //-----------------------------------------------------------------------------
2426 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2428 #ifdef __WXUNIVERSAL__
2429 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2431 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2432 #endif // __WXUNIVERSAL__/__WXGTK__
2434 void wxWindowGTK::Init()
2437 m_widget
= (GtkWidget
*) NULL
;
2438 m_wxwindow
= (GtkWidget
*) NULL
;
2439 m_focusWidget
= (GtkWidget
*) NULL
;
2449 m_needParent
= true;
2450 m_isBeingDeleted
= false;
2453 m_nativeSizeEvent
= false;
2455 m_hasScrolling
= false;
2456 m_isScrolling
= false;
2457 m_mouseButtonDown
= false;
2458 m_blockScrollEvent
= false;
2461 m_scrollBar
[1] = NULL
;
2464 m_blockValueChanged
[0] =
2465 m_blockValueChanged
[1] = false;
2468 m_oldClientHeight
= 0;
2472 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2474 m_acceptsFocus
= false;
2477 m_clipPaintRegion
= false;
2479 m_needsStyleChange
= false;
2481 m_cursor
= *wxSTANDARD_CURSOR
;
2484 m_dirtyTabOrder
= false;
2487 wxWindowGTK::wxWindowGTK()
2492 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2497 const wxString
&name
)
2501 Create( parent
, id
, pos
, size
, style
, name
);
2504 bool wxWindowGTK::Create( wxWindow
*parent
,
2509 const wxString
&name
)
2511 if (!PreCreation( parent
, pos
, size
) ||
2512 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2514 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2518 m_insertCallback
= wxInsertChildInWindow
;
2520 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2521 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2523 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2525 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2526 scroll_class
->scrollbar_spacing
= 0;
2528 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2530 m_scrollBar
[0] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2531 m_scrollBar
[1] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2533 m_wxwindow
= gtk_pizza_new();
2535 #ifndef __WXUNIVERSAL__
2536 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2538 if (HasFlag(wxRAISED_BORDER
))
2540 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2542 else if (HasFlag(wxSUNKEN_BORDER
))
2544 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2546 else if (HasFlag(wxSIMPLE_BORDER
))
2548 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2552 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2554 #endif // __WXUNIVERSAL__
2556 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2558 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2559 m_acceptsFocus
= true;
2561 // these handlers block mouse events to any window during scrolling such as
2562 // motion events and prevent GTK and wxWidgets from fighting over where the
2564 g_signal_connect(m_scrollBar
[0], "button_press_event",
2565 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2566 g_signal_connect(m_scrollBar
[1], "button_press_event",
2567 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2568 g_signal_connect(m_scrollBar
[0], "button_release_event",
2569 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2570 g_signal_connect(m_scrollBar
[1], "button_release_event",
2571 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2573 // these handlers get notified when scrollbar slider moves
2575 g_signal_connect(m_scrollBar
[0], "value_changed",
2576 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2577 g_signal_connect(m_scrollBar
[1], "value_changed",
2578 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2580 gtk_widget_show( m_wxwindow
);
2583 m_parent
->DoAddChild( this );
2585 m_focusWidget
= m_wxwindow
;
2592 wxWindowGTK::~wxWindowGTK()
2596 if (g_focusWindow
== this)
2597 g_focusWindow
= NULL
;
2599 if ( g_delayedFocus
== this )
2600 g_delayedFocus
= NULL
;
2602 m_isBeingDeleted
= true;
2605 // destroy children before destroying this window itself
2608 // unhook focus handlers to prevent stray events being
2609 // propagated to this (soon to be) dead object
2610 if (m_focusWidget
!= NULL
)
2612 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2613 (gpointer
) gtk_window_focus_in_callback
,
2615 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2616 (gpointer
) gtk_window_focus_out_callback
,
2625 gdk_ic_destroy (m_ic
);
2627 gdk_ic_attr_destroy (m_icattr
);
2630 // delete before the widgets to avoid a crash on solaris
2635 gtk_widget_destroy( m_wxwindow
);
2636 m_wxwindow
= (GtkWidget
*) NULL
;
2641 gtk_widget_destroy( m_widget
);
2642 m_widget
= (GtkWidget
*) NULL
;
2646 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2648 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2650 // Use either the given size, or the default if -1 is given.
2651 // See wxWindowBase for these functions.
2652 m_width
= WidthDefault(size
.x
) ;
2653 m_height
= HeightDefault(size
.y
);
2661 void wxWindowGTK::PostCreation()
2663 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2669 // these get reported to wxWidgets -> wxPaintEvent
2671 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2673 g_signal_connect (m_wxwindow
, "expose_event",
2674 G_CALLBACK (gtk_window_expose_callback
), this);
2676 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2679 // Create input method handler
2680 m_imData
= new wxGtkIMData
;
2682 // Cannot handle drawing preedited text yet
2683 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2685 g_signal_connect (m_imData
->context
, "commit",
2686 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2688 // these are called when the "sunken" or "raised" borders are drawn
2689 g_signal_connect (m_widget
, "expose_event",
2690 G_CALLBACK (gtk_window_own_expose_callback
), this);
2695 if (!GTK_IS_WINDOW(m_widget
))
2697 if (m_focusWidget
== NULL
)
2698 m_focusWidget
= m_widget
;
2702 g_signal_connect (m_focusWidget
, "focus_in_event",
2703 G_CALLBACK (gtk_window_focus_in_callback
), this);
2704 g_signal_connect (m_focusWidget
, "focus_out_event",
2705 G_CALLBACK (gtk_window_focus_out_callback
), this);
2709 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2710 G_CALLBACK (gtk_window_focus_in_callback
), this);
2711 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2712 G_CALLBACK (gtk_window_focus_out_callback
), this);
2716 // connect to the various key and mouse handlers
2718 GtkWidget
*connect_widget
= GetConnectWidget();
2720 ConnectWidget( connect_widget
);
2722 /* We cannot set colours, fonts and cursors before the widget has
2723 been realized, so we do this directly after realization */
2724 g_signal_connect (connect_widget
, "realize",
2725 G_CALLBACK (gtk_window_realized_callback
), this);
2729 // Catch native resize events
2730 g_signal_connect (m_wxwindow
, "size_allocate",
2731 G_CALLBACK (gtk_window_size_callback
), this);
2733 // Initialize XIM support
2734 g_signal_connect (m_wxwindow
, "realize",
2735 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2737 // And resize XIM window
2738 g_signal_connect (m_wxwindow
, "size_allocate",
2739 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2742 if (GTK_IS_COMBO(m_widget
))
2744 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2746 g_signal_connect (gcombo
->entry
, "size_request",
2747 G_CALLBACK (wxgtk_combo_size_request_callback
),
2750 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2751 else if (GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2753 // If we connect to the "size_request" signal of a GtkFileChooserButton
2754 // then that control won't be sized properly when placed inside sizers
2755 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2756 // FIXME: what should be done here ?
2761 // This is needed if we want to add our windows into native
2762 // GTK controls, such as the toolbar. With this callback, the
2763 // toolbar gets to know the correct size (the one set by the
2764 // programmer). Sadly, it misbehaves for wxComboBox.
2765 g_signal_connect (m_widget
, "size_request",
2766 G_CALLBACK (wxgtk_window_size_request_callback
),
2770 InheritAttributes();
2774 // unless the window was created initially hidden (i.e. Hide() had been
2775 // called before Create()), we should show it at GTK+ level as well
2777 gtk_widget_show( m_widget
);
2780 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2782 g_signal_connect (widget
, "key_press_event",
2783 G_CALLBACK (gtk_window_key_press_callback
), this);
2784 g_signal_connect (widget
, "key_release_event",
2785 G_CALLBACK (gtk_window_key_release_callback
), this);
2786 g_signal_connect (widget
, "button_press_event",
2787 G_CALLBACK (gtk_window_button_press_callback
), this);
2788 g_signal_connect (widget
, "button_release_event",
2789 G_CALLBACK (gtk_window_button_release_callback
), this);
2790 g_signal_connect (widget
, "motion_notify_event",
2791 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2792 g_signal_connect (widget
, "scroll_event",
2793 G_CALLBACK (window_scroll_event
), this);
2794 g_signal_connect (widget
, "popup_menu",
2795 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2796 g_signal_connect (widget
, "enter_notify_event",
2797 G_CALLBACK (gtk_window_enter_callback
), this);
2798 g_signal_connect (widget
, "leave_notify_event",
2799 G_CALLBACK (gtk_window_leave_callback
), this);
2802 bool wxWindowGTK::Destroy()
2804 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2808 return wxWindowBase::Destroy();
2811 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2813 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2816 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2818 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2819 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2822 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2825 if (m_resizing
) return; /* I don't like recursions */
2828 int currentX
, currentY
;
2829 GetPosition(¤tX
, ¤tY
);
2830 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2832 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2834 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2836 // calculate the best size if we should auto size the window
2837 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2838 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2840 const wxSize sizeBest
= GetBestSize();
2841 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2843 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2844 height
= sizeBest
.y
;
2852 int minWidth
= GetMinWidth(),
2853 minHeight
= GetMinHeight(),
2854 maxWidth
= GetMaxWidth(),
2855 maxHeight
= GetMaxHeight();
2857 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2858 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2859 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2860 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2862 #if wxUSE_TOOLBAR_NATIVE
2863 if (wxDynamicCast(GetParent(), wxToolBar
))
2865 // don't take the x,y values, they're wrong because toolbar sets them
2866 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2867 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2868 if (GTK_WIDGET_VISIBLE (widget
))
2869 gtk_widget_queue_resize (widget
);
2873 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2875 // don't set the size for children of wxNotebook, just take the values.
2883 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2884 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2886 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2887 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2891 m_x
= x
+ pizza
->xoffset
;
2892 m_y
= y
+ pizza
->yoffset
;
2895 int left_border
= 0;
2896 int right_border
= 0;
2898 int bottom_border
= 0;
2900 /* the default button has a border around it */
2901 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2903 GtkBorder
*default_border
= NULL
;
2904 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2907 left_border
+= default_border
->left
;
2908 right_border
+= default_border
->right
;
2909 top_border
+= default_border
->top
;
2910 bottom_border
+= default_border
->bottom
;
2911 g_free( default_border
);
2915 DoMoveWindow( m_x
-top_border
,
2917 m_width
+left_border
+right_border
,
2918 m_height
+top_border
+bottom_border
);
2923 /* Sometimes the client area changes size without the
2924 whole windows's size changing, but if the whole
2925 windows's size doesn't change, no wxSizeEvent will
2926 normally be sent. Here we add an extra test if
2927 the client test has been changed and this will
2929 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2933 wxPrintf( "OnSize sent from " );
2934 if (GetClassInfo() && GetClassInfo()->GetClassName())
2935 wxPrintf( GetClassInfo()->GetClassName() );
2936 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2939 if (!m_nativeSizeEvent
)
2941 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2942 event
.SetEventObject( this );
2943 GetEventHandler()->ProcessEvent( event
);
2949 void wxWindowGTK::OnInternalIdle()
2951 if ( m_dirtyTabOrder
)
2953 m_dirtyTabOrder
= false;
2957 // Update style if the window was not yet realized
2958 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2959 if (m_needsStyleChange
)
2961 SetBackgroundStyle(GetBackgroundStyle());
2962 m_needsStyleChange
= false;
2965 // Update invalidated regions.
2968 wxCursor cursor
= m_cursor
;
2969 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2973 /* I now set the cursor anew in every OnInternalIdle call
2974 as setting the cursor in a parent window also effects the
2975 windows above so that checking for the current cursor is
2980 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2982 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2984 if (!g_globalCursor
.Ok())
2985 cursor
= *wxSTANDARD_CURSOR
;
2987 window
= m_widget
->window
;
2988 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2989 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2995 GdkWindow
*window
= m_widget
->window
;
2996 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2997 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3002 if (wxUpdateUIEvent::CanUpdate(this))
3003 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3006 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3008 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3010 if (width
) (*width
) = m_width
;
3011 if (height
) (*height
) = m_height
;
3014 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3016 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3025 GetScrollbarWidth(m_widget
, dw
, dh
);
3028 #ifndef __WXUNIVERSAL__
3029 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3031 // shadow border size is 2
3035 if (HasFlag(wxSIMPLE_BORDER
))
3037 // simple border size is 1
3041 #endif // __WXUNIVERSAL__
3047 SetSize(width
, height
);
3050 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3052 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3064 GetScrollbarWidth(m_widget
, dw
, dh
);
3067 #ifndef __WXUNIVERSAL__
3068 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3070 // shadow border size is 2
3074 if (HasFlag(wxSIMPLE_BORDER
))
3076 // simple border size is 1
3080 #endif // __WXUNIVERSAL__
3086 if (width
) *width
= w
;
3087 if (height
) *height
= h
;
3090 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3092 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3096 if (m_parent
&& m_parent
->m_wxwindow
)
3098 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3099 dx
= pizza
->xoffset
;
3100 dy
= pizza
->yoffset
;
3103 if (x
) (*x
) = m_x
- dx
;
3104 if (y
) (*y
) = m_y
- dy
;
3107 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3109 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3111 if (!m_widget
->window
) return;
3113 GdkWindow
*source
= (GdkWindow
*) NULL
;
3115 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3117 source
= m_widget
->window
;
3121 gdk_window_get_origin( source
, &org_x
, &org_y
);
3125 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3127 org_x
+= m_widget
->allocation
.x
;
3128 org_y
+= m_widget
->allocation
.y
;
3136 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3138 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3140 if (!m_widget
->window
) return;
3142 GdkWindow
*source
= (GdkWindow
*) NULL
;
3144 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3146 source
= m_widget
->window
;
3150 gdk_window_get_origin( source
, &org_x
, &org_y
);
3154 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3156 org_x
+= m_widget
->allocation
.x
;
3157 org_y
+= m_widget
->allocation
.y
;
3165 bool wxWindowGTK::Show( bool show
)
3167 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3169 if (!wxWindowBase::Show(show
))
3176 gtk_widget_show( m_widget
);
3178 gtk_widget_hide( m_widget
);
3180 wxShowEvent
eventShow(GetId(), show
);
3181 eventShow
.SetEventObject(this);
3183 GetEventHandler()->ProcessEvent(eventShow
);
3188 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3190 win
->OnParentEnable(enable
);
3192 // Recurse, so that children have the opportunity to Do The Right Thing
3193 // and reset colours that have been messed up by a parent's (really ancestor's)
3195 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3197 node
= node
->GetNext() )
3199 wxWindow
*child
= node
->GetData();
3200 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3201 wxWindowNotifyEnable(child
, enable
);
3205 bool wxWindowGTK::Enable( bool enable
)
3207 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3209 if (!wxWindowBase::Enable(enable
))
3215 gtk_widget_set_sensitive( m_widget
, enable
);
3217 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3219 wxWindowNotifyEnable(this, enable
);
3224 int wxWindowGTK::GetCharHeight() const
3226 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3228 wxFont font
= GetFont();
3229 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3231 PangoContext
*context
= NULL
;
3233 context
= gtk_widget_get_pango_context( m_widget
);
3238 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3239 PangoLayout
*layout
= pango_layout_new(context
);
3240 pango_layout_set_font_description(layout
, desc
);
3241 pango_layout_set_text(layout
, "H", 1);
3242 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3244 PangoRectangle rect
;
3245 pango_layout_line_get_extents(line
, NULL
, &rect
);
3247 g_object_unref (layout
);
3249 return (int) PANGO_PIXELS(rect
.height
);
3252 int wxWindowGTK::GetCharWidth() const
3254 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3256 wxFont font
= GetFont();
3257 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3259 PangoContext
*context
= NULL
;
3261 context
= gtk_widget_get_pango_context( m_widget
);
3266 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3267 PangoLayout
*layout
= pango_layout_new(context
);
3268 pango_layout_set_font_description(layout
, desc
);
3269 pango_layout_set_text(layout
, "g", 1);
3270 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3272 PangoRectangle rect
;
3273 pango_layout_line_get_extents(line
, NULL
, &rect
);
3275 g_object_unref (layout
);
3277 return (int) PANGO_PIXELS(rect
.width
);
3280 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3284 int *externalLeading
,
3285 const wxFont
*theFont
) const
3287 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3289 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3298 PangoContext
*context
= NULL
;
3300 context
= gtk_widget_get_pango_context( m_widget
);
3309 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3310 PangoLayout
*layout
= pango_layout_new(context
);
3311 pango_layout_set_font_description(layout
, desc
);
3313 const wxCharBuffer data
= wxGTK_CONV( string
);
3315 pango_layout_set_text(layout
, data
, strlen(data
));
3318 PangoRectangle rect
;
3319 pango_layout_get_extents(layout
, NULL
, &rect
);
3321 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3322 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3325 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3326 int baseline
= pango_layout_iter_get_baseline(iter
);
3327 pango_layout_iter_free(iter
);
3328 *descent
= *y
- PANGO_PIXELS(baseline
);
3330 if (externalLeading
) (*externalLeading
) = 0; // ??
3332 g_object_unref (layout
);
3335 void wxWindowGTK::SetFocus()
3337 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3340 // don't do anything if we already have focus
3346 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3348 gtk_widget_grab_focus (m_wxwindow
);
3353 if (GTK_IS_CONTAINER(m_widget
))
3355 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3358 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3361 if (!GTK_WIDGET_REALIZED(m_widget
))
3363 // we can't set the focus to the widget now so we remember that
3364 // it should be focused and will do it later, during the idle
3365 // time, as soon as we can
3366 wxLogTrace(TRACE_FOCUS
,
3367 _T("Delaying setting focus to %s(%s)"),
3368 GetClassInfo()->GetClassName(), GetLabel().c_str());
3370 g_delayedFocus
= this;
3374 wxLogTrace(TRACE_FOCUS
,
3375 _T("Setting focus to %s(%s)"),
3376 GetClassInfo()->GetClassName(), GetLabel().c_str());
3378 gtk_widget_grab_focus (m_widget
);
3383 wxLogTrace(TRACE_FOCUS
,
3384 _T("Can't set focus to %s(%s)"),
3385 GetClassInfo()->GetClassName(), GetLabel().c_str());
3390 bool wxWindowGTK::AcceptsFocus() const
3392 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3395 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3397 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3399 wxWindowGTK
*oldParent
= m_parent
,
3400 *newParent
= (wxWindowGTK
*)newParentBase
;
3402 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3404 if ( !wxWindowBase::Reparent(newParent
) )
3407 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3409 /* prevent GTK from deleting the widget arbitrarily */
3410 gtk_widget_ref( m_widget
);
3414 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3417 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3421 /* insert GTK representation */
3422 (*(newParent
->m_insertCallback
))(newParent
, this);
3425 /* reverse: prevent GTK from deleting the widget arbitrarily */
3426 gtk_widget_unref( m_widget
);
3431 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3433 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3435 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3437 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3442 /* insert GTK representation */
3443 (*m_insertCallback
)(this, child
);
3446 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3448 wxWindowBase::AddChild(child
);
3449 m_dirtyTabOrder
= true;
3451 wxapp_install_idle_handler();
3454 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3456 wxWindowBase::RemoveChild(child
);
3457 m_dirtyTabOrder
= true;
3459 wxapp_install_idle_handler();
3462 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3464 wxWindowBase::DoMoveInTabOrder(win
, move
);
3465 m_dirtyTabOrder
= true;
3467 wxapp_install_idle_handler();
3470 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3472 // none needed by default
3476 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3478 // nothing to do by default since none is needed
3481 void wxWindowGTK::RealizeTabOrder()
3485 if ( !m_children
.empty() )
3487 // we don't only construct the correct focus chain but also use
3488 // this opportunity to update the mnemonic widgets for the widgets
3491 GList
*chain
= NULL
;
3492 wxWindowGTK
* mnemonicWindow
= NULL
;
3494 for ( wxWindowList::const_iterator i
= m_children
.begin();
3495 i
!= m_children
.end();
3498 wxWindowGTK
*win
= *i
;
3500 if ( mnemonicWindow
)
3502 if ( win
->AcceptsFocusFromKeyboard() )
3504 // wxComboBox et al. needs to focus on on a different
3505 // widget than m_widget, so if the main widget isn't
3506 // focusable try the connect widget
3507 GtkWidget
* w
= win
->m_widget
;
3508 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3510 w
= win
->GetConnectWidget();
3511 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3517 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3518 mnemonicWindow
= NULL
;
3522 else if ( win
->GTKWidgetNeedsMnemonic() )
3524 mnemonicWindow
= win
;
3527 chain
= g_list_prepend(chain
, win
->m_widget
);
3530 chain
= g_list_reverse(chain
);
3532 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3537 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3542 void wxWindowGTK::Raise()
3544 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3546 if (m_wxwindow
&& m_wxwindow
->window
)
3548 gdk_window_raise( m_wxwindow
->window
);
3550 else if (m_widget
->window
)
3552 gdk_window_raise( m_widget
->window
);
3556 void wxWindowGTK::Lower()
3558 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3560 if (m_wxwindow
&& m_wxwindow
->window
)
3562 gdk_window_lower( m_wxwindow
->window
);
3564 else if (m_widget
->window
)
3566 gdk_window_lower( m_widget
->window
);
3570 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3572 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3574 if (cursor
== m_cursor
)
3578 wxapp_install_idle_handler();
3580 if (cursor
== wxNullCursor
)
3581 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3583 return wxWindowBase::SetCursor( cursor
);
3586 void wxWindowGTK::WarpPointer( int x
, int y
)
3588 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3590 // We provide this function ourselves as it is
3591 // missing in GDK (top of this file).
3593 GdkWindow
*window
= (GdkWindow
*) NULL
;
3595 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3597 window
= GetConnectWidget()->window
;
3600 gdk_window_warp_pointer( window
, x
, y
);
3603 bool wxWindowGTK::ScrollLines(int lines
)
3605 bool changed
= false;
3606 GtkRange
* range
= m_scrollBar
[1];
3609 GtkAdjustment
* adj
= range
->adjustment
;
3610 const int pos
= int(adj
->value
+ 0.5);
3611 gtk_range_set_value(range
, pos
+ lines
);
3612 changed
= pos
!= int(adj
->value
+ 0.5);
3617 bool wxWindowGTK::ScrollPages(int pages
)
3619 bool changed
= false;
3620 GtkRange
* range
= m_scrollBar
[1];
3623 GtkAdjustment
* adj
= range
->adjustment
;
3624 const int pos
= int(adj
->value
+ 0.5);
3625 gtk_range_set_value(range
, pos
+ pages
* adj
->page_size
);
3626 changed
= pos
!= int(adj
->value
+ 0.5);
3631 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3635 if (!m_widget
->window
)
3640 GdkRectangle gdk_rect
,
3644 gdk_rect
.x
= rect
->x
;
3645 gdk_rect
.y
= rect
->y
;
3646 gdk_rect
.width
= rect
->width
;
3647 gdk_rect
.height
= rect
->height
;
3650 else // invalidate everything
3655 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3659 void wxWindowGTK::Update()
3663 // when we call Update() we really want to update the window immediately on
3664 // screen, even if it means flushing the entire queue and hence slowing down
3665 // everything -- but it should still be done, it's just that Update() should
3666 // be called very rarely
3670 void wxWindowGTK::GtkUpdate()
3672 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3673 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3675 // for consistency with other platforms (and also because it's convenient
3676 // to be able to update an entire TLW by calling Update() only once), we
3677 // should also update all our children here
3678 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3680 node
= node
->GetNext() )
3682 node
->GetData()->GtkUpdate();
3686 void wxWindowGTK::GtkSendPaintEvents()
3690 m_updateRegion
.Clear();
3694 // Clip to paint region in wxClientDC
3695 m_clipPaintRegion
= true;
3697 // widget to draw on
3698 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3700 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3702 // find ancestor from which to steal background
3703 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3705 parent
= (wxWindow
*)this;
3707 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3709 wxRegionIterator
upd( m_updateRegion
);
3713 rect
.x
= upd
.GetX();
3714 rect
.y
= upd
.GetY();
3715 rect
.width
= upd
.GetWidth();
3716 rect
.height
= upd
.GetHeight();
3718 gtk_paint_flat_box( parent
->m_widget
->style
,
3720 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3734 wxWindowDC
dc( (wxWindow
*)this );
3735 dc
.SetClippingRegion( m_updateRegion
);
3737 wxEraseEvent
erase_event( GetId(), &dc
);
3738 erase_event
.SetEventObject( this );
3740 GetEventHandler()->ProcessEvent(erase_event
);
3743 wxNcPaintEvent
nc_paint_event( GetId() );
3744 nc_paint_event
.SetEventObject( this );
3745 GetEventHandler()->ProcessEvent( nc_paint_event
);
3747 wxPaintEvent
paint_event( GetId() );
3748 paint_event
.SetEventObject( this );
3749 GetEventHandler()->ProcessEvent( paint_event
);
3751 m_clipPaintRegion
= false;
3753 m_updateRegion
.Clear();
3756 void wxWindowGTK::SetDoubleBuffered( bool on
)
3758 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3761 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3764 void wxWindowGTK::ClearBackground()
3766 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3770 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3772 wxWindowBase::DoSetToolTip(tip
);
3775 m_tooltip
->Apply( (wxWindow
*)this );
3778 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3780 wxString
tmp( tip
);
3781 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3783 #endif // wxUSE_TOOLTIPS
3785 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3787 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3789 if (!wxWindowBase::SetBackgroundColour(colour
))
3794 // We need the pixel value e.g. for background clearing.
3795 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3798 // apply style change (forceStyle=true so that new style is applied
3799 // even if the bg colour changed from valid to wxNullColour)
3800 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3801 ApplyWidgetStyle(true);
3806 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3808 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3810 if (!wxWindowBase::SetForegroundColour(colour
))
3817 // We need the pixel value e.g. for background clearing.
3818 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3821 // apply style change (forceStyle=true so that new style is applied
3822 // even if the bg colour changed from valid to wxNullColour):
3823 ApplyWidgetStyle(true);
3828 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3830 return gtk_widget_get_pango_context( m_widget
);
3833 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3835 // do we need to apply any changes at all?
3838 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3843 GtkRcStyle
*style
= gtk_rc_style_new();
3848 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3851 if ( m_foregroundColour
.Ok() )
3853 GdkColor
*fg
= m_foregroundColour
.GetColor();
3855 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3856 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3858 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3859 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3861 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3862 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3865 if ( m_backgroundColour
.Ok() )
3867 GdkColor
*bg
= m_backgroundColour
.GetColor();
3869 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3870 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3871 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3872 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3874 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3875 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3876 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3877 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3879 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3880 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3881 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3882 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3884 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3885 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3886 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3887 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3893 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3895 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3898 DoApplyWidgetStyle(style
);
3899 gtk_rc_style_unref(style
);
3902 // Style change may affect GTK+'s size calculation:
3903 InvalidateBestSize();
3906 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3909 gtk_widget_modify_style(m_wxwindow
, style
);
3911 gtk_widget_modify_style(m_widget
, style
);
3914 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3916 wxWindowBase::SetBackgroundStyle(style
);
3918 if (style
== wxBG_STYLE_CUSTOM
)
3920 GdkWindow
*window
= (GdkWindow
*) NULL
;
3922 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3924 window
= GetConnectWidget()->window
;
3928 // Make sure GDK/X11 doesn't refresh the window
3930 gdk_window_set_back_pixmap( window
, None
, False
);
3932 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3935 m_needsStyleChange
= false;
3938 // Do in OnIdle, because the window is not yet available
3939 m_needsStyleChange
= true;
3941 // Don't apply widget style, or we get a grey background
3945 // apply style change (forceStyle=true so that new style is applied
3946 // even if the bg colour changed from valid to wxNullColour):
3947 ApplyWidgetStyle(true);
3952 #if wxUSE_DRAG_AND_DROP
3954 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3956 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3958 GtkWidget
*dnd_widget
= GetConnectWidget();
3960 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3962 if (m_dropTarget
) delete m_dropTarget
;
3963 m_dropTarget
= dropTarget
;
3965 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3968 #endif // wxUSE_DRAG_AND_DROP
3970 GtkWidget
* wxWindowGTK::GetConnectWidget()
3972 GtkWidget
*connect_widget
= m_widget
;
3973 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3975 return connect_widget
;
3978 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3981 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3983 return (window
== m_widget
->window
);
3986 bool wxWindowGTK::SetFont( const wxFont
&font
)
3988 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3990 if (!wxWindowBase::SetFont(font
))
3993 // apply style change (forceStyle=true so that new style is applied
3994 // even if the font changed from valid to wxNullFont):
3995 ApplyWidgetStyle(true);
4000 void wxWindowGTK::DoCaptureMouse()
4002 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4004 GdkWindow
*window
= (GdkWindow
*) NULL
;
4006 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4008 window
= GetConnectWidget()->window
;
4010 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4012 const wxCursor
* cursor
= &m_cursor
;
4014 cursor
= wxSTANDARD_CURSOR
;
4016 gdk_pointer_grab( window
, FALSE
,
4018 (GDK_BUTTON_PRESS_MASK
|
4019 GDK_BUTTON_RELEASE_MASK
|
4020 GDK_POINTER_MOTION_HINT_MASK
|
4021 GDK_POINTER_MOTION_MASK
),
4023 cursor
->GetCursor(),
4024 (guint32
)GDK_CURRENT_TIME
);
4025 g_captureWindow
= this;
4026 g_captureWindowHasMouse
= true;
4029 void wxWindowGTK::DoReleaseMouse()
4031 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4033 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4035 g_captureWindow
= (wxWindowGTK
*) NULL
;
4037 GdkWindow
*window
= (GdkWindow
*) NULL
;
4039 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4041 window
= GetConnectWidget()->window
;
4046 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4050 wxWindow
*wxWindowBase::GetCapture()
4052 return (wxWindow
*)g_captureWindow
;
4055 bool wxWindowGTK::IsRetained() const
4060 void wxWindowGTK::BlockScrollEvent()
4062 wxASSERT(!m_blockScrollEvent
);
4063 m_blockScrollEvent
= true;
4066 void wxWindowGTK::UnblockScrollEvent()
4068 wxASSERT(m_blockScrollEvent
);
4069 m_blockScrollEvent
= false;
4072 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4075 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4076 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4080 m_hasScrolling
= true;
4084 // GtkRange requires upper > lower
4089 if (pos
> range
- thumbVisible
)
4090 pos
= range
- thumbVisible
;
4093 const int i
= orient
== wxVERTICAL
;
4094 GtkAdjustment
* adj
= m_scrollBar
[i
]->adjustment
;
4095 adj
->step_increment
= 1;
4096 adj
->page_increment
=
4097 adj
->page_size
= thumbVisible
;
4099 SetScrollPos(orient
, pos
);
4100 gtk_adjustment_changed(adj
);
4103 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4105 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4106 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4108 // This check is more than an optimization. Without it, the slider
4109 // will not move smoothly while tracking when using wxScrollHelper.
4110 if (GetScrollPos(orient
) != pos
)
4112 const int i
= orient
== wxVERTICAL
;
4113 GtkAdjustment
* adj
= m_scrollBar
[i
]->adjustment
;
4114 const int max
= int(adj
->upper
- adj
->page_size
);
4121 // If a "value_changed" signal emission is not already in progress
4122 if (!m_blockValueChanged
[i
])
4124 gtk_adjustment_value_changed(adj
);
4129 int wxWindowGTK::GetScrollThumb( int orient
) const
4131 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4132 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4134 const int i
= orient
== wxVERTICAL
;
4135 return int(m_scrollBar
[i
]->adjustment
->page_size
);
4138 int wxWindowGTK::GetScrollPos( int orient
) const
4140 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4141 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4143 const int i
= orient
== wxVERTICAL
;
4144 return int(m_scrollBar
[i
]->adjustment
->value
+ 0.5);
4147 int wxWindowGTK::GetScrollRange( int orient
) const
4149 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4150 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4152 const int i
= orient
== wxVERTICAL
;
4153 return int(m_scrollBar
[i
]->adjustment
->upper
);
4156 // Determine if increment is the same as +/-x, allowing for some small
4157 // difference due to possible inexactness in floating point arithmetic
4158 static inline bool IsScrollIncrement(double increment
, double x
)
4160 wxASSERT(increment
> 0);
4161 const double tolerance
= 1.0 / 1024;
4162 return fabs(increment
- fabs(x
)) < tolerance
;
4165 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4170 wxapp_install_idle_handler();
4172 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4174 const int barIndex
= range
== m_scrollBar
[1];
4175 GtkAdjustment
* adj
= range
->adjustment
;
4176 const int value
= int(adj
->value
+ 0.5);
4177 // save previous position
4178 const double oldPos
= m_scrollPos
[barIndex
];
4179 // update current position
4180 m_scrollPos
[barIndex
] = adj
->value
;
4181 // If event should be ignored, or integral position has not changed
4182 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4187 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4190 // Difference from last change event
4191 const double diff
= adj
->value
- oldPos
;
4192 const bool isDown
= diff
> 0;
4194 if (IsScrollIncrement(adj
->step_increment
, diff
))
4196 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4198 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4200 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4202 else if (m_mouseButtonDown
)
4204 // Assume track event
4205 m_isScrolling
= true;
4211 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4213 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4215 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4217 // No scrolling requested.
4218 if ((dx
== 0) && (dy
== 0)) return;
4220 m_clipPaintRegion
= true;
4222 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4224 m_clipPaintRegion
= false;
4227 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4229 //RN: Note that static controls usually have no border on gtk, so maybe
4230 //it makes sense to treat that as simply no border at the wx level
4232 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4234 GtkShadowType gtkstyle
;
4236 if(wxstyle
& wxBORDER_RAISED
)
4237 gtkstyle
= GTK_SHADOW_OUT
;
4238 else if (wxstyle
& wxBORDER_SUNKEN
)
4239 gtkstyle
= GTK_SHADOW_IN
;
4240 else if (wxstyle
& wxBORDER_DOUBLE
)
4241 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4243 gtkstyle
= GTK_SHADOW_IN
;
4245 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4250 void wxWindowGTK::SetWindowStyleFlag( long style
)
4252 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4253 wxWindowBase::SetWindowStyleFlag(style
);
4256 // Find the wxWindow at the current mouse position, also returning the mouse
4258 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4260 pt
= wxGetMousePosition();
4261 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4265 // Get the current mouse position.
4266 wxPoint
wxGetMousePosition()
4268 /* This crashes when used within wxHelpContext,
4269 so we have to use the X-specific implementation below.
4271 GdkModifierType *mask;
4272 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4274 return wxPoint(x, y);
4278 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4280 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4281 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4282 Window rootReturn
, childReturn
;
4283 int rootX
, rootY
, winX
, winY
;
4284 unsigned int maskReturn
;
4286 XQueryPointer (display
,
4290 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4291 return wxPoint(rootX
, rootY
);
4295 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4296 void wxAddGrab(wxWindow
* window
)
4298 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4301 void wxRemoveGrab(wxWindow
* window
)
4303 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4306 // ----------------------------------------------------------------------------
4308 // ----------------------------------------------------------------------------
4310 class wxWinModule
: public wxModule
4317 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4320 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4322 bool wxWinModule::OnInit()
4324 // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() );
4325 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4330 void wxWinModule::OnExit()
4333 g_object_unref (g_eraseGC
);