1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/window.cpp
3 // Purpose: wxWindowGTK implementation
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"
22 #include "wx/toplevel.h"
23 #include "wx/dcclient.h"
25 #include "wx/settings.h"
26 #include "wx/msgdlg.h"
31 #include "wx/tooltip.h"
33 #include "wx/fontutil.h"
34 #include "wx/sysopt.h"
38 #include "wx/gtk/private.h"
39 #include "wx/gtk/private/win_gtk.h"
40 #include "wx/gtk/private/event.h"
41 using namespace wxGTKImpl
;
45 #include <gdk/gdkkeysyms.h>
46 #if GTK_CHECK_VERSION(3,0,0)
47 #include <gdk/gdkkeysyms-compat.h>
50 //-----------------------------------------------------------------------------
51 // documentation on internals
52 //-----------------------------------------------------------------------------
55 I have been asked several times about writing some documentation about
56 the GTK port of wxWidgets, especially its internal structures. Obviously,
57 you cannot understand wxGTK without knowing a little about the GTK, but
58 some more information about what the wxWindow, which is the base class
59 for all other window classes, does seems required as well.
63 What does wxWindow do? It contains the common interface for the following
64 jobs of its descendants:
66 1) Define the rudimentary behaviour common to all window classes, such as
67 resizing, intercepting user input (so as to make it possible to use these
68 events for special purposes in a derived class), window names etc.
70 2) Provide the possibility to contain and manage children, if the derived
71 class is allowed to contain children, which holds true for those window
72 classes which do not display a native GTK widget. To name them, these
73 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
74 work classes are a special case and are handled a bit differently from
75 the rest. The same holds true for the wxNotebook class.
77 3) Provide the possibility to draw into a client area of a window. This,
78 too, only holds true for classes that do not display a native GTK widget
81 4) Provide the entire mechanism for scrolling widgets. This actual inter-
82 face for this is usually in wxScrolledWindow, but the GTK implementation
85 5) A multitude of helper or extra methods for special purposes, such as
86 Drag'n'Drop, managing validators etc.
88 6) Display a border (sunken, raised, simple or none).
90 Normally one might expect, that one wxWidgets window would always correspond
91 to one GTK widget. Under GTK, there is no such all-round widget that has all
92 the functionality. Moreover, the GTK defines a client area as a different
93 widget from the actual widget you are handling. Last but not least some
94 special classes (e.g. wxFrame) handle different categories of widgets and
95 still have the possibility to draw something in the client area.
96 It was therefore required to write a special purpose GTK widget, that would
97 represent a client area in the sense of wxWidgets capable to do the jobs
98 2), 3) and 4). I have written this class and it resides in win_gtk.c of
101 All windows must have a widget, with which they interact with other under-
102 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
103 the wxWindow class has a member variable called m_widget which holds a
104 pointer to this widget. When the window class represents a GTK native widget,
105 this is (in most cases) the only GTK widget the class manages. E.g. the
106 wxStaticText class handles only a GtkLabel widget a pointer to which you
107 can find in m_widget (defined in wxWindow)
109 When the class has a client area for drawing into and for containing children
110 it has to handle the client area widget (of the type wxPizza, defined in
111 win_gtk.cpp), but there could be any number of widgets, handled by a class.
112 The common rule for all windows is only, that the widget that interacts with
113 the rest of GTK must be referenced in m_widget and all other widgets must be
114 children of this widget on the GTK level. The top-most widget, which also
115 represents the client area, must be in the m_wxwindow field and must be of
118 As I said, the window classes that display a GTK native widget only have
119 one widget, so in the case of e.g. the wxButton class m_widget holds a
120 pointer to a GtkButton widget. But windows with client areas (for drawing
121 and children) have a m_widget field that is a pointer to a GtkScrolled-
122 Window and a m_wxwindow field that is pointer to a wxPizza and this
123 one is (in the GTK sense) a child of the GtkScrolledWindow.
125 If the m_wxwindow field is set, then all input to this widget is inter-
126 cepted and sent to the wxWidgets class. If not, all input to the widget
127 that gets pointed to by m_widget gets intercepted and sent to the class.
131 The design of scrolling in wxWidgets is markedly different from that offered
132 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
133 clicking on a scrollbar belonging to scrolled window will inevitably move
134 the window. In wxWidgets, the scrollbar will only emit an event, send this
135 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
136 which actually moves the window and its sub-windows. Note that wxPizza
137 memorizes how much it has been scrolled but that wxWidgets forgets this
138 so that the two coordinates systems have to be kept in synch. This is done
139 in various places using the pizza->m_scroll_x and pizza->m_scroll_y values.
143 Singularly the most broken code in GTK is the code that is supposed to
144 inform subwindows (child windows) about new positions. Very often, duplicate
145 events are sent without changes in size or position, equally often no
146 events are sent at all (All this is due to a bug in the GtkContainer code
147 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
148 GTK's own system and it simply waits for size events for toplevel windows
149 and then iterates down the respective size events to all window. This has
150 the disadvantage that windows might get size events before the GTK widget
151 actually has the reported size. This doesn't normally pose any problem, but
152 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
153 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
154 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
155 window that is used for OpenGL output really has that size (as reported by
160 If someone at some point of time feels the immense desire to have a look at,
161 change or attempt to optimise the Refresh() logic, this person will need an
162 intimate understanding of what "draw" and "expose" events are and what
163 they are used for, in particular when used in connection with GTK's
164 own windowless widgets. Beware.
168 Cursors, too, have been a constant source of pleasure. The main difficulty
169 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
170 for the parent. To prevent this from doing too much harm, SetCursor calls
171 GTKUpdateCursor, which will recursively re-set the cursors of all child windows.
172 Also don't forget that cursors (like much else) are connected to GdkWindows,
173 not GtkWidgets and that the "window" field of a GtkWidget might very well
174 point to the GdkWindow of the parent widget (-> "window-less widget") and
175 that the two obviously have very different meanings.
178 //-----------------------------------------------------------------------------
180 //-----------------------------------------------------------------------------
182 // Don't allow event propagation during drag
183 bool g_blockEventsOnDrag
;
184 // Don't allow mouse event propagation during scroll
185 bool g_blockEventsOnScroll
;
186 extern wxCursor g_globalCursor
;
188 // mouse capture state: the window which has it and if the mouse is currently
190 static wxWindowGTK
*g_captureWindow
= NULL
;
191 static bool g_captureWindowHasMouse
= false;
193 // The window that currently has focus:
194 static wxWindowGTK
*gs_currentFocus
= NULL
;
195 // The window that is scheduled to get focus in the next event loop iteration
196 // or NULL if there's no pending focus change:
197 static wxWindowGTK
*gs_pendingFocus
= NULL
;
199 // the window that has deferred focus-out event pending, if any (see
200 // GTKAddDeferredFocusOut() for details)
201 static wxWindowGTK
*gs_deferredFocusOut
= NULL
;
203 // global variables because GTK+ DnD want to have the
204 // mouse event that caused it
205 GdkEvent
*g_lastMouseEvent
= NULL
;
206 int g_lastButtonNumber
= 0;
208 //-----------------------------------------------------------------------------
210 //-----------------------------------------------------------------------------
212 // the trace mask used for the focus debugging messages
213 #define TRACE_FOCUS wxT("focus")
215 //-----------------------------------------------------------------------------
216 // "size_request" of m_widget
217 //-----------------------------------------------------------------------------
221 wxgtk_window_size_request_callback(GtkWidget
* WXUNUSED(widget
),
222 GtkRequisition
*requisition
,
226 win
->GetSize( &w
, &h
);
232 requisition
->height
= h
;
233 requisition
->width
= w
;
237 //-----------------------------------------------------------------------------
238 // "expose_event" of m_wxwindow
239 //-----------------------------------------------------------------------------
243 gtk_window_expose_callback( GtkWidget
*,
244 GdkEventExpose
*gdk_event
,
247 if (gdk_event
->window
== win
->GTKGetDrawingWindow())
249 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
250 win
->GtkSendPaintEvents();
252 // Let parent window draw window-less widgets
257 #ifndef __WXUNIVERSAL__
258 //-----------------------------------------------------------------------------
259 // "expose_event" from m_wxwindow->parent, for drawing border
260 //-----------------------------------------------------------------------------
264 expose_event_border(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxWindow
* win
)
266 if (gdk_event
->window
!= gtk_widget_get_parent_window(win
->m_wxwindow
))
273 gtk_widget_get_allocation(win
->m_wxwindow
, &alloc
);
274 const int x
= alloc
.x
;
275 const int y
= alloc
.y
;
276 const int w
= alloc
.width
;
277 const int h
= alloc
.height
;
279 if (w
<= 0 || h
<= 0)
282 if (win
->HasFlag(wxBORDER_SIMPLE
))
284 gdk_draw_rectangle(gdk_event
->window
,
285 gtk_widget_get_style(widget
)->black_gc
, false, x
, y
, w
- 1, h
- 1);
289 GtkShadowType shadow
= GTK_SHADOW_IN
;
290 if (win
->HasFlag(wxBORDER_RAISED
))
291 shadow
= GTK_SHADOW_OUT
;
293 // Style detail to use
295 if (win
->m_widget
== win
->m_wxwindow
)
296 // for non-scrollable wxWindows
299 // for scrollable ones
302 // clip rect is required to avoid painting background
303 // over upper left (w,h) of parent window
304 GdkRectangle clipRect
= { x
, y
, w
, h
};
306 gtk_widget_get_style(win
->m_wxwindow
), gdk_event
->window
, GTK_STATE_NORMAL
,
307 shadow
, &clipRect
, wxGTKPrivate
::GetEntryWidget(), detail
, x
, y
, w
, h
);
313 //-----------------------------------------------------------------------------
314 // "parent_set" from m_wxwindow
315 //-----------------------------------------------------------------------------
319 parent_set(GtkWidget
* widget
, GtkWidget
* old_parent
, wxWindow
* win
)
323 g_signal_handlers_disconnect_by_func(
324 old_parent
, (void*)expose_event_border
, win
);
326 GtkWidget
* parent
= gtk_widget_get_parent(widget
);
329 g_signal_connect_after(parent
, "expose_event",
330 G_CALLBACK(expose_event_border
), win
);
334 #endif // !__WXUNIVERSAL__
336 //-----------------------------------------------------------------------------
337 // "key_press_event" from any window
338 //-----------------------------------------------------------------------------
340 // These are used when transforming Ctrl-alpha to ascii values 1-26
341 inline bool wxIsLowerChar(int code
)
343 return (code
>= 'a' && code
<= 'z' );
346 inline bool wxIsUpperChar(int code
)
348 return (code
>= 'A' && code
<= 'Z' );
352 // set WXTRACE to this to see the key event codes on the console
353 #define TRACE_KEYS wxT("keyevent")
355 // translates an X key symbol to WXK_XXX value
357 // if isChar is true it means that the value returned will be used for EVT_CHAR
358 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
359 // for example, while if it is false it means that the value is going to be
360 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
362 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
368 // Shift, Control and Alt don't generate the CHAR events at all
371 key_code
= isChar ?
0 : WXK_SHIFT
;
375 key_code
= isChar ?
0 : WXK_CONTROL
;
383 key_code
= isChar ?
0 : WXK_ALT
;
386 // neither do the toggle modifies
387 case GDK_Scroll_Lock
:
388 key_code
= isChar ?
0 : WXK_SCROLL
;
392 key_code
= isChar ?
0 : WXK_CAPITAL
;
396 key_code
= isChar ?
0 : WXK_NUMLOCK
;
400 // various other special keys
413 case GDK_ISO_Left_Tab
:
420 key_code
= WXK_RETURN
;
424 key_code
= WXK_CLEAR
;
428 key_code
= WXK_PAUSE
;
432 key_code
= WXK_SELECT
;
436 key_code
= WXK_PRINT
;
440 key_code
= WXK_EXECUTE
;
444 key_code
= WXK_ESCAPE
;
447 // cursor and other extended keyboard keys
449 key_code
= WXK_DELETE
;
465 key_code
= WXK_RIGHT
;
472 case GDK_Prior
: // == GDK_Page_Up
473 key_code
= WXK_PAGEUP
;
476 case GDK_Next
: // == GDK_Page_Down
477 key_code
= WXK_PAGEDOWN
;
489 key_code
= WXK_INSERT
;
504 key_code
= (isChar ?
'0' : int(WXK_NUMPAD0
)) + keysym
- GDK_KP_0
;
508 key_code
= isChar ?
' ' : int(WXK_NUMPAD_SPACE
);
512 key_code
= isChar ? WXK_TAB
: WXK_NUMPAD_TAB
;
516 key_code
= isChar ? WXK_RETURN
: WXK_NUMPAD_ENTER
;
520 key_code
= isChar ? WXK_F1
: WXK_NUMPAD_F1
;
524 key_code
= isChar ? WXK_F2
: WXK_NUMPAD_F2
;
528 key_code
= isChar ? WXK_F3
: WXK_NUMPAD_F3
;
532 key_code
= isChar ? WXK_F4
: WXK_NUMPAD_F4
;
536 key_code
= isChar ? WXK_HOME
: WXK_NUMPAD_HOME
;
540 key_code
= isChar ? WXK_LEFT
: WXK_NUMPAD_LEFT
;
544 key_code
= isChar ? WXK_UP
: WXK_NUMPAD_UP
;
548 key_code
= isChar ? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
552 key_code
= isChar ? WXK_DOWN
: WXK_NUMPAD_DOWN
;
555 case GDK_KP_Prior
: // == GDK_KP_Page_Up
556 key_code
= isChar ? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
559 case GDK_KP_Next
: // == GDK_KP_Page_Down
560 key_code
= isChar ? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
564 key_code
= isChar ? WXK_END
: WXK_NUMPAD_END
;
568 key_code
= isChar ? WXK_HOME
: WXK_NUMPAD_BEGIN
;
572 key_code
= isChar ? WXK_INSERT
: WXK_NUMPAD_INSERT
;
576 key_code
= isChar ? WXK_DELETE
: WXK_NUMPAD_DELETE
;
580 key_code
= isChar ?
'=' : int(WXK_NUMPAD_EQUAL
);
583 case GDK_KP_Multiply
:
584 key_code
= isChar ?
'*' : int(WXK_NUMPAD_MULTIPLY
);
588 key_code
= isChar ?
'+' : int(WXK_NUMPAD_ADD
);
591 case GDK_KP_Separator
:
592 // FIXME: what is this?
593 key_code
= isChar ?
'.' : int(WXK_NUMPAD_SEPARATOR
);
596 case GDK_KP_Subtract
:
597 key_code
= isChar ?
'-' : int(WXK_NUMPAD_SUBTRACT
);
601 key_code
= isChar ?
'.' : int(WXK_NUMPAD_DECIMAL
);
605 key_code
= isChar ?
'/' : int(WXK_NUMPAD_DIVIDE
);
622 key_code
= WXK_F1
+ keysym
- GDK_F1
;
632 static inline bool wxIsAsciiKeysym(KeySym ks
)
637 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
639 GdkEventKey
*gdk_event
)
641 event
.SetTimestamp( gdk_event
->time
);
642 event
.SetId(win
->GetId());
644 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
645 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
646 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
647 event
.m_metaDown
= (gdk_event
->state
& GDK_META_MASK
) != 0;
649 // Normally we take the state of modifiers directly from the low level GDK
650 // event but unfortunately GDK uses a different convention from MSW for the
651 // key events corresponding to the modifier keys themselves: in it, when
652 // e.g. Shift key is pressed, GDK_SHIFT_MASK is not set while it is set
653 // when Shift is released. Under MSW the situation is exactly reversed and
654 // the modifier corresponding to the key is set when it is pressed and
655 // unset when it is released. To ensure consistent behaviour between
656 // platforms (and because it seems to make slightly more sense, although
657 // arguably both behaviours are reasonable) we follow MSW here.
659 // Final notice: we set the flags to the desired value instead of just
660 // inverting them because they are not set correctly (i.e. in the same way
661 // as for the real events generated by the user) for wxUIActionSimulator-
662 // produced events and it seems better to keep that class code the same
663 // among all platforms and fix the discrepancy here instead of adding
664 // wxGTK-specific code to wxUIActionSimulator.
665 const bool isPress
= gdk_event
->type
== GDK_KEY_PRESS
;
666 switch ( gdk_event
->keyval
)
670 event
.m_shiftDown
= isPress
;
675 event
.m_controlDown
= isPress
;
680 event
.m_altDown
= isPress
;
687 event
.m_metaDown
= isPress
;
691 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
692 event
.m_rawFlags
= gdk_event
->hardware_keycode
;
694 wxGetMousePosition(&event
.m_x
, &event
.m_y
);
695 win
->ScreenToClient(&event
.m_x
, &event
.m_y
);
696 event
.SetEventObject( win
);
701 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
703 GdkEventKey
*gdk_event
)
705 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
706 // but only event->keyval which is quite useless to us, so remember
707 // the last character from GDK_KEY_PRESS and reuse it as last resort
709 // NB: should be MT-safe as we're always called from the main thread only
714 } s_lastKeyPress
= { 0, 0 };
716 KeySym keysym
= gdk_event
->keyval
;
718 wxLogTrace(TRACE_KEYS
, wxT("Key %s event: keysym = %ld"),
719 event
.GetEventType() == wxEVT_KEY_UP ?
wxT("release")
723 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
727 // do we have the translation or is it a plain ASCII character?
728 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
730 // we should use keysym if it is ASCII as X does some translations
731 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
732 // which we don't want here (but which we do use for OnChar())
733 if ( !wxIsAsciiKeysym(keysym
) )
735 keysym
= (KeySym
)gdk_event
->string
[0];
738 // we want to always get the same key code when the same key is
739 // pressed regardless of the state of the modifiers, i.e. on a
740 // standard US keyboard pressing '5' or '%' ('5' key with
741 // Shift) should result in the same key code in OnKeyDown():
742 // '5' (although OnChar() will get either '5' or '%').
744 // to do it we first translate keysym to keycode (== scan code)
745 // and then back but always using the lower register
746 Display
*dpy
= (Display
*)wxGetDisplay();
747 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
749 wxLogTrace(TRACE_KEYS
, wxT("\t-> keycode %d"), keycode
);
751 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
753 // use the normalized, i.e. lower register, keysym if we've
755 key_code
= keysymNormalized ? keysymNormalized
: keysym
;
757 // as explained above, we want to have lower register key codes
758 // normally but for the letter keys we want to have the upper ones
760 // NB: don't use XConvertCase() here, we want to do it for letters
762 key_code
= toupper(key_code
);
764 else // non ASCII key, what to do?
766 // by default, ignore it
769 // but if we have cached information from the last KEY_PRESS
770 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
773 if ( keysym
== s_lastKeyPress
.keysym
)
775 key_code
= s_lastKeyPress
.keycode
;
780 if ( gdk_event
->type
== GDK_KEY_PRESS
)
782 // remember it to be reused for KEY_UP event later
783 s_lastKeyPress
.keysym
= keysym
;
784 s_lastKeyPress
.keycode
= key_code
;
788 wxLogTrace(TRACE_KEYS
, wxT("\t-> wxKeyCode %ld"), key_code
);
790 // sending unknown key events doesn't really make sense
794 event
.m_keyCode
= key_code
;
797 event
.m_uniChar
= gdk_keyval_to_unicode(key_code ? key_code
: keysym
);
798 if ( !event
.m_uniChar
&& event
.m_keyCode
<= WXK_DELETE
)
800 // Set Unicode key code to the ASCII equivalent for compatibility. E.g.
801 // let RETURN generate the key event with both key and Unicode key
803 event
.m_uniChar
= event
.m_keyCode
;
805 #endif // wxUSE_UNICODE
807 // now fill all the other fields
808 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
816 GtkIMContext
*context
;
817 GdkEventKey
*lastKeyEvent
;
821 context
= gtk_im_multicontext_new();
826 g_object_unref (context
);
833 // Send wxEVT_CHAR_HOOK event to the parent of the window and return true only
834 // if it was processed (and not skipped).
835 bool SendCharHookEvent(const wxKeyEvent
& event
, wxWindow
*win
)
837 // wxEVT_CHAR_HOOK must be sent to the top level parent window to allow it
838 // to handle key events in all of its children unless the mouse is captured
839 // in which case we consider that the keyboard should be "captured" too.
840 if ( !g_captureWindow
)
842 wxWindow
* const parent
= wxGetTopLevelParent(win
);
845 // We need to make a copy of the event object because it is
846 // modified while it's handled, notably its WasProcessed() flag
847 // is set after it had been processed once.
848 wxKeyEvent
eventCharHook(event
);
849 eventCharHook
.SetEventType(wxEVT_CHAR_HOOK
);
850 if ( parent
->HandleWindowEvent(eventCharHook
) )
858 } // anonymous namespace
862 gtk_window_key_press_callback( GtkWidget
*WXUNUSED(widget
),
863 GdkEventKey
*gdk_event
,
868 if (g_blockEventsOnDrag
)
871 wxKeyEvent
event( wxEVT_KEY_DOWN
);
873 bool return_after_IM
= false;
875 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
877 // Send the CHAR_HOOK event first
878 if ( SendCharHookEvent(event
, win
) )
880 // Don't do anything at all with this event any more.
884 // Emit KEY_DOWN event
885 ret
= win
->HandleWindowEvent( event
);
889 // Return after IM processing as we cannot do
890 // anything with it anyhow.
891 return_after_IM
= true;
894 if (!ret
&& win
->m_imData
)
896 win
->m_imData
->lastKeyEvent
= gdk_event
;
898 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
899 // docs, if IM filter returns true, no further processing should be done.
900 // we should send the key_down event anyway.
901 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
902 win
->m_imData
->lastKeyEvent
= NULL
;
903 if (intercepted_by_IM
)
905 wxLogTrace(TRACE_KEYS
, wxT("Key event intercepted by IM"));
916 wxWindowGTK
*ancestor
= win
;
919 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
922 wxCommandEvent
menu_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
923 ret
= ancestor
->HandleWindowEvent( menu_event
);
927 // if the accelerator wasn't handled as menu event, try
928 // it as button click (for compatibility with other
930 wxCommandEvent
button_event( wxEVT_COMMAND_BUTTON_CLICKED
, command
);
931 ret
= ancestor
->HandleWindowEvent( button_event
);
936 if (ancestor
->IsTopLevel())
938 ancestor
= ancestor
->GetParent();
941 #endif // wxUSE_ACCEL
943 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
944 // will only be sent if it is not in an accelerator table.
948 KeySym keysym
= gdk_event
->keyval
;
949 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
950 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
953 if ( wxIsAsciiKeysym(keysym
) )
956 key_code
= (unsigned char)keysym
;
958 // gdk_event->string is actually deprecated
959 else if ( gdk_event
->length
== 1 )
961 key_code
= (unsigned char)gdk_event
->string
[0];
967 wxKeyEvent
eventChar(wxEVT_CHAR
, event
);
969 wxLogTrace(TRACE_KEYS
, wxT("Char event: %ld"), key_code
);
971 eventChar
.m_keyCode
= key_code
;
973 // To conform to the docs we need to translate Ctrl-alpha
974 // characters to values in the range 1-26.
975 if ( eventChar
.ControlDown() &&
976 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
978 if ( wxIsLowerChar(key_code
) )
979 eventChar
.m_keyCode
= key_code
- 'a' + 1;
980 if ( wxIsUpperChar(key_code
) )
981 eventChar
.m_keyCode
= key_code
- 'A' + 1;
983 eventChar
.m_uniChar
= event
.m_keyCode
;
987 ret
= win
->HandleWindowEvent(eventChar
);
997 gtk_wxwindow_commit_cb (GtkIMContext
* WXUNUSED(context
),
1001 wxKeyEvent
event( wxEVT_CHAR
);
1003 // take modifiers, cursor position, timestamp etc. from the last
1004 // key_press_event that was fed into Input Method:
1005 if (window
->m_imData
->lastKeyEvent
)
1007 wxFillOtherKeyEventFields(event
,
1008 window
, window
->m_imData
->lastKeyEvent
);
1012 event
.SetEventObject( window
);
1015 const wxString
data(wxGTK_CONV_BACK_SYS(str
));
1019 for( wxString
::const_iterator pstr
= data
.begin(); pstr
!= data
.end(); ++pstr
)
1022 event
.m_uniChar
= *pstr
;
1023 // Backward compatible for ISO-8859-1
1024 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1025 wxLogTrace(TRACE_KEYS
, wxT("IM sent character '%c'"), event
.m_uniChar
);
1027 event
.m_keyCode
= (char)*pstr
;
1028 #endif // wxUSE_UNICODE
1030 // To conform to the docs we need to translate Ctrl-alpha
1031 // characters to values in the range 1-26.
1032 if ( event
.ControlDown() &&
1033 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
1035 if ( wxIsLowerChar(*pstr
) )
1036 event
.m_keyCode
= *pstr
- 'a' + 1;
1037 if ( wxIsUpperChar(*pstr
) )
1038 event
.m_keyCode
= *pstr
- 'A' + 1;
1040 event
.m_keyCode
= *pstr
- 'a' + 1;
1042 event
.m_uniChar
= event
.m_keyCode
;
1046 window
->HandleWindowEvent(event
);
1052 //-----------------------------------------------------------------------------
1053 // "key_release_event" from any window
1054 //-----------------------------------------------------------------------------
1058 gtk_window_key_release_callback( GtkWidget
* WXUNUSED(widget
),
1059 GdkEventKey
*gdk_event
,
1065 if (g_blockEventsOnDrag
)
1068 wxKeyEvent
event( wxEVT_KEY_UP
);
1069 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1071 // unknown key pressed, ignore (the event would be useless anyhow)
1075 return win
->GTKProcessEvent(event
);
1079 // ============================================================================
1081 // ============================================================================
1083 // ----------------------------------------------------------------------------
1084 // mouse event processing helpers
1085 // ----------------------------------------------------------------------------
1087 static void AdjustEventButtonState(wxMouseEvent
& event
)
1089 // GDK reports the old state of the button for a button press event, but
1090 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1091 // for a LEFT_DOWN event, not FALSE, so we will invert
1092 // left/right/middleDown for the corresponding click events
1094 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1095 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1096 (event
.GetEventType() == wxEVT_LEFT_UP
))
1098 event
.m_leftDown
= !event
.m_leftDown
;
1102 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1103 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1104 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1106 event
.m_middleDown
= !event
.m_middleDown
;
1110 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1111 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1112 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1114 event
.m_rightDown
= !event
.m_rightDown
;
1118 if ((event
.GetEventType() == wxEVT_AUX1_DOWN
) ||
1119 (event
.GetEventType() == wxEVT_AUX1_DCLICK
))
1121 event
.m_aux1Down
= true;
1125 if ((event
.GetEventType() == wxEVT_AUX2_DOWN
) ||
1126 (event
.GetEventType() == wxEVT_AUX2_DCLICK
))
1128 event
.m_aux2Down
= true;
1133 // find the window to send the mouse event too
1135 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1140 if (win
->m_wxwindow
)
1142 wxPizza
* pizza
= WX_PIZZA(win
->m_wxwindow
);
1143 xx
+= pizza
->m_scroll_x
;
1144 yy
+= pizza
->m_scroll_y
;
1147 wxWindowList
::compatibility_iterator node
= win
->GetChildren().GetFirst();
1150 wxWindowGTK
*child
= node
->GetData();
1152 node
= node
->GetNext();
1153 if (!child
->IsShown())
1156 if (child
->GTKIsTransparentForMouse())
1158 // wxStaticBox is transparent in the box itself
1159 int xx1
= child
->m_x
;
1160 int yy1
= child
->m_y
;
1161 int xx2
= child
->m_x
+ child
->m_width
;
1162 int yy2
= child
->m_y
+ child
->m_height
;
1165 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1167 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1169 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1171 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1182 if ((child
->m_wxwindow
== NULL
) &&
1183 (child
->m_x
<= xx
) &&
1184 (child
->m_y
<= yy
) &&
1185 (child
->m_x
+child
->m_width
>= xx
) &&
1186 (child
->m_y
+child
->m_height
>= yy
))
1199 // ----------------------------------------------------------------------------
1200 // common event handlers helpers
1201 // ----------------------------------------------------------------------------
1203 bool wxWindowGTK
::GTKProcessEvent(wxEvent
& event
) const
1205 // nothing special at this level
1206 return HandleWindowEvent(event
);
1209 bool wxWindowGTK
::GTKShouldIgnoreEvent() const
1211 return !m_hasVMT
|| g_blockEventsOnDrag
;
1214 int wxWindowGTK
::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1218 if (g_blockEventsOnDrag
)
1220 if (g_blockEventsOnScroll
)
1223 if (!GTKIsOwnWindow(event
->window
))
1229 // overloads for all GDK event types we use here: we need to have this as
1230 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1231 // derives from it in the sense that the structs have the same layout
1232 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1233 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1235 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1238 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1239 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1240 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1242 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1244 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1245 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1249 // all event handlers must have C linkage as they're called from GTK+ C code
1253 //-----------------------------------------------------------------------------
1254 // "button_press_event"
1255 //-----------------------------------------------------------------------------
1258 gtk_window_button_press_callback( GtkWidget
*widget
,
1259 GdkEventButton
*gdk_event
,
1262 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1264 g_lastButtonNumber
= gdk_event
->button
;
1266 // GDK sends surplus button down events
1267 // before a double click event. We
1268 // need to filter these out.
1269 if ((gdk_event
->type
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
))
1271 GdkEvent
*peek_event
= gdk_event_peek();
1274 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1275 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1277 gdk_event_free( peek_event
);
1282 gdk_event_free( peek_event
);
1287 wxEventType event_type
= wxEVT_NULL
;
1289 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1290 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1292 // Reset GDK internal timestamp variables in order to disable GDK
1293 // triple click events. GDK will then next time believe no button has
1294 // been clicked just before, and send a normal button click event.
1295 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1296 display
->button_click_time
[1] = 0;
1297 display
->button_click_time
[0] = 0;
1300 if (gdk_event
->button
== 1)
1302 // note that GDK generates triple click events which are not supported
1303 // by wxWidgets but still have to be passed to the app as otherwise
1304 // clicks would simply go missing
1305 switch (gdk_event
->type
)
1307 // we shouldn't get triple clicks at all for GTK2 because we
1308 // suppress them artificially using the code above but we still
1309 // should map them to something for GTK1 and not just ignore them
1310 // as this would lose clicks
1311 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1312 case GDK_BUTTON_PRESS
:
1313 event_type
= wxEVT_LEFT_DOWN
;
1316 case GDK_2BUTTON_PRESS
:
1317 event_type
= wxEVT_LEFT_DCLICK
;
1321 // just to silence gcc warnings
1325 else if (gdk_event
->button
== 2)
1327 switch (gdk_event
->type
)
1329 case GDK_3BUTTON_PRESS
:
1330 case GDK_BUTTON_PRESS
:
1331 event_type
= wxEVT_MIDDLE_DOWN
;
1334 case GDK_2BUTTON_PRESS
:
1335 event_type
= wxEVT_MIDDLE_DCLICK
;
1342 else if (gdk_event
->button
== 3)
1344 switch (gdk_event
->type
)
1346 case GDK_3BUTTON_PRESS
:
1347 case GDK_BUTTON_PRESS
:
1348 event_type
= wxEVT_RIGHT_DOWN
;
1351 case GDK_2BUTTON_PRESS
:
1352 event_type
= wxEVT_RIGHT_DCLICK
;
1360 else if (gdk_event
->button
== 8)
1362 switch (gdk_event
->type
)
1364 case GDK_3BUTTON_PRESS
:
1365 case GDK_BUTTON_PRESS
:
1366 event_type
= wxEVT_AUX1_DOWN
;
1369 case GDK_2BUTTON_PRESS
:
1370 event_type
= wxEVT_AUX1_DCLICK
;
1378 else if (gdk_event
->button
== 9)
1380 switch (gdk_event
->type
)
1382 case GDK_3BUTTON_PRESS
:
1383 case GDK_BUTTON_PRESS
:
1384 event_type
= wxEVT_AUX2_DOWN
;
1387 case GDK_2BUTTON_PRESS
:
1388 event_type
= wxEVT_AUX2_DCLICK
;
1396 if ( event_type
== wxEVT_NULL
)
1398 // unknown mouse button or click type
1402 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1404 wxMouseEvent
event( event_type
);
1405 InitMouseEvent( win
, event
, gdk_event
);
1407 AdjustEventButtonState(event
);
1409 // find the correct window to send the event to: it may be a different one
1410 // from the one which got it at GTK+ level because some controls don't have
1411 // their own X window and thus cannot get any events.
1412 if ( !g_captureWindow
)
1413 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1415 // reset the event object and id in case win changed.
1416 event
.SetEventObject( win
);
1417 event
.SetId( win
->GetId() );
1419 bool ret
= win
->GTKProcessEvent( event
);
1420 g_lastMouseEvent
= NULL
;
1424 if ((event_type
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&
1425 (gs_currentFocus
!= win
) /* && win->IsFocusable() */)
1430 if (event_type
== wxEVT_RIGHT_DOWN
)
1432 // generate a "context menu" event: this is similar to right mouse
1433 // click under many GUIs except that it is generated differently
1434 // (right up under MSW, ctrl-click under Mac, right down here) and
1436 // (a) it's a command event and so is propagated to the parent
1437 // (b) under some ports it can be generated from kbd too
1438 // (c) it uses screen coords (because of (a))
1439 wxContextMenuEvent
evtCtx(
1442 win
->ClientToScreen(event
.GetPosition()));
1443 evtCtx
.SetEventObject(win
);
1444 return win
->GTKProcessEvent(evtCtx
);
1450 //-----------------------------------------------------------------------------
1451 // "button_release_event"
1452 //-----------------------------------------------------------------------------
1455 gtk_window_button_release_callback( GtkWidget
*WXUNUSED(widget
),
1456 GdkEventButton
*gdk_event
,
1459 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1461 g_lastButtonNumber
= 0;
1463 wxEventType event_type
= wxEVT_NULL
;
1465 switch (gdk_event
->button
)
1468 event_type
= wxEVT_LEFT_UP
;
1472 event_type
= wxEVT_MIDDLE_UP
;
1476 event_type
= wxEVT_RIGHT_UP
;
1480 event_type
= wxEVT_AUX1_UP
;
1484 event_type
= wxEVT_AUX2_UP
;
1488 // unknown button, don't process
1492 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1494 wxMouseEvent
event( event_type
);
1495 InitMouseEvent( win
, event
, gdk_event
);
1497 AdjustEventButtonState(event
);
1499 if ( !g_captureWindow
)
1500 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1502 // reset the event object and id in case win changed.
1503 event
.SetEventObject( win
);
1504 event
.SetId( win
->GetId() );
1506 bool ret
= win
->GTKProcessEvent(event
);
1508 g_lastMouseEvent
= NULL
;
1513 //-----------------------------------------------------------------------------
1514 // "motion_notify_event"
1515 //-----------------------------------------------------------------------------
1518 gtk_window_motion_notify_callback( GtkWidget
* WXUNUSED(widget
),
1519 GdkEventMotion
*gdk_event
,
1522 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1524 if (gdk_event
->is_hint
)
1528 GdkModifierType state
;
1529 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1534 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1536 wxMouseEvent
event( wxEVT_MOTION
);
1537 InitMouseEvent(win
, event
, gdk_event
);
1539 if ( g_captureWindow
)
1541 // synthesise a mouse enter or leave event if needed
1542 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1543 // This seems to be necessary and actually been added to
1544 // GDK itself in version 2.0.X
1547 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1548 if ( hasMouse
!= g_captureWindowHasMouse
)
1550 // the mouse changed window
1551 g_captureWindowHasMouse
= hasMouse
;
1553 wxMouseEvent
eventM(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1554 : wxEVT_LEAVE_WINDOW
);
1555 InitMouseEvent(win
, eventM
, gdk_event
);
1556 eventM
.SetEventObject(win
);
1557 win
->GTKProcessEvent(eventM
);
1562 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1564 // reset the event object and id in case win changed.
1565 event
.SetEventObject( win
);
1566 event
.SetId( win
->GetId() );
1569 if ( !g_captureWindow
)
1571 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1572 if (win
->GTKProcessEvent( cevent
))
1574 win
->SetCursor( cevent
.GetCursor() );
1578 bool ret
= win
->GTKProcessEvent(event
);
1580 g_lastMouseEvent
= NULL
;
1585 //-----------------------------------------------------------------------------
1586 // "scroll_event" (mouse wheel event)
1587 //-----------------------------------------------------------------------------
1590 window_scroll_event_hscrollbar(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1592 if (gdk_event
->direction
!= GDK_SCROLL_LEFT
&&
1593 gdk_event
->direction
!= GDK_SCROLL_RIGHT
)
1598 GtkRange
*range
= win
->m_scrollBar
[wxWindow
::ScrollDir_Horz
];
1600 if (range
&& gtk_widget_get_visible(GTK_WIDGET(range
)))
1602 GtkAdjustment
* adj
= gtk_range_get_adjustment(range
);
1603 double delta
= gtk_adjustment_get_step_increment(adj
) * 3;
1604 if (gdk_event
->direction
== GDK_SCROLL_LEFT
)
1607 gtk_range_set_value(range
, gtk_adjustment_get_value(adj
) + delta
);
1616 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1618 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1619 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1624 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1625 InitMouseEvent(win
, event
, gdk_event
);
1627 // FIXME: Get these values from GTK or GDK
1628 event
.m_linesPerAction
= 3;
1629 event
.m_wheelDelta
= 120;
1630 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1631 event
.m_wheelRotation
= 120;
1633 event
.m_wheelRotation
= -120;
1635 if (win
->GTKProcessEvent(event
))
1638 GtkRange
*range
= win
->m_scrollBar
[wxWindow
::ScrollDir_Vert
];
1640 if (range
&& gtk_widget_get_visible(GTK_WIDGET(range
)))
1642 GtkAdjustment
* adj
= gtk_range_get_adjustment(range
);
1643 double delta
= gtk_adjustment_get_step_increment(adj
) * 3;
1644 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1647 gtk_range_set_value(range
, gtk_adjustment_get_value(adj
) + delta
);
1655 //-----------------------------------------------------------------------------
1657 //-----------------------------------------------------------------------------
1659 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1661 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1662 event
.SetEventObject(win
);
1663 return win
->GTKProcessEvent(event
);
1666 //-----------------------------------------------------------------------------
1668 //-----------------------------------------------------------------------------
1671 gtk_window_focus_in_callback( GtkWidget
* WXUNUSED(widget
),
1672 GdkEventFocus
*WXUNUSED(event
),
1675 return win
->GTKHandleFocusIn();
1678 //-----------------------------------------------------------------------------
1679 // "focus_out_event"
1680 //-----------------------------------------------------------------------------
1683 gtk_window_focus_out_callback( GtkWidget
* WXUNUSED(widget
),
1684 GdkEventFocus
* WXUNUSED(gdk_event
),
1687 return win
->GTKHandleFocusOut();
1690 //-----------------------------------------------------------------------------
1692 //-----------------------------------------------------------------------------
1695 wx_window_focus_callback(GtkWidget
*widget
,
1696 GtkDirectionType
WXUNUSED(direction
),
1699 // the default handler for focus signal in GtkScrolledWindow sets
1700 // focus to the window itself even if it doesn't accept focus, i.e. has no
1701 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1702 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1703 // any children which might accept focus (we know we don't accept the focus
1704 // ourselves as this signal is only connected in this case)
1705 if ( win
->GetChildren().empty() )
1706 g_signal_stop_emission_by_name(widget
, "focus");
1708 // we didn't change the focus
1712 //-----------------------------------------------------------------------------
1713 // "enter_notify_event"
1714 //-----------------------------------------------------------------------------
1717 gtk_window_enter_callback( GtkWidget
*widget
,
1718 GdkEventCrossing
*gdk_event
,
1721 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1723 // Event was emitted after a grab
1724 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1728 GdkModifierType state
= (GdkModifierType
)0;
1730 gdk_window_get_pointer(gtk_widget_get_window(widget
), &x
, &y
, &state
);
1732 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1733 InitMouseEvent(win
, event
, gdk_event
);
1734 wxPoint pt
= win
->GetClientAreaOrigin();
1735 event
.m_x
= x
+ pt
.x
;
1736 event
.m_y
= y
+ pt
.y
;
1738 if ( !g_captureWindow
)
1740 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1741 if (win
->GTKProcessEvent( cevent
))
1743 win
->SetCursor( cevent
.GetCursor() );
1747 return win
->GTKProcessEvent(event
);
1750 //-----------------------------------------------------------------------------
1751 // "leave_notify_event"
1752 //-----------------------------------------------------------------------------
1755 gtk_window_leave_callback( GtkWidget
*widget
,
1756 GdkEventCrossing
*gdk_event
,
1759 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1761 // Event was emitted after an ungrab
1762 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1764 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1768 GdkModifierType state
= (GdkModifierType
)0;
1770 gdk_window_get_pointer(gtk_widget_get_window(widget
), &x
, &y
, &state
);
1772 InitMouseEvent(win
, event
, gdk_event
);
1774 return win
->GTKProcessEvent(event
);
1777 //-----------------------------------------------------------------------------
1778 // "value_changed" from scrollbar
1779 //-----------------------------------------------------------------------------
1782 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
1784 wxEventType eventType
= win
->GTKGetScrollEventType(range
);
1785 if (eventType
!= wxEVT_NULL
)
1787 // Convert scroll event type to scrollwin event type
1788 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
1790 // find the scrollbar which generated the event
1791 wxWindowGTK
::ScrollDir dir
= win
->ScrollDirFromRange(range
);
1793 // generate the corresponding wx event
1794 const int orient
= wxWindow
::OrientFromScrollDir(dir
);
1795 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
1796 event
.SetEventObject(win
);
1798 win
->GTKProcessEvent(event
);
1802 //-----------------------------------------------------------------------------
1803 // "button_press_event" from scrollbar
1804 //-----------------------------------------------------------------------------
1807 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
1809 g_blockEventsOnScroll
= true;
1810 win
->m_mouseButtonDown
= true;
1815 //-----------------------------------------------------------------------------
1816 // "event_after" from scrollbar
1817 //-----------------------------------------------------------------------------
1820 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
1822 if (event
->type
== GDK_BUTTON_RELEASE
)
1824 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1826 const int orient
= wxWindow
::OrientFromScrollDir(
1827 win
->ScrollDirFromRange(range
));
1828 wxScrollWinEvent
evt(wxEVT_SCROLLWIN_THUMBRELEASE
,
1829 win
->GetScrollPos(orient
), orient
);
1830 evt
.SetEventObject(win
);
1831 win
->GTKProcessEvent(evt
);
1835 //-----------------------------------------------------------------------------
1836 // "button_release_event" from scrollbar
1837 //-----------------------------------------------------------------------------
1840 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
1842 g_blockEventsOnScroll
= false;
1843 win
->m_mouseButtonDown
= false;
1844 // If thumb tracking
1845 if (win
->m_isScrolling
)
1847 win
->m_isScrolling
= false;
1848 // Hook up handler to send thumb release event after this emission is finished.
1849 // To allow setting scroll position from event handler, sending event must
1850 // be deferred until after the GtkRange handler for this signal has run
1851 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1857 //-----------------------------------------------------------------------------
1858 // "realize" from m_widget
1859 //-----------------------------------------------------------------------------
1862 gtk_window_realized_callback(GtkWidget
* WXUNUSED(widget
), wxWindowGTK
* win
)
1864 win
->GTKHandleRealized();
1867 //-----------------------------------------------------------------------------
1868 // "unrealize" from m_wxwindow
1869 //-----------------------------------------------------------------------------
1871 static void unrealize(GtkWidget
*, wxWindowGTK
* win
)
1874 gtk_im_context_set_client_window(win
->m_imData
->context
, NULL
);
1877 //-----------------------------------------------------------------------------
1878 // "size_allocate" from m_wxwindow or m_widget
1879 //-----------------------------------------------------------------------------
1882 size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxWindow
* win
)
1884 int w
= alloc
->width
;
1885 int h
= alloc
->height
;
1886 if (win
->m_wxwindow
)
1888 int border_x
, border_y
;
1889 WX_PIZZA(win
->m_wxwindow
)->get_border_widths(border_x
, border_y
);
1895 if (win
->m_oldClientWidth
!= w
|| win
->m_oldClientHeight
!= h
)
1897 win
->m_oldClientWidth
= w
;
1898 win
->m_oldClientHeight
= h
;
1899 // this callback can be connected to m_wxwindow,
1900 // so always get size from m_widget->allocation
1902 gtk_widget_get_allocation(win
->m_widget
, &a
);
1903 win
->m_width
= a
.width
;
1904 win
->m_height
= a
.height
;
1905 if (!win
->m_nativeSizeEvent
)
1907 wxSizeEvent
event(win
->GetSize(), win
->GetId());
1908 event
.SetEventObject(win
);
1909 win
->GTKProcessEvent(event
);
1914 //-----------------------------------------------------------------------------
1916 //-----------------------------------------------------------------------------
1918 #if GTK_CHECK_VERSION(2, 8, 0)
1920 gtk_window_grab_broken( GtkWidget
*,
1921 GdkEventGrabBroken
*event
,
1924 // Mouse capture has been lost involuntarily, notify the application
1925 if(!event
->keyboard
&& wxWindow
::GetCapture() == win
)
1927 wxMouseCaptureLostEvent
evt( win
->GetId() );
1928 evt
.SetEventObject( win
);
1929 win
->HandleWindowEvent( evt
);
1935 //-----------------------------------------------------------------------------
1937 //-----------------------------------------------------------------------------
1940 void gtk_window_style_set_callback( GtkWidget
*WXUNUSED(widget
),
1941 GtkStyle
*previous_style
,
1944 if (win
&& previous_style
)
1946 wxSysColourChangedEvent event
;
1947 event
.SetEventObject(win
);
1949 win
->GTKProcessEvent( event
);
1955 void wxWindowGTK
::GTKHandleRealized()
1959 gtk_im_context_set_client_window
1962 m_wxwindow ?
GTKGetDrawingWindow()
1963 : gtk_widget_get_window(m_widget
)
1967 // We cannot set colours and fonts before the widget
1968 // been realized, so we do this directly after realization
1969 // or otherwise in idle time
1971 if (m_needsStyleChange
)
1973 SetBackgroundStyle(GetBackgroundStyle());
1974 m_needsStyleChange
= false;
1977 wxWindowCreateEvent
event(static_cast<wxWindow
*>(this));
1978 event
.SetEventObject( this );
1979 GTKProcessEvent( event
);
1981 GTKUpdateCursor(true, false);
1984 // ----------------------------------------------------------------------------
1985 // this wxWindowBase function is implemented here (in platform-specific file)
1986 // because it is static and so couldn't be made virtual
1987 // ----------------------------------------------------------------------------
1989 wxWindow
*wxWindowBase
::DoFindFocus()
1991 wxWindowGTK
*focus
= gs_pendingFocus ? gs_pendingFocus
: gs_currentFocus
;
1992 // the cast is necessary when we compile in wxUniversal mode
1993 return static_cast<wxWindow
*>(focus
);
1996 void wxWindowGTK
::AddChildGTK(wxWindowGTK
* child
)
1998 wxASSERT_MSG(m_wxwindow
, "Cannot add a child to a window without a client area");
2000 // the window might have been scrolled already, we
2001 // have to adapt the position
2002 wxPizza
* pizza
= WX_PIZZA(m_wxwindow
);
2003 child
->m_x
+= pizza
->m_scroll_x
;
2004 child
->m_y
+= pizza
->m_scroll_y
;
2006 gtk_widget_set_size_request(
2007 child
->m_widget
, child
->m_width
, child
->m_height
);
2008 pizza
->put(child
->m_widget
, child
->m_x
, child
->m_y
);
2011 //-----------------------------------------------------------------------------
2013 //-----------------------------------------------------------------------------
2015 wxWindow
*wxGetActiveWindow()
2017 return wxWindow
::FindFocus();
2021 wxMouseState
wxGetMouseState()
2027 GdkModifierType mask
;
2029 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2033 ms
.SetLeftDown((mask
& GDK_BUTTON1_MASK
) != 0);
2034 ms
.SetMiddleDown((mask
& GDK_BUTTON2_MASK
) != 0);
2035 ms
.SetRightDown((mask
& GDK_BUTTON3_MASK
) != 0);
2036 // see the comment in InitMouseEvent()
2037 ms
.SetAux1Down((mask
& GDK_BUTTON4_MASK
) != 0);
2038 ms
.SetAux2Down((mask
& GDK_BUTTON5_MASK
) != 0);
2040 ms
.SetControlDown((mask
& GDK_CONTROL_MASK
) != 0);
2041 ms
.SetShiftDown((mask
& GDK_SHIFT_MASK
) != 0);
2042 ms
.SetAltDown((mask
& GDK_MOD1_MASK
) != 0);
2043 ms
.SetMetaDown((mask
& GDK_META_MASK
) != 0);
2048 //-----------------------------------------------------------------------------
2050 //-----------------------------------------------------------------------------
2052 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2054 #ifdef __WXUNIVERSAL__
2055 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2056 #endif // __WXUNIVERSAL__
2058 void wxWindowGTK
::Init()
2063 m_focusWidget
= NULL
;
2073 m_showOnIdle
= false;
2076 m_nativeSizeEvent
= false;
2078 m_isScrolling
= false;
2079 m_mouseButtonDown
= false;
2081 // initialize scrolling stuff
2082 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2084 m_scrollBar
[dir
] = NULL
;
2085 m_scrollPos
[dir
] = 0;
2089 m_oldClientHeight
= 0;
2091 m_clipPaintRegion
= false;
2093 m_needsStyleChange
= false;
2095 m_cursor
= *wxSTANDARD_CURSOR
;
2098 m_dirtyTabOrder
= false;
2101 wxWindowGTK
::wxWindowGTK()
2106 wxWindowGTK
::wxWindowGTK( wxWindow
*parent
,
2111 const wxString
&name
)
2115 Create( parent
, id
, pos
, size
, style
, name
);
2118 bool wxWindowGTK
::Create( wxWindow
*parent
,
2123 const wxString
&name
)
2125 // Get default border
2126 wxBorder border
= GetBorder(style
);
2128 style
&= ~wxBORDER_MASK
;
2131 if (!PreCreation( parent
, pos
, size
) ||
2132 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2134 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2138 // We should accept the native look
2140 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2141 scroll_class
->scrollbar_spacing
= 0;
2145 m_wxwindow
= wxPizza
::New(m_windowStyle
);
2146 #ifndef __WXUNIVERSAL__
2147 if (HasFlag(wxPizza
::BORDER_STYLES
))
2149 g_signal_connect(m_wxwindow
, "parent_set",
2150 G_CALLBACK(parent_set
), this);
2153 if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
))
2154 m_widget
= m_wxwindow
;
2157 m_widget
= gtk_scrolled_window_new( NULL
, NULL
);
2159 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2161 // There is a conflict with default bindings at GTK+
2162 // level between scrolled windows and notebooks both of which want to use
2163 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2164 // direction and notebooks for changing pages -- we decide that if we don't
2165 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2166 // means we can get working keyboard navigation in notebooks
2167 if ( !HasFlag(wxHSCROLL
) )
2170 bindings
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
));
2173 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
);
2174 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
);
2178 if (HasFlag(wxALWAYS_SHOW_SB
))
2180 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
2184 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2187 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(gtk_scrolled_window_get_hscrollbar(scrolledWindow
));
2188 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(gtk_scrolled_window_get_vscrollbar(scrolledWindow
));
2189 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2190 gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE
);
2192 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2194 // connect various scroll-related events
2195 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2197 // these handlers block mouse events to any window during scrolling
2198 // such as motion events and prevent GTK and wxWidgets from fighting
2199 // over where the slider should be
2200 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2201 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2202 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2203 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2205 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2206 G_CALLBACK(gtk_scrollbar_event_after
), this);
2207 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2209 // these handlers get notified when scrollbar slider moves
2210 g_signal_connect_after(m_scrollBar
[dir
], "value_changed",
2211 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2214 gtk_widget_show( m_wxwindow
);
2216 g_object_ref(m_widget
);
2219 m_parent
->DoAddChild( this );
2221 m_focusWidget
= m_wxwindow
;
2223 SetCanFocus(AcceptsFocus());
2230 wxWindowGTK
::~wxWindowGTK()
2234 if (gs_currentFocus
== this)
2235 gs_currentFocus
= NULL
;
2236 if (gs_pendingFocus
== this)
2237 gs_pendingFocus
= NULL
;
2239 if ( gs_deferredFocusOut
== this )
2240 gs_deferredFocusOut
= NULL
;
2244 // destroy children before destroying this window itself
2247 // unhook focus handlers to prevent stray events being
2248 // propagated to this (soon to be) dead object
2249 if (m_focusWidget
!= NULL
)
2251 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2252 (gpointer
) gtk_window_focus_in_callback
,
2254 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2255 (gpointer
) gtk_window_focus_out_callback
,
2262 // delete before the widgets to avoid a crash on solaris
2266 // avoid problem with GTK+ 2.18 where a frozen window causes the whole
2267 // TLW to be frozen, and if the window is then destroyed, nothing ever
2268 // gets painted again
2274 // Note that gtk_widget_destroy() does not destroy the widget, it just
2275 // emits the "destroy" signal. The widget is not actually destroyed
2276 // until its reference count drops to zero.
2277 gtk_widget_destroy(m_widget
);
2278 // Release our reference, should be the last one
2279 g_object_unref(m_widget
);
2285 bool wxWindowGTK
::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2287 if ( GTKNeedsParent() )
2289 wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") );
2292 // Use either the given size, or the default if -1 is given.
2293 // See wxWindowBase for these functions.
2294 m_width
= WidthDefault(size
.x
) ;
2295 m_height
= HeightDefault(size
.y
);
2303 void wxWindowGTK
::PostCreation()
2305 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2311 // these get reported to wxWidgets -> wxPaintEvent
2313 g_signal_connect (m_wxwindow
, "expose_event",
2314 G_CALLBACK (gtk_window_expose_callback
), this);
2316 if (GetLayoutDirection() == wxLayout_LeftToRight
)
2317 gtk_widget_set_redraw_on_allocate(m_wxwindow
, HasFlag(wxFULL_REPAINT_ON_RESIZE
));
2320 // Create input method handler
2321 m_imData
= new wxGtkIMData
;
2323 // Cannot handle drawing preedited text yet
2324 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2326 g_signal_connect (m_imData
->context
, "commit",
2327 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2328 g_signal_connect(m_wxwindow
, "unrealize", G_CALLBACK(unrealize
), this);
2333 if (!GTK_IS_WINDOW(m_widget
))
2335 if (m_focusWidget
== NULL
)
2336 m_focusWidget
= m_widget
;
2340 g_signal_connect (m_focusWidget
, "focus_in_event",
2341 G_CALLBACK (gtk_window_focus_in_callback
), this);
2342 g_signal_connect (m_focusWidget
, "focus_out_event",
2343 G_CALLBACK (gtk_window_focus_out_callback
), this);
2347 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2348 G_CALLBACK (gtk_window_focus_in_callback
), this);
2349 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2350 G_CALLBACK (gtk_window_focus_out_callback
), this);
2354 if ( !AcceptsFocusFromKeyboard() )
2358 g_signal_connect(m_widget
, "focus",
2359 G_CALLBACK(wx_window_focus_callback
), this);
2362 // connect to the various key and mouse handlers
2364 GtkWidget
*connect_widget
= GetConnectWidget();
2366 ConnectWidget( connect_widget
);
2368 // We cannot set colours, fonts and cursors before the widget has been
2369 // realized, so we do this directly after realization -- unless the widget
2370 // was in fact realized already.
2371 if ( gtk_widget_get_realized(connect_widget
) )
2373 gtk_window_realized_callback(connect_widget
, this);
2377 g_signal_connect (connect_widget
, "realize",
2378 G_CALLBACK (gtk_window_realized_callback
), this);
2383 g_signal_connect(m_wxwindow ? m_wxwindow
: m_widget
, "size_allocate",
2384 G_CALLBACK(size_allocate
), this);
2387 #if GTK_CHECK_VERSION(2, 8, 0)
2388 if ( gtk_check_version(2,8,0) == NULL
)
2390 // Make sure we can notify the app when mouse capture is lost
2393 g_signal_connect (m_wxwindow
, "grab_broken_event",
2394 G_CALLBACK (gtk_window_grab_broken
), this);
2397 if ( connect_widget
!= m_wxwindow
)
2399 g_signal_connect (connect_widget
, "grab_broken_event",
2400 G_CALLBACK (gtk_window_grab_broken
), this);
2403 #endif // GTK+ >= 2.8
2405 if ( GTKShouldConnectSizeRequest() )
2407 // This is needed if we want to add our windows into native
2408 // GTK controls, such as the toolbar. With this callback, the
2409 // toolbar gets to know the correct size (the one set by the
2410 // programmer). Sadly, it misbehaves for wxComboBox.
2411 g_signal_connect (m_widget
, "size_request",
2412 G_CALLBACK (wxgtk_window_size_request_callback
),
2416 InheritAttributes();
2420 SetLayoutDirection(wxLayout_Default
);
2422 // unless the window was created initially hidden (i.e. Hide() had been
2423 // called before Create()), we should show it at GTK+ level as well
2425 gtk_widget_show( m_widget
);
2429 wxWindowGTK
::GTKConnectWidget(const char *signal
, wxGTKCallback callback
)
2431 return g_signal_connect(m_widget
, signal
, callback
, this);
2434 void wxWindowGTK
::ConnectWidget( GtkWidget
*widget
)
2436 g_signal_connect (widget
, "key_press_event",
2437 G_CALLBACK (gtk_window_key_press_callback
), this);
2438 g_signal_connect (widget
, "key_release_event",
2439 G_CALLBACK (gtk_window_key_release_callback
), this);
2440 g_signal_connect (widget
, "button_press_event",
2441 G_CALLBACK (gtk_window_button_press_callback
), this);
2442 g_signal_connect (widget
, "button_release_event",
2443 G_CALLBACK (gtk_window_button_release_callback
), this);
2444 g_signal_connect (widget
, "motion_notify_event",
2445 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2447 g_signal_connect (widget
, "scroll_event",
2448 G_CALLBACK (window_scroll_event
), this);
2449 if (m_scrollBar
[ScrollDir_Horz
])
2450 g_signal_connect (m_scrollBar
[ScrollDir_Horz
], "scroll_event",
2451 G_CALLBACK (window_scroll_event_hscrollbar
), this);
2452 if (m_scrollBar
[ScrollDir_Vert
])
2453 g_signal_connect (m_scrollBar
[ScrollDir_Vert
], "scroll_event",
2454 G_CALLBACK (window_scroll_event
), this);
2456 g_signal_connect (widget
, "popup_menu",
2457 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2458 g_signal_connect (widget
, "enter_notify_event",
2459 G_CALLBACK (gtk_window_enter_callback
), this);
2460 g_signal_connect (widget
, "leave_notify_event",
2461 G_CALLBACK (gtk_window_leave_callback
), this);
2463 if (IsTopLevel() && m_wxwindow
)
2464 g_signal_connect (m_wxwindow
, "style_set",
2465 G_CALLBACK (gtk_window_style_set_callback
), this);
2468 bool wxWindowGTK
::Destroy()
2472 return wxWindowBase
::Destroy();
2475 void wxWindowGTK
::DoMoveWindow(int x
, int y
, int width
, int height
)
2477 gtk_widget_set_size_request(m_widget
, width
, height
);
2479 // inform the parent to perform the move
2480 wxASSERT_MSG(m_parent
&& m_parent
->m_wxwindow
,
2481 "the parent window has no client area?");
2482 WX_PIZZA(m_parent
->m_wxwindow
)->move(m_widget
, x
, y
);
2485 void wxWindowGTK
::ConstrainSize()
2488 // GPE's window manager doesn't like size hints at all, esp. when the user
2489 // has to use the virtual keyboard, so don't constrain size there
2493 const wxSize minSize
= GetMinSize();
2494 const wxSize maxSize
= GetMaxSize();
2495 if (minSize
.x
> 0 && m_width
< minSize
.x
) m_width
= minSize
.x
;
2496 if (minSize
.y
> 0 && m_height
< minSize
.y
) m_height
= minSize
.y
;
2497 if (maxSize
.x
> 0 && m_width
> maxSize
.x
) m_width
= maxSize
.x
;
2498 if (maxSize
.y
> 0 && m_height
> maxSize
.y
) m_height
= maxSize
.y
;
2502 void wxWindowGTK
::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2504 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2505 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2507 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0 && (x
== -1 || y
== -1))
2509 int currentX
, currentY
;
2510 GetPosition(¤tX
, ¤tY
);
2516 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2518 // calculate the best size if we should auto size the window
2519 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2520 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2522 const wxSize sizeBest
= GetBestSize();
2523 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2525 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2526 height
= sizeBest
.y
;
2529 const wxSize
oldSize(m_width
, m_height
);
2535 if (m_parent
->m_wxwindow
)
2537 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2538 m_x
= x
+ pizza
->m_scroll_x
;
2539 m_y
= y
+ pizza
->m_scroll_y
;
2541 int left_border
= 0;
2542 int right_border
= 0;
2544 int bottom_border
= 0;
2546 /* the default button has a border around it */
2547 if (gtk_widget_get_can_default(m_widget
))
2549 GtkBorder
*default_border
= NULL
;
2550 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2553 left_border
+= default_border
->left
;
2554 right_border
+= default_border
->right
;
2555 top_border
+= default_border
->top
;
2556 bottom_border
+= default_border
->bottom
;
2557 gtk_border_free( default_border
);
2561 DoMoveWindow( m_x
- left_border
,
2563 m_width
+left_border
+right_border
,
2564 m_height
+top_border
+bottom_border
);
2567 if (m_width
!= oldSize
.x
|| m_height
!= oldSize
.y
)
2569 // update these variables to keep size_allocate handler
2570 // from sending another size event for this change
2571 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2573 gtk_widget_queue_resize(m_widget
);
2574 if (!m_nativeSizeEvent
)
2576 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2577 event
.SetEventObject( this );
2578 HandleWindowEvent( event
);
2581 if (sizeFlags
& wxSIZE_FORCE_EVENT
)
2583 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2584 event
.SetEventObject( this );
2585 HandleWindowEvent( event
);
2589 bool wxWindowGTK
::GTKShowFromOnIdle()
2591 if (IsShown() && m_showOnIdle
&& !gtk_widget_get_visible (m_widget
))
2593 GtkAllocation alloc
;
2596 alloc
.width
= m_width
;
2597 alloc
.height
= m_height
;
2598 gtk_widget_size_allocate( m_widget
, &alloc
);
2599 gtk_widget_show( m_widget
);
2600 wxShowEvent
eventShow(GetId(), true);
2601 eventShow
.SetEventObject(this);
2602 HandleWindowEvent(eventShow
);
2603 m_showOnIdle
= false;
2610 void wxWindowGTK
::OnInternalIdle()
2612 if ( gs_deferredFocusOut
)
2613 GTKHandleDeferredFocusOut();
2615 // Check if we have to show window now
2616 if (GTKShowFromOnIdle()) return;
2618 if ( m_dirtyTabOrder
)
2620 m_dirtyTabOrder
= false;
2624 // Update style if the window was not yet realized when
2625 // SetBackgroundStyle() was called
2626 if (m_needsStyleChange
)
2628 SetBackgroundStyle(GetBackgroundStyle());
2629 m_needsStyleChange
= false;
2632 wxWindowBase
::OnInternalIdle();
2635 void wxWindowGTK
::DoGetSize( int *width
, int *height
) const
2637 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2639 if (width
) (*width
) = m_width
;
2640 if (height
) (*height
) = m_height
;
2643 void wxWindowGTK
::DoSetClientSize( int width
, int height
)
2645 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2647 const wxSize size
= GetSize();
2648 const wxSize clientSize
= GetClientSize();
2649 SetSize(width
+ (size
.x
- clientSize
.x
), height
+ (size
.y
- clientSize
.y
));
2652 void wxWindowGTK
::DoGetClientSize( int *width
, int *height
) const
2654 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2661 // if window is scrollable, account for scrollbars
2662 if ( GTK_IS_SCROLLED_WINDOW(m_widget
) )
2664 GtkPolicyType policy
[ScrollDir_Max
];
2665 gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(m_widget
),
2666 &policy
[ScrollDir_Horz
],
2667 &policy
[ScrollDir_Vert
]);
2669 for ( int i
= 0; i
< ScrollDir_Max
; i
++ )
2671 // don't account for the scrollbars we don't have
2672 GtkRange
* const range
= m_scrollBar
[i
];
2676 // nor for the ones we have but don't current show
2677 switch ( policy
[i
] )
2679 case GTK_POLICY_NEVER
:
2680 // never shown so doesn't take any place
2683 case GTK_POLICY_ALWAYS
:
2684 // no checks necessary
2687 case GTK_POLICY_AUTOMATIC
:
2688 // may be shown or not, check
2689 GtkAdjustment
*adj
= gtk_range_get_adjustment(range
);
2690 if (gtk_adjustment_get_upper(adj
) <= gtk_adjustment_get_page_size(adj
))
2694 GtkScrolledWindowClass
*scroll_class
=
2695 GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2698 gtk_widget_size_request(GTK_WIDGET(range
), &req
);
2699 if (i
== ScrollDir_Horz
)
2700 h
-= req
.height
+ scroll_class
->scrollbar_spacing
;
2702 w
-= req
.width
+ scroll_class
->scrollbar_spacing
;
2706 const wxSize sizeBorders
= DoGetBorderSize();
2716 if (width
) *width
= w
;
2717 if (height
) *height
= h
;
2720 wxSize wxWindowGTK
::DoGetBorderSize() const
2723 return wxWindowBase
::DoGetBorderSize();
2726 WX_PIZZA(m_wxwindow
)->get_border_widths(x
, y
);
2728 return 2*wxSize(x
, y
);
2731 void wxWindowGTK
::DoGetPosition( int *x
, int *y
) const
2733 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2737 if (!IsTopLevel() && m_parent
&& m_parent
->m_wxwindow
)
2739 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2740 dx
= pizza
->m_scroll_x
;
2741 dy
= pizza
->m_scroll_y
;
2744 if (m_x
== -1 && m_y
== -1)
2746 GdkWindow
*source
= NULL
;
2748 source
= gtk_widget_get_window(m_wxwindow
);
2750 source
= gtk_widget_get_window(m_widget
);
2756 gdk_window_get_origin( source
, &org_x
, &org_y
);
2759 m_parent
->ScreenToClient(&org_x
, &org_y
);
2761 const_cast<wxWindowGTK
*>(this)->m_x
= org_x
;
2762 const_cast<wxWindowGTK
*>(this)->m_y
= org_y
;
2766 if (x
) (*x
) = m_x
- dx
;
2767 if (y
) (*y
) = m_y
- dy
;
2770 void wxWindowGTK
::DoClientToScreen( int *x
, int *y
) const
2772 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2774 if (gtk_widget_get_window(m_widget
) == NULL
) return;
2776 GdkWindow
*source
= NULL
;
2778 source
= gtk_widget_get_window(m_wxwindow
);
2780 source
= gtk_widget_get_window(m_widget
);
2784 gdk_window_get_origin( source
, &org_x
, &org_y
);
2788 if (!gtk_widget_get_has_window(m_widget
))
2791 gtk_widget_get_allocation(m_widget
, &a
);
2800 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2801 *x
= (GetClientSize().x
- *x
) + org_x
;
2809 void wxWindowGTK
::DoScreenToClient( int *x
, int *y
) const
2811 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2813 if (!gtk_widget_get_realized(m_widget
)) return;
2815 GdkWindow
*source
= NULL
;
2817 source
= gtk_widget_get_window(m_wxwindow
);
2819 source
= gtk_widget_get_window(m_widget
);
2823 gdk_window_get_origin( source
, &org_x
, &org_y
);
2827 if (!gtk_widget_get_has_window(m_widget
))
2830 gtk_widget_get_allocation(m_widget
, &a
);
2838 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2839 *x
= (GetClientSize().x
- *x
) - org_x
;
2846 bool wxWindowGTK
::Show( bool show
)
2848 if ( !wxWindowBase
::Show(show
) )
2854 // notice that we may call Hide() before the window is created and this is
2855 // actually useful to create it hidden initially -- but we can't call
2856 // Show() before it is created
2859 wxASSERT_MSG( !show
, "can't show invalid window" );
2867 // defer until later
2871 gtk_widget_show(m_widget
);
2875 gtk_widget_hide(m_widget
);
2878 wxShowEvent
eventShow(GetId(), show
);
2879 eventShow
.SetEventObject(this);
2880 HandleWindowEvent(eventShow
);
2885 void wxWindowGTK
::DoEnable( bool enable
)
2887 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2889 gtk_widget_set_sensitive( m_widget
, enable
);
2890 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2891 gtk_widget_set_sensitive( m_wxwindow
, enable
);
2894 int wxWindowGTK
::GetCharHeight() const
2896 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
2898 wxFont font
= GetFont();
2899 wxCHECK_MSG( font
.IsOk(), 12, wxT("invalid font") );
2901 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2906 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2907 PangoLayout
*layout
= pango_layout_new(context
);
2908 pango_layout_set_font_description(layout
, desc
);
2909 pango_layout_set_text(layout
, "H", 1);
2910 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2912 PangoRectangle rect
;
2913 pango_layout_line_get_extents(line
, NULL
, &rect
);
2915 g_object_unref (layout
);
2917 return (int) PANGO_PIXELS(rect
.height
);
2920 int wxWindowGTK
::GetCharWidth() const
2922 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
2924 wxFont font
= GetFont();
2925 wxCHECK_MSG( font
.IsOk(), 8, wxT("invalid font") );
2927 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2932 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2933 PangoLayout
*layout
= pango_layout_new(context
);
2934 pango_layout_set_font_description(layout
, desc
);
2935 pango_layout_set_text(layout
, "g", 1);
2936 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2938 PangoRectangle rect
;
2939 pango_layout_line_get_extents(line
, NULL
, &rect
);
2941 g_object_unref (layout
);
2943 return (int) PANGO_PIXELS(rect
.width
);
2946 void wxWindowGTK
::DoGetTextExtent( const wxString
& string
,
2950 int *externalLeading
,
2951 const wxFont
*theFont
) const
2953 wxFont fontToUse
= theFont ?
*theFont
: GetFont();
2955 wxCHECK_RET( fontToUse
.IsOk(), wxT("invalid font") );
2964 PangoContext
*context
= NULL
;
2966 context
= gtk_widget_get_pango_context( m_widget
);
2975 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
2976 PangoLayout
*layout
= pango_layout_new(context
);
2977 pango_layout_set_font_description(layout
, desc
);
2979 const wxCharBuffer data
= wxGTK_CONV( string
);
2981 pango_layout_set_text(layout
, data
, strlen(data
));
2984 PangoRectangle rect
;
2985 pango_layout_get_extents(layout
, NULL
, &rect
);
2987 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
2988 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
2991 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
2992 int baseline
= pango_layout_iter_get_baseline(iter
);
2993 pango_layout_iter_free(iter
);
2994 *descent
= *y
- PANGO_PIXELS(baseline
);
2996 if (externalLeading
) (*externalLeading
) = 0; // ??
2998 g_object_unref (layout
);
3001 void wxWindowGTK
::GTKDisableFocusOutEvent()
3003 g_signal_handlers_block_by_func( m_focusWidget
,
3004 (gpointer
) gtk_window_focus_out_callback
, this);
3007 void wxWindowGTK
::GTKEnableFocusOutEvent()
3009 g_signal_handlers_unblock_by_func( m_focusWidget
,
3010 (gpointer
) gtk_window_focus_out_callback
, this);
3013 bool wxWindowGTK
::GTKHandleFocusIn()
3015 // Disable default focus handling for custom windows since the default GTK+
3016 // handler issues a repaint
3017 const bool retval
= m_wxwindow ?
true : false;
3020 // NB: if there's still unprocessed deferred focus-out event (see
3021 // GTKHandleFocusOut() for explanation), we need to process it first so
3022 // that the order of focus events -- focus-out first, then focus-in
3023 // elsewhere -- is preserved
3024 if ( gs_deferredFocusOut
)
3026 if ( GTKNeedsToFilterSameWindowFocus() &&
3027 gs_deferredFocusOut
== this )
3029 // GTK+ focus changed from this wxWindow back to itself, so don't
3030 // emit any events at all
3031 wxLogTrace(TRACE_FOCUS
,
3032 "filtered out spurious focus change within %s(%p, %s)",
3033 GetClassInfo()->GetClassName(), this, GetLabel());
3034 gs_deferredFocusOut
= NULL
;
3038 // otherwise we need to send focus-out first
3039 wxASSERT_MSG ( gs_deferredFocusOut
!= this,
3040 "GTKHandleFocusIn(GTKFocus_Normal) called even though focus changed back to itself - derived class should handle this" );
3041 GTKHandleDeferredFocusOut();
3045 wxLogTrace(TRACE_FOCUS
,
3046 "handling focus_in event for %s(%p, %s)",
3047 GetClassInfo()->GetClassName(), this, GetLabel());
3050 gtk_im_context_focus_in(m_imData
->context
);
3052 gs_currentFocus
= this;
3053 gs_pendingFocus
= NULL
;
3056 // caret needs to be informed about focus change
3057 wxCaret
*caret
= GetCaret();
3060 caret
->OnSetFocus();
3062 #endif // wxUSE_CARET
3064 // Notify the parent keeping track of focus for the kbd navigation
3065 // purposes that we got it.
3066 wxChildFocusEvent
eventChildFocus(static_cast<wxWindow
*>(this));
3067 GTKProcessEvent(eventChildFocus
);
3069 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, GetId());
3070 eventFocus
.SetEventObject(this);
3071 GTKProcessEvent(eventFocus
);
3076 bool wxWindowGTK
::GTKHandleFocusOut()
3078 // Disable default focus handling for custom windows since the default GTK+
3079 // handler issues a repaint
3080 const bool retval
= m_wxwindow ?
true : false;
3083 // NB: If a control is composed of several GtkWidgets and when focus
3084 // changes from one of them to another within the same wxWindow, we get
3085 // a focus-out event followed by focus-in for another GtkWidget owned
3086 // by the same wx control. We don't want to generate two spurious
3087 // wxEVT_SET_FOCUS events in this case, so we defer sending wx events
3088 // from GTKHandleFocusOut() until we know for sure it's not coming back
3089 // (i.e. in GTKHandleFocusIn() or at idle time).
3090 if ( GTKNeedsToFilterSameWindowFocus() )
3092 wxASSERT_MSG( gs_deferredFocusOut
== NULL
,
3093 "deferred focus out event already pending" );
3094 wxLogTrace(TRACE_FOCUS
,
3095 "deferring focus_out event for %s(%p, %s)",
3096 GetClassInfo()->GetClassName(), this, GetLabel());
3097 gs_deferredFocusOut
= this;
3101 GTKHandleFocusOutNoDeferring();
3106 void wxWindowGTK
::GTKHandleFocusOutNoDeferring()
3108 wxLogTrace(TRACE_FOCUS
,
3109 "handling focus_out event for %s(%p, %s)",
3110 GetClassInfo()->GetClassName(), this, GetLabel());
3113 gtk_im_context_focus_out(m_imData
->context
);
3115 if ( gs_currentFocus
!= this )
3117 // Something is terribly wrong, gs_currentFocus is out of sync with the
3118 // real focus. We will reset it to NULL anyway, because after this
3119 // focus-out event is handled, one of the following with happen:
3121 // * either focus will go out of the app altogether, in which case
3122 // gs_currentFocus _should_ be NULL
3124 // * or it goes to another control, in which case focus-in event will
3125 // follow immediately and it will set gs_currentFocus to the right
3127 wxLogDebug("window %s(%p, %s) lost focus even though it didn't have it",
3128 GetClassInfo()->GetClassName(), this, GetLabel());
3130 gs_currentFocus
= NULL
;
3133 // caret needs to be informed about focus change
3134 wxCaret
*caret
= GetCaret();
3137 caret
->OnKillFocus();
3139 #endif // wxUSE_CARET
3141 wxFocusEvent
event( wxEVT_KILL_FOCUS
, GetId() );
3142 event
.SetEventObject( this );
3143 event
.SetWindow( FindFocus() );
3144 GTKProcessEvent( event
);
3148 void wxWindowGTK
::GTKHandleDeferredFocusOut()
3150 // NB: See GTKHandleFocusOut() for explanation. This function is called
3151 // from either GTKHandleFocusIn() or OnInternalIdle() to process
3153 if ( gs_deferredFocusOut
)
3155 wxWindowGTK
*win
= gs_deferredFocusOut
;
3156 gs_deferredFocusOut
= NULL
;
3158 wxLogTrace(TRACE_FOCUS
,
3159 "processing deferred focus_out event for %s(%p, %s)",
3160 win
->GetClassInfo()->GetClassName(), win
, win
->GetLabel());
3162 win
->GTKHandleFocusOutNoDeferring();
3166 void wxWindowGTK
::SetFocus()
3168 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3170 // Setting "physical" focus is not immediate in GTK+ and while
3171 // gtk_widget_is_focus ("determines if the widget is the focus widget
3172 // within its toplevel", i.e. returns true for one widget per TLW, not
3173 // globally) returns true immediately after grabbing focus,
3174 // GTK_WIDGET_HAS_FOCUS (which returns true only for the one widget that
3175 // has focus at the moment) takes effect only after the window is shown
3176 // (if it was hidden at the moment of the call) or at the next event loop
3179 // Because we want to FindFocus() call immediately following
3180 // foo->SetFocus() to return foo, we have to keep track of "pending" focus
3182 gs_pendingFocus
= this;
3184 GtkWidget
*widget
= m_wxwindow ? m_wxwindow
: m_focusWidget
;
3186 if ( GTK_IS_CONTAINER(widget
) &&
3187 !gtk_widget_get_can_focus(widget
) )
3189 wxLogTrace(TRACE_FOCUS
,
3190 wxT("Setting focus to a child of %s(%p, %s)"),
3191 GetClassInfo()->GetClassName(), this, GetLabel().c_str());
3192 gtk_widget_child_focus(widget
, GTK_DIR_TAB_FORWARD
);
3196 wxLogTrace(TRACE_FOCUS
,
3197 wxT("Setting focus to %s(%p, %s)"),
3198 GetClassInfo()->GetClassName(), this, GetLabel().c_str());
3199 gtk_widget_grab_focus(widget
);
3203 void wxWindowGTK
::SetCanFocus(bool canFocus
)
3205 gtk_widget_set_can_focus(m_widget
, canFocus
);
3207 if ( m_wxwindow
&& (m_widget
!= m_wxwindow
) )
3209 gtk_widget_set_can_focus(m_wxwindow
, canFocus
);
3213 bool wxWindowGTK
::Reparent( wxWindowBase
*newParentBase
)
3215 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3217 wxWindowGTK
* const newParent
= (wxWindowGTK
*)newParentBase
;
3219 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3221 if ( !wxWindowBase
::Reparent(newParent
) )
3224 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3226 // Notice that old m_parent pointer might be non-NULL here but the widget
3227 // still not have any parent at GTK level if it's a notebook page that had
3228 // been removed from the notebook so test this at GTK level and not wx one.
3229 if ( GtkWidget
*parentGTK
= gtk_widget_get_parent(m_widget
) )
3230 gtk_container_remove(GTK_CONTAINER(parentGTK
), m_widget
);
3232 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3236 if (gtk_widget_get_visible (newParent
->m_widget
))
3238 m_showOnIdle
= true;
3239 gtk_widget_hide( m_widget
);
3241 /* insert GTK representation */
3242 newParent
->AddChildGTK(this);
3245 SetLayoutDirection(wxLayout_Default
);
3250 void wxWindowGTK
::DoAddChild(wxWindowGTK
*child
)
3252 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3253 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3258 /* insert GTK representation */
3262 void wxWindowGTK
::AddChild(wxWindowBase
*child
)
3264 wxWindowBase
::AddChild(child
);
3265 m_dirtyTabOrder
= true;
3266 wxTheApp
->WakeUpIdle();
3269 void wxWindowGTK
::RemoveChild(wxWindowBase
*child
)
3271 wxWindowBase
::RemoveChild(child
);
3272 m_dirtyTabOrder
= true;
3273 wxTheApp
->WakeUpIdle();
3277 wxLayoutDirection wxWindowGTK
::GTKGetLayout(GtkWidget
*widget
)
3279 return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
3280 ? wxLayout_RightToLeft
3281 : wxLayout_LeftToRight
;
3285 void wxWindowGTK
::GTKSetLayout(GtkWidget
*widget
, wxLayoutDirection dir
)
3287 wxASSERT_MSG( dir
!= wxLayout_Default
, wxT("invalid layout direction") );
3289 gtk_widget_set_direction(widget
,
3290 dir
== wxLayout_RightToLeft ? GTK_TEXT_DIR_RTL
3291 : GTK_TEXT_DIR_LTR
);
3294 wxLayoutDirection wxWindowGTK
::GetLayoutDirection() const
3296 return GTKGetLayout(m_widget
);
3299 void wxWindowGTK
::SetLayoutDirection(wxLayoutDirection dir
)
3301 if ( dir
== wxLayout_Default
)
3303 const wxWindow
*const parent
= GetParent();
3306 // inherit layout from parent.
3307 dir
= parent
->GetLayoutDirection();
3309 else // no parent, use global default layout
3311 dir
= wxTheApp
->GetLayoutDirection();
3315 if ( dir
== wxLayout_Default
)
3318 GTKSetLayout(m_widget
, dir
);
3320 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3321 GTKSetLayout(m_wxwindow
, dir
);
3325 wxWindowGTK
::AdjustForLayoutDirection(wxCoord x
,
3326 wxCoord
WXUNUSED(width
),
3327 wxCoord
WXUNUSED(widthTotal
)) const
3329 // We now mirror the coordinates of RTL windows in wxPizza
3333 void wxWindowGTK
::DoMoveInTabOrder(wxWindow
*win
, WindowOrder move
)
3335 wxWindowBase
::DoMoveInTabOrder(win
, move
);
3336 m_dirtyTabOrder
= true;
3337 wxTheApp
->WakeUpIdle();
3340 bool wxWindowGTK
::DoNavigateIn(int flags
)
3342 if ( flags
& wxNavigationKeyEvent
::WinChange
)
3344 wxFAIL_MSG( wxT("not implemented") );
3348 else // navigate inside the container
3350 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3351 wxCHECK_MSG( parent
, false, wxT("every window must have a TLW parent") );
3353 GtkDirectionType dir
;
3354 dir
= flags
& wxNavigationKeyEvent
::IsForward ? GTK_DIR_TAB_FORWARD
3355 : GTK_DIR_TAB_BACKWARD
;
3358 g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
);
3364 bool wxWindowGTK
::GTKWidgetNeedsMnemonic() const
3366 // none needed by default
3370 void wxWindowGTK
::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3372 // nothing to do by default since none is needed
3375 void wxWindowGTK
::RealizeTabOrder()
3379 if ( !m_children
.empty() )
3381 // we don't only construct the correct focus chain but also use
3382 // this opportunity to update the mnemonic widgets for the widgets
3385 GList
*chain
= NULL
;
3386 wxWindowGTK
* mnemonicWindow
= NULL
;
3388 for ( wxWindowList
::const_iterator i
= m_children
.begin();
3389 i
!= m_children
.end();
3392 wxWindowGTK
*win
= *i
;
3394 bool focusableFromKeyboard
= win
->AcceptsFocusFromKeyboard();
3396 if ( mnemonicWindow
)
3398 if ( focusableFromKeyboard
)
3400 // wxComboBox et al. needs to focus on on a different
3401 // widget than m_widget, so if the main widget isn't
3402 // focusable try the connect widget
3403 GtkWidget
* w
= win
->m_widget
;
3404 if ( !gtk_widget_get_can_focus(w
) )
3406 w
= win
->GetConnectWidget();
3407 if ( !gtk_widget_get_can_focus(w
) )
3413 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3414 mnemonicWindow
= NULL
;
3418 else if ( win
->GTKWidgetNeedsMnemonic() )
3420 mnemonicWindow
= win
;
3423 if ( focusableFromKeyboard
)
3424 chain
= g_list_prepend(chain
, win
->m_widget
);
3427 chain
= g_list_reverse(chain
);
3429 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3434 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3439 void wxWindowGTK
::Raise()
3441 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3443 if (m_wxwindow
&& gtk_widget_get_window(m_wxwindow
))
3445 gdk_window_raise(gtk_widget_get_window(m_wxwindow
));
3447 else if (gtk_widget_get_window(m_widget
))
3449 gdk_window_raise(gtk_widget_get_window(m_widget
));
3453 void wxWindowGTK
::Lower()
3455 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3457 if (m_wxwindow
&& gtk_widget_get_window(m_wxwindow
))
3459 gdk_window_lower(gtk_widget_get_window(m_wxwindow
));
3461 else if (gtk_widget_get_window(m_widget
))
3463 gdk_window_lower(gtk_widget_get_window(m_widget
));
3467 bool wxWindowGTK
::SetCursor( const wxCursor
&cursor
)
3469 if ( !wxWindowBase
::SetCursor(cursor
.IsOk() ? cursor
: *wxSTANDARD_CURSOR
) )
3477 void wxWindowGTK
::GTKUpdateCursor(bool update_self
/*=true*/, bool recurse
/*=true*/)
3481 wxCursor
cursor(g_globalCursor
.IsOk() ? g_globalCursor
: GetCursor());
3482 if ( cursor
.IsOk() )
3484 wxArrayGdkWindows windowsThis
;
3485 GdkWindow
* window
= GTKGetWindow(windowsThis
);
3487 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3490 const size_t count
= windowsThis
.size();
3491 for ( size_t n
= 0; n
< count
; n
++ )
3493 GdkWindow
*win
= windowsThis
[n
];
3494 // It can be zero if the window has not been realized yet.
3497 gdk_window_set_cursor(win
, cursor
.GetCursor());
3506 for (wxWindowList
::iterator it
= GetChildren().begin(); it
!= GetChildren().end(); ++it
)
3508 (*it
)->GTKUpdateCursor( true );
3513 void wxWindowGTK
::WarpPointer( int x
, int y
)
3515 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3517 ClientToScreen(&x
, &y
);
3518 GdkDisplay
* display
= gtk_widget_get_display(m_widget
);
3519 GdkScreen
* screen
= gtk_widget_get_screen(m_widget
);
3521 GdkDeviceManager
* manager
= gdk_display_get_device_manager(display
);
3522 gdk_device_warp(gdk_device_manager_get_client_pointer(manager
), screen
, x
, y
);
3524 XWarpPointer(GDK_DISPLAY_XDISPLAY(display
),
3526 GDK_WINDOW_XID(gdk_screen_get_root_window(screen
)),
3531 wxWindowGTK
::ScrollDir wxWindowGTK
::ScrollDirFromRange(GtkRange
*range
) const
3533 // find the scrollbar which generated the event
3534 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3536 if ( range
== m_scrollBar
[dir
] )
3537 return (ScrollDir
)dir
;
3540 wxFAIL_MSG( wxT("event from unknown scrollbar received") );
3542 return ScrollDir_Max
;
3545 bool wxWindowGTK
::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3547 bool changed
= false;
3548 GtkRange
* range
= m_scrollBar
[dir
];
3549 if ( range
&& units
)
3551 GtkAdjustment
* adj
= gtk_range_get_adjustment(range
);
3552 double inc
= unit
== ScrollUnit_Line ?
gtk_adjustment_get_step_increment(adj
)
3553 : gtk_adjustment_get_page_increment(adj
);
3555 const int posOld
= wxRound(gtk_adjustment_get_value(adj
));
3556 gtk_range_set_value(range
, posOld
+ units
*inc
);
3558 changed
= wxRound(gtk_adjustment_get_value(adj
)) != posOld
;
3564 bool wxWindowGTK
::ScrollLines(int lines
)
3566 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3569 bool wxWindowGTK
::ScrollPages(int pages
)
3571 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3574 void wxWindowGTK
::Refresh(bool WXUNUSED(eraseBackground
),
3577 if (m_widget
== NULL
|| !gtk_widget_get_mapped(m_widget
))
3582 GdkWindow
* window
= gtk_widget_get_window(m_wxwindow
);
3585 GdkRectangle r
= { rect
->x
, rect
->y
, rect
->width
, rect
->height
};
3586 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3587 r
.x
= gdk_window_get_width(window
) - r
.x
- rect
->width
;
3588 gdk_window_invalidate_rect(window
, &r
, true);
3591 gdk_window_invalidate_rect(window
, NULL
, true);
3596 gtk_widget_queue_draw_area(m_widget
, rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3598 gtk_widget_queue_draw(m_widget
);
3602 void wxWindowGTK
::Update()
3604 if (m_widget
&& gtk_widget_get_mapped(m_widget
))
3606 GdkDisplay
* display
= gtk_widget_get_display(m_widget
);
3607 // Flush everything out to the server, and wait for it to finish.
3608 // This ensures nothing will overwrite the drawing we are about to do.
3609 gdk_display_sync(display
);
3611 GdkWindow
* window
= GTKGetDrawingWindow();
3613 window
= gtk_widget_get_window(m_widget
);
3614 gdk_window_process_updates(window
, true);
3616 // Flush again, but no need to wait for it to finish
3617 gdk_display_flush(display
);
3621 bool wxWindowGTK
::DoIsExposed( int x
, int y
) const
3623 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
3626 bool wxWindowGTK
::DoIsExposed( int x
, int y
, int w
, int h
) const
3628 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3629 return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
;
3631 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
3634 void wxWindowGTK
::GtkSendPaintEvents()
3638 m_updateRegion
.Clear();
3642 // Clip to paint region in wxClientDC
3643 m_clipPaintRegion
= true;
3645 m_nativeUpdateRegion
= m_updateRegion
;
3647 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3649 // Transform m_updateRegion under RTL
3650 m_updateRegion
.Clear();
3653 gdk_drawable_get_size(gtk_widget_get_window(m_wxwindow
), &width
, NULL
);
3655 wxRegionIterator
upd( m_nativeUpdateRegion
);
3659 rect
.x
= upd
.GetX();
3660 rect
.y
= upd
.GetY();
3661 rect
.width
= upd
.GetWidth();
3662 rect
.height
= upd
.GetHeight();
3664 rect
.x
= width
- rect
.x
- rect
.width
;
3665 m_updateRegion
.Union( rect
);
3671 switch ( GetBackgroundStyle() )
3673 case wxBG_STYLE_ERASE
:
3675 wxWindowDC
dc( (wxWindow
*)this );
3676 dc
.SetDeviceClippingRegion( m_updateRegion
);
3678 // Work around gtk-qt <= 0.60 bug whereby the window colour
3682 GetOptionInt("gtk.window.force-background-colour") )
3684 dc
.SetBackground(GetBackgroundColour());
3688 wxEraseEvent
erase_event( GetId(), &dc
);
3689 erase_event
.SetEventObject( this );
3691 if ( HandleWindowEvent(erase_event
) )
3693 // background erased, don't do it again
3699 case wxBG_STYLE_SYSTEM
:
3700 if ( GetThemeEnabled() )
3702 // find ancestor from which to steal background
3703 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3705 parent
= (wxWindow
*)this;
3707 if (gtk_widget_get_mapped(parent
->m_widget
))
3709 wxRegionIterator
upd( m_nativeUpdateRegion
);
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(gtk_widget_get_style(parent
->m_widget
),
3719 GTKGetDrawingWindow(),
3720 gtk_widget_get_state(m_wxwindow
),
3733 case wxBG_STYLE_PAINT
:
3734 // nothing to do: window will be painted over in EVT_PAINT
3738 wxFAIL_MSG( "unsupported background style" );
3741 wxNcPaintEvent
nc_paint_event( GetId() );
3742 nc_paint_event
.SetEventObject( this );
3743 HandleWindowEvent( nc_paint_event
);
3745 wxPaintEvent
paint_event( GetId() );
3746 paint_event
.SetEventObject( this );
3747 HandleWindowEvent( paint_event
);
3749 m_clipPaintRegion
= false;
3751 m_updateRegion
.Clear();
3752 m_nativeUpdateRegion
.Clear();
3755 void wxWindowGTK
::SetDoubleBuffered( bool on
)
3757 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3760 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3763 bool wxWindowGTK
::IsDoubleBuffered() const
3765 return gtk_widget_get_double_buffered( m_wxwindow
);
3768 void wxWindowGTK
::ClearBackground()
3770 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3774 void wxWindowGTK
::DoSetToolTip( wxToolTip
*tip
)
3776 if (m_tooltip
!= tip
)
3778 wxWindowBase
::DoSetToolTip(tip
);
3781 m_tooltip
->GTKSetWindow(static_cast<wxWindow
*>(this));
3783 GTKApplyToolTip(NULL
);
3787 void wxWindowGTK
::GTKApplyToolTip(const char* tip
)
3789 wxToolTip
::GTKApply(GetConnectWidget(), tip
);
3791 #endif // wxUSE_TOOLTIPS
3793 bool wxWindowGTK
::SetBackgroundColour( const wxColour
&colour
)
3795 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3797 if (!wxWindowBase
::SetBackgroundColour(colour
))
3802 // We need the pixel value e.g. for background clearing.
3803 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3806 // apply style change (forceStyle=true so that new style is applied
3807 // even if the bg colour changed from valid to wxNullColour)
3808 GTKApplyWidgetStyle(true);
3813 bool wxWindowGTK
::SetForegroundColour( const wxColour
&colour
)
3815 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3817 if (!wxWindowBase
::SetForegroundColour(colour
))
3824 // We need the pixel value e.g. for background clearing.
3825 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3828 // apply style change (forceStyle=true so that new style is applied
3829 // even if the bg colour changed from valid to wxNullColour):
3830 GTKApplyWidgetStyle(true);
3835 PangoContext
*wxWindowGTK
::GTKGetPangoDefaultContext()
3837 return gtk_widget_get_pango_context( m_widget
);
3840 GtkRcStyle
*wxWindowGTK
::GTKCreateWidgetStyle(bool forceStyle
)
3842 // do we need to apply any changes at all?
3845 !m_foregroundColour
.IsOk() && !m_backgroundColour
.IsOk() )
3850 GtkRcStyle
*style
= gtk_rc_style_new();
3852 if ( m_font
.IsOk() )
3855 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3858 int flagsNormal
= 0,
3861 flagsInsensitive
= 0;
3863 if ( m_foregroundColour
.IsOk() )
3865 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3867 style
->fg
[GTK_STATE_NORMAL
] =
3868 style
->text
[GTK_STATE_NORMAL
] = *fg
;
3869 flagsNormal
|= GTK_RC_FG
| GTK_RC_TEXT
;
3871 style
->fg
[GTK_STATE_PRELIGHT
] =
3872 style
->text
[GTK_STATE_PRELIGHT
] = *fg
;
3873 flagsPrelight
|= GTK_RC_FG
| GTK_RC_TEXT
;
3875 style
->fg
[GTK_STATE_ACTIVE
] =
3876 style
->text
[GTK_STATE_ACTIVE
] = *fg
;
3877 flagsActive
|= GTK_RC_FG
| GTK_RC_TEXT
;
3880 if ( m_backgroundColour
.IsOk() )
3882 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3884 style
->bg
[GTK_STATE_NORMAL
] =
3885 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3886 flagsNormal
|= GTK_RC_BG
| GTK_RC_BASE
;
3888 style
->bg
[GTK_STATE_PRELIGHT
] =
3889 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3890 flagsPrelight
|= GTK_RC_BG
| GTK_RC_BASE
;
3892 style
->bg
[GTK_STATE_ACTIVE
] =
3893 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3894 flagsActive
|= GTK_RC_BG
| GTK_RC_BASE
;
3896 style
->bg
[GTK_STATE_INSENSITIVE
] =
3897 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3898 flagsInsensitive
|= GTK_RC_BG
| GTK_RC_BASE
;
3901 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
;
3902 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
;
3903 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
;
3904 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
;
3909 void wxWindowGTK
::GTKApplyWidgetStyle(bool forceStyle
)
3911 GtkRcStyle
*style
= GTKCreateWidgetStyle(forceStyle
);
3914 DoApplyWidgetStyle(style
);
3915 g_object_unref(style
);
3918 // Style change may affect GTK+'s size calculation:
3919 InvalidateBestSize();
3922 void wxWindowGTK
::DoApplyWidgetStyle(GtkRcStyle
*style
)
3926 // block the signal temporarily to avoid sending
3927 // wxSysColourChangedEvents when we change the colours ourselves
3928 bool unblock
= false;
3932 g_signal_handlers_block_by_func(
3933 m_wxwindow
, (void *)gtk_window_style_set_callback
, this);
3936 gtk_widget_modify_style(m_wxwindow
, style
);
3940 g_signal_handlers_unblock_by_func(
3941 m_wxwindow
, (void *)gtk_window_style_set_callback
, this);
3946 gtk_widget_modify_style(m_widget
, style
);
3950 bool wxWindowGTK
::SetBackgroundStyle(wxBackgroundStyle style
)
3952 wxWindowBase
::SetBackgroundStyle(style
);
3954 if ( style
== wxBG_STYLE_PAINT
)
3959 window
= GTKGetDrawingWindow();
3963 GtkWidget
* const w
= GetConnectWidget();
3964 window
= w ?
gtk_widget_get_window(w
) : NULL
;
3969 // Make sure GDK/X11 doesn't refresh the window
3971 gdk_window_set_back_pixmap( window
, None
, False
);
3973 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3976 m_needsStyleChange
= false;
3978 else // window not realized yet
3980 // Do in OnIdle, because the window is not yet available
3981 m_needsStyleChange
= true;
3984 // Don't apply widget style, or we get a grey background
3988 // apply style change (forceStyle=true so that new style is applied
3989 // even if the bg colour changed from valid to wxNullColour):
3990 GTKApplyWidgetStyle(true);
3996 // ----------------------------------------------------------------------------
3997 // Pop-up menu stuff
3998 // ----------------------------------------------------------------------------
4000 #if wxUSE_MENUS_NATIVE
4004 void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4006 gboolean
* WXUNUSED(whatever
),
4007 gpointer user_data
)
4009 // ensure that the menu appears entirely on screen
4011 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4013 wxSize sizeScreen
= wxGetDisplaySize();
4014 wxPoint
*pos
= (wxPoint
*)user_data
;
4016 gint xmax
= sizeScreen
.x
- req
.width
,
4017 ymax
= sizeScreen
.y
- req
.height
;
4019 *x
= pos
->x
< xmax ? pos
->x
: xmax
;
4020 *y
= pos
->y
< ymax ? pos
->y
: ymax
;
4024 bool wxWindowGTK
::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4026 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4032 GtkMenuPositionFunc posfunc
;
4033 if ( x
== -1 && y
== -1 )
4035 // use GTK's default positioning algorithm
4041 pos
= ClientToScreen(wxPoint(x
, y
));
4043 posfunc
= wxPopupMenuPositionCallback
;
4046 menu
->m_popupShown
= true;
4048 GTK_MENU(menu
->m_menu
),
4049 NULL
, // parent menu shell
4050 NULL
, // parent menu item
4051 posfunc
, // function to position it
4052 userdata
, // client data
4053 0, // button used to activate it
4054 gtk_get_current_event_time()
4057 while (menu
->m_popupShown
)
4059 gtk_main_iteration();
4065 #endif // wxUSE_MENUS_NATIVE
4067 #if wxUSE_DRAG_AND_DROP
4069 void wxWindowGTK
::SetDropTarget( wxDropTarget
*dropTarget
)
4071 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4073 GtkWidget
*dnd_widget
= GetConnectWidget();
4075 if (m_dropTarget
) m_dropTarget
->GtkUnregisterWidget( dnd_widget
);
4077 if (m_dropTarget
) delete m_dropTarget
;
4078 m_dropTarget
= dropTarget
;
4080 if (m_dropTarget
) m_dropTarget
->GtkRegisterWidget( dnd_widget
);
4083 #endif // wxUSE_DRAG_AND_DROP
4085 GtkWidget
* wxWindowGTK
::GetConnectWidget()
4087 GtkWidget
*connect_widget
= m_widget
;
4088 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4090 return connect_widget
;
4093 bool wxWindowGTK
::GTKIsOwnWindow(GdkWindow
*window
) const
4095 wxArrayGdkWindows windowsThis
;
4096 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
4098 return winThis ? window
== winThis
4099 : windowsThis
.Index(window
) != wxNOT_FOUND
;
4102 GdkWindow
*wxWindowGTK
::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
4104 return m_wxwindow ?
GTKGetDrawingWindow() : gtk_widget_get_window(m_widget
);
4107 bool wxWindowGTK
::SetFont( const wxFont
&font
)
4109 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4111 if (!wxWindowBase
::SetFont(font
))
4114 // apply style change (forceStyle=true so that new style is applied
4115 // even if the font changed from valid to wxNullFont):
4116 GTKApplyWidgetStyle(true);
4121 void wxWindowGTK
::DoCaptureMouse()
4123 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4125 GdkWindow
*window
= NULL
;
4127 window
= GTKGetDrawingWindow();
4129 window
= gtk_widget_get_window(GetConnectWidget());
4131 wxCHECK_RET( window
, wxT("CaptureMouse() failed") );
4133 const wxCursor
* cursor
= &m_cursor
;
4134 if (!cursor
->IsOk())
4135 cursor
= wxSTANDARD_CURSOR
;
4137 gdk_pointer_grab( window
, FALSE
,
4139 (GDK_BUTTON_PRESS_MASK
|
4140 GDK_BUTTON_RELEASE_MASK
|
4141 GDK_POINTER_MOTION_HINT_MASK
|
4142 GDK_POINTER_MOTION_MASK
),
4144 cursor
->GetCursor(),
4145 (guint32
)GDK_CURRENT_TIME
);
4146 g_captureWindow
= this;
4147 g_captureWindowHasMouse
= true;
4150 void wxWindowGTK
::DoReleaseMouse()
4152 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4154 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4156 g_captureWindow
= NULL
;
4158 GdkWindow
*window
= NULL
;
4160 window
= GTKGetDrawingWindow();
4162 window
= gtk_widget_get_window(GetConnectWidget());
4167 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4170 void wxWindowGTK
::GTKReleaseMouseAndNotify()
4173 wxMouseCaptureLostEvent
evt(GetId());
4174 evt
.SetEventObject( this );
4175 HandleWindowEvent( evt
);
4179 wxWindow
*wxWindowBase
::GetCapture()
4181 return (wxWindow
*)g_captureWindow
;
4184 bool wxWindowGTK
::IsRetained() const
4189 void wxWindowGTK
::SetScrollbar(int orient
,
4193 bool WXUNUSED(update
))
4195 const int dir
= ScrollDirFromOrient(orient
);
4196 GtkRange
* const sb
= m_scrollBar
[dir
];
4197 wxCHECK_RET( sb
, wxT("this window is not scrollable") );
4201 // GtkRange requires upper > lower
4206 g_signal_handlers_block_by_func(
4207 sb
, (void*)gtk_scrollbar_value_changed
, this);
4209 gtk_range_set_increments(sb
, 1, thumbVisible
);
4210 gtk_adjustment_set_page_size(gtk_range_get_adjustment(sb
), thumbVisible
);
4211 gtk_range_set_range(sb
, 0, range
);
4212 gtk_range_set_value(sb
, pos
);
4213 m_scrollPos
[dir
] = gtk_range_get_value(sb
);
4215 g_signal_handlers_unblock_by_func(
4216 sb
, (void*)gtk_scrollbar_value_changed
, this);
4219 void wxWindowGTK
::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4221 const int dir
= ScrollDirFromOrient(orient
);
4222 GtkRange
* const sb
= m_scrollBar
[dir
];
4223 wxCHECK_RET( sb
, wxT("this window is not scrollable") );
4225 // This check is more than an optimization. Without it, the slider
4226 // will not move smoothly while tracking when using wxScrollHelper.
4227 if (GetScrollPos(orient
) != pos
)
4229 g_signal_handlers_block_by_func(
4230 sb
, (void*)gtk_scrollbar_value_changed
, this);
4232 gtk_range_set_value(sb
, pos
);
4233 m_scrollPos
[dir
] = gtk_range_get_value(sb
);
4235 g_signal_handlers_unblock_by_func(
4236 sb
, (void*)gtk_scrollbar_value_changed
, this);
4240 int wxWindowGTK
::GetScrollThumb(int orient
) const
4242 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4243 wxCHECK_MSG( sb
, 0, wxT("this window is not scrollable") );
4245 return wxRound(gtk_adjustment_get_page_size(gtk_range_get_adjustment(sb
)));
4248 int wxWindowGTK
::GetScrollPos( int orient
) const
4250 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4251 wxCHECK_MSG( sb
, 0, wxT("this window is not scrollable") );
4253 return wxRound(gtk_range_get_value(sb
));
4256 int wxWindowGTK
::GetScrollRange( int orient
) const
4258 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4259 wxCHECK_MSG( sb
, 0, wxT("this window is not scrollable") );
4261 return wxRound(gtk_adjustment_get_upper(gtk_range_get_adjustment(sb
)));
4264 // Determine if increment is the same as +/-x, allowing for some small
4265 // difference due to possible inexactness in floating point arithmetic
4266 static inline bool IsScrollIncrement(double increment
, double x
)
4268 wxASSERT(increment
> 0);
4269 const double tolerance
= 1.0 / 1024;
4270 return fabs(increment
- fabs(x
)) < tolerance
;
4273 wxEventType wxWindowGTK
::GTKGetScrollEventType(GtkRange
* range
)
4275 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4277 const int barIndex
= range
== m_scrollBar
[1];
4279 const double value
= gtk_range_get_value(range
);
4281 // save previous position
4282 const double oldPos
= m_scrollPos
[barIndex
];
4283 // update current position
4284 m_scrollPos
[barIndex
] = value
;
4285 // If event should be ignored, or integral position has not changed
4286 if (!m_hasVMT
|| g_blockEventsOnDrag
|| wxRound(value
) == wxRound(oldPos
))
4291 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4294 // Difference from last change event
4295 const double diff
= value
- oldPos
;
4296 const bool isDown
= diff
> 0;
4298 GtkAdjustment
* adj
= gtk_range_get_adjustment(range
);
4299 if (IsScrollIncrement(gtk_adjustment_get_step_increment(adj
), diff
))
4301 eventType
= isDown ? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4303 else if (IsScrollIncrement(gtk_adjustment_get_page_increment(adj
), diff
))
4305 eventType
= isDown ? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4307 else if (m_mouseButtonDown
)
4309 // Assume track event
4310 m_isScrolling
= true;
4316 void wxWindowGTK
::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4318 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4320 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4322 // No scrolling requested.
4323 if ((dx
== 0) && (dy
== 0)) return;
4325 m_clipPaintRegion
= true;
4327 WX_PIZZA(m_wxwindow
)->scroll(dx
, dy
);
4329 m_clipPaintRegion
= false;
4332 bool restoreCaret
= (GetCaret() != NULL
&& GetCaret()->IsVisible());
4335 wxRect
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4337 caretRect
.width
+= dx
;
4340 caretRect
.x
+= dx
; caretRect
.width
-= dx
;
4343 caretRect
.height
+= dy
;
4346 caretRect
.y
+= dy
; caretRect
.height
-= dy
;
4349 RefreshRect(caretRect
);
4351 #endif // wxUSE_CARET
4354 void wxWindowGTK
::GTKScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4356 //RN: Note that static controls usually have no border on gtk, so maybe
4357 //it makes sense to treat that as simply no border at the wx level
4359 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4361 GtkShadowType gtkstyle
;
4363 if(wxstyle
& wxBORDER_RAISED
)
4364 gtkstyle
= GTK_SHADOW_OUT
;
4365 else if ((wxstyle
& wxBORDER_SUNKEN
) || (wxstyle
& wxBORDER_THEME
))
4366 gtkstyle
= GTK_SHADOW_IN
;
4369 else if (wxstyle
& wxBORDER_DOUBLE
)
4370 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4373 gtkstyle
= GTK_SHADOW_IN
;
4375 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4380 void wxWindowGTK
::SetWindowStyleFlag( long style
)
4382 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4383 wxWindowBase
::SetWindowStyleFlag(style
);
4386 // Find the wxWindow at the current mouse position, also returning the mouse
4388 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4390 pt
= wxGetMousePosition();
4391 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4395 // Get the current mouse position.
4396 wxPoint
wxGetMousePosition()
4398 /* This crashes when used within wxHelpContext,
4399 so we have to use the X-specific implementation below.
4401 GdkModifierType *mask;
4402 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4404 return wxPoint(x, y);
4408 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4410 Display
*display
= windowAtPtr ?
GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4411 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4412 Window rootReturn
, childReturn
;
4413 int rootX
, rootY
, winX
, winY
;
4414 unsigned int maskReturn
;
4416 XQueryPointer (display
,
4420 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4421 return wxPoint(rootX
, rootY
);
4425 GdkWindow
* wxWindowGTK
::GTKGetDrawingWindow() const
4427 GdkWindow
* window
= NULL
;
4429 window
= gtk_widget_get_window(m_wxwindow
);
4433 // ----------------------------------------------------------------------------
4435 // ----------------------------------------------------------------------------
4440 // this is called if we attempted to freeze unrealized widget when it finally
4441 // is realized (and so can be frozen):
4442 static void wx_frozen_widget_realize(GtkWidget
* w
, wxWindowGTK
* win
)
4444 wxASSERT( w
&& gtk_widget_get_has_window(w
) );
4445 wxASSERT( gtk_widget_get_realized(w
) );
4447 g_signal_handlers_disconnect_by_func
4450 (void*)wx_frozen_widget_realize
,
4455 if (w
== win
->m_wxwindow
)
4456 window
= win
->GTKGetDrawingWindow();
4458 window
= gtk_widget_get_window(w
);
4459 gdk_window_freeze_updates(window
);
4464 void wxWindowGTK
::GTKFreezeWidget(GtkWidget
*w
)
4466 if ( !w
|| !gtk_widget_get_has_window(w
) )
4467 return; // window-less widget, cannot be frozen
4469 GdkWindow
* window
= gtk_widget_get_window(w
);
4472 // we can't thaw unrealized widgets because they don't have GdkWindow,
4473 // so set it up to be done immediately after realization:
4474 g_signal_connect_after
4478 G_CALLBACK(wx_frozen_widget_realize
),
4484 if (w
== m_wxwindow
)
4485 window
= GTKGetDrawingWindow();
4486 gdk_window_freeze_updates(window
);
4489 void wxWindowGTK
::GTKThawWidget(GtkWidget
*w
)
4491 if ( !w
|| !gtk_widget_get_has_window(w
) )
4492 return; // window-less widget, cannot be frozen
4494 GdkWindow
* window
= gtk_widget_get_window(w
);
4497 // the widget wasn't realized yet, no need to thaw
4498 g_signal_handlers_disconnect_by_func
4501 (void*)wx_frozen_widget_realize
,
4507 if (w
== m_wxwindow
)
4508 window
= GTKGetDrawingWindow();
4509 gdk_window_thaw_updates(window
);
4512 void wxWindowGTK
::DoFreeze()
4514 GTKFreezeWidget(m_widget
);
4515 if ( m_wxwindow
&& m_widget
!= m_wxwindow
)
4516 GTKFreezeWidget(m_wxwindow
);
4519 void wxWindowGTK
::DoThaw()
4521 GTKThawWidget(m_widget
);
4522 if ( m_wxwindow
&& m_widget
!= m_wxwindow
)
4523 GTKThawWidget(m_wxwindow
);