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/scopeguard.h"
35 #include "wx/sysopt.h"
39 #include "wx/gtk/private.h"
40 #include "wx/gtk/private/win_gtk.h"
41 #include "wx/gtk/private/event.h"
42 using namespace wxGTKImpl
;
46 #include <gdk/gdkkeysyms.h>
47 #if GTK_CHECK_VERSION(3,0,0)
48 #include <gdk/gdkkeysyms-compat.h>
51 // gdk_window_set_composited() is only supported since 2.12
52 #define wxGTK_VERSION_REQUIRED_FOR_COMPOSITING 2,12,0
53 #define wxGTK_HAS_COMPOSITING_SUPPORT GTK_CHECK_VERSION(2,12,0)
55 //-----------------------------------------------------------------------------
56 // documentation on internals
57 //-----------------------------------------------------------------------------
60 I have been asked several times about writing some documentation about
61 the GTK port of wxWidgets, especially its internal structures. Obviously,
62 you cannot understand wxGTK without knowing a little about the GTK, but
63 some more information about what the wxWindow, which is the base class
64 for all other window classes, does seems required as well.
68 What does wxWindow do? It contains the common interface for the following
69 jobs of its descendants:
71 1) Define the rudimentary behaviour common to all window classes, such as
72 resizing, intercepting user input (so as to make it possible to use these
73 events for special purposes in a derived class), window names etc.
75 2) Provide the possibility to contain and manage children, if the derived
76 class is allowed to contain children, which holds true for those window
77 classes which do not display a native GTK widget. To name them, these
78 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
79 work classes are a special case and are handled a bit differently from
80 the rest. The same holds true for the wxNotebook class.
82 3) Provide the possibility to draw into a client area of a window. This,
83 too, only holds true for classes that do not display a native GTK widget
86 4) Provide the entire mechanism for scrolling widgets. This actual inter-
87 face for this is usually in wxScrolledWindow, but the GTK implementation
90 5) A multitude of helper or extra methods for special purposes, such as
91 Drag'n'Drop, managing validators etc.
93 6) Display a border (sunken, raised, simple or none).
95 Normally one might expect, that one wxWidgets window would always correspond
96 to one GTK widget. Under GTK, there is no such all-round widget that has all
97 the functionality. Moreover, the GTK defines a client area as a different
98 widget from the actual widget you are handling. Last but not least some
99 special classes (e.g. wxFrame) handle different categories of widgets and
100 still have the possibility to draw something in the client area.
101 It was therefore required to write a special purpose GTK widget, that would
102 represent a client area in the sense of wxWidgets capable to do the jobs
103 2), 3) and 4). I have written this class and it resides in win_gtk.c of
106 All windows must have a widget, with which they interact with other under-
107 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
108 the wxWindow class has a member variable called m_widget which holds a
109 pointer to this widget. When the window class represents a GTK native widget,
110 this is (in most cases) the only GTK widget the class manages. E.g. the
111 wxStaticText class handles only a GtkLabel widget a pointer to which you
112 can find in m_widget (defined in wxWindow)
114 When the class has a client area for drawing into and for containing children
115 it has to handle the client area widget (of the type wxPizza, defined in
116 win_gtk.cpp), but there could be any number of widgets, handled by a class.
117 The common rule for all windows is only, that the widget that interacts with
118 the rest of GTK must be referenced in m_widget and all other widgets must be
119 children of this widget on the GTK level. The top-most widget, which also
120 represents the client area, must be in the m_wxwindow field and must be of
123 As I said, the window classes that display a GTK native widget only have
124 one widget, so in the case of e.g. the wxButton class m_widget holds a
125 pointer to a GtkButton widget. But windows with client areas (for drawing
126 and children) have a m_widget field that is a pointer to a GtkScrolled-
127 Window and a m_wxwindow field that is pointer to a wxPizza and this
128 one is (in the GTK sense) a child of the GtkScrolledWindow.
130 If the m_wxwindow field is set, then all input to this widget is inter-
131 cepted and sent to the wxWidgets class. If not, all input to the widget
132 that gets pointed to by m_widget gets intercepted and sent to the class.
136 The design of scrolling in wxWidgets is markedly different from that offered
137 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
138 clicking on a scrollbar belonging to scrolled window will inevitably move
139 the window. In wxWidgets, the scrollbar will only emit an event, send this
140 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
141 which actually moves the window and its sub-windows. Note that wxPizza
142 memorizes how much it has been scrolled but that wxWidgets forgets this
143 so that the two coordinates systems have to be kept in synch. This is done
144 in various places using the pizza->m_scroll_x and pizza->m_scroll_y values.
148 Singularly the most broken code in GTK is the code that is supposed to
149 inform subwindows (child windows) about new positions. Very often, duplicate
150 events are sent without changes in size or position, equally often no
151 events are sent at all (All this is due to a bug in the GtkContainer code
152 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
153 GTK's own system and it simply waits for size events for toplevel windows
154 and then iterates down the respective size events to all window. This has
155 the disadvantage that windows might get size events before the GTK widget
156 actually has the reported size. This doesn't normally pose any problem, but
157 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
158 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
159 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
160 window that is used for OpenGL output really has that size (as reported by
165 If someone at some point of time feels the immense desire to have a look at,
166 change or attempt to optimise the Refresh() logic, this person will need an
167 intimate understanding of what "draw" and "expose" events are and what
168 they are used for, in particular when used in connection with GTK's
169 own windowless widgets. Beware.
173 Cursors, too, have been a constant source of pleasure. The main difficulty
174 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
175 for the parent. To prevent this from doing too much harm, SetCursor calls
176 GTKUpdateCursor, which will recursively re-set the cursors of all child windows.
177 Also don't forget that cursors (like much else) are connected to GdkWindows,
178 not GtkWidgets and that the "window" field of a GtkWidget might very well
179 point to the GdkWindow of the parent widget (-> "window-less widget") and
180 that the two obviously have very different meanings.
183 //-----------------------------------------------------------------------------
185 //-----------------------------------------------------------------------------
187 // Don't allow event propagation during drag
188 bool g_blockEventsOnDrag
;
189 // Don't allow mouse event propagation during scroll
190 bool g_blockEventsOnScroll
;
191 extern wxCursor g_globalCursor
;
193 // mouse capture state: the window which has it and if the mouse is currently
195 static wxWindowGTK
*g_captureWindow
= NULL
;
196 static bool g_captureWindowHasMouse
= false;
198 // The window that currently has focus:
199 static wxWindowGTK
*gs_currentFocus
= NULL
;
200 // The window that is scheduled to get focus in the next event loop iteration
201 // or NULL if there's no pending focus change:
202 static wxWindowGTK
*gs_pendingFocus
= NULL
;
204 // the window that has deferred focus-out event pending, if any (see
205 // GTKAddDeferredFocusOut() for details)
206 static wxWindowGTK
*gs_deferredFocusOut
= NULL
;
208 // global variables because GTK+ DnD want to have the
209 // mouse event that caused it
210 GdkEvent
*g_lastMouseEvent
= NULL
;
211 int g_lastButtonNumber
= 0;
213 //-----------------------------------------------------------------------------
215 //-----------------------------------------------------------------------------
217 // the trace mask used for the focus debugging messages
218 #define TRACE_FOCUS wxT("focus")
220 //-----------------------------------------------------------------------------
221 // "size_request" of m_widget
222 //-----------------------------------------------------------------------------
226 wxgtk_window_size_request_callback(GtkWidget
* WXUNUSED(widget
),
227 GtkRequisition
*requisition
,
231 win
->GetSize( &w
, &h
);
237 requisition
->height
= h
;
238 requisition
->width
= w
;
242 //-----------------------------------------------------------------------------
243 // "expose_event" of m_wxwindow
244 //-----------------------------------------------------------------------------
248 gtk_window_expose_callback( GtkWidget
*,
249 GdkEventExpose
*gdk_event
,
252 if (gdk_event
->window
== win
->GTKGetDrawingWindow())
254 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
255 win
->GtkSendPaintEvents();
257 // Let parent window draw window-less widgets
262 #ifndef __WXUNIVERSAL__
263 //-----------------------------------------------------------------------------
264 // "expose_event" from m_wxwindow->parent, for drawing border
265 //-----------------------------------------------------------------------------
269 expose_event_border(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxWindow
* win
)
271 if (gdk_event
->window
!= gtk_widget_get_parent_window(win
->m_wxwindow
))
278 gtk_widget_get_allocation(win
->m_wxwindow
, &alloc
);
279 const int x
= alloc
.x
;
280 const int y
= alloc
.y
;
281 const int w
= alloc
.width
;
282 const int h
= alloc
.height
;
284 if (w
<= 0 || h
<= 0)
287 if (win
->HasFlag(wxBORDER_SIMPLE
))
289 gdk_draw_rectangle(gdk_event
->window
,
290 gtk_widget_get_style(widget
)->black_gc
, false, x
, y
, w
- 1, h
- 1);
294 GtkShadowType shadow
= GTK_SHADOW_IN
;
295 if (win
->HasFlag(wxBORDER_RAISED
))
296 shadow
= GTK_SHADOW_OUT
;
298 // Style detail to use
300 if (win
->m_widget
== win
->m_wxwindow
)
301 // for non-scrollable wxWindows
304 // for scrollable ones
307 // clip rect is required to avoid painting background
308 // over upper left (w,h) of parent window
309 GdkRectangle clipRect
= { x
, y
, w
, h
};
311 gtk_widget_get_style(win
->m_wxwindow
), gdk_event
->window
, GTK_STATE_NORMAL
,
312 shadow
, &clipRect
, wxGTKPrivate::GetEntryWidget(), detail
, x
, y
, w
, h
);
318 //-----------------------------------------------------------------------------
319 // "parent_set" from m_wxwindow
320 //-----------------------------------------------------------------------------
324 parent_set(GtkWidget
* widget
, GtkWidget
* old_parent
, wxWindow
* win
)
328 g_signal_handlers_disconnect_by_func(
329 old_parent
, (void*)expose_event_border
, win
);
331 GtkWidget
* parent
= gtk_widget_get_parent(widget
);
334 g_signal_connect_after(parent
, "expose_event",
335 G_CALLBACK(expose_event_border
), win
);
339 #endif // !__WXUNIVERSAL__
341 //-----------------------------------------------------------------------------
342 // "key_press_event" from any window
343 //-----------------------------------------------------------------------------
345 // set WXTRACE to this to see the key event codes on the console
346 #define TRACE_KEYS wxT("keyevent")
348 // translates an X key symbol to WXK_XXX value
350 // if isChar is true it means that the value returned will be used for EVT_CHAR
351 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
352 // for example, while if it is false it means that the value is going to be
353 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
355 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
361 // Shift, Control and Alt don't generate the CHAR events at all
364 key_code
= isChar
? 0 : WXK_SHIFT
;
368 key_code
= isChar
? 0 : WXK_CONTROL
;
376 key_code
= isChar
? 0 : WXK_ALT
;
379 // neither do the toggle modifies
380 case GDK_Scroll_Lock
:
381 key_code
= isChar
? 0 : WXK_SCROLL
;
385 key_code
= isChar
? 0 : WXK_CAPITAL
;
389 key_code
= isChar
? 0 : WXK_NUMLOCK
;
393 // various other special keys
406 case GDK_ISO_Left_Tab
:
413 key_code
= WXK_RETURN
;
417 key_code
= WXK_CLEAR
;
421 key_code
= WXK_PAUSE
;
425 key_code
= WXK_SELECT
;
429 key_code
= WXK_PRINT
;
433 key_code
= WXK_EXECUTE
;
437 key_code
= WXK_ESCAPE
;
440 // cursor and other extended keyboard keys
442 key_code
= WXK_DELETE
;
458 key_code
= WXK_RIGHT
;
465 case GDK_Prior
: // == GDK_Page_Up
466 key_code
= WXK_PAGEUP
;
469 case GDK_Next
: // == GDK_Page_Down
470 key_code
= WXK_PAGEDOWN
;
482 key_code
= WXK_INSERT
;
497 key_code
= (isChar
? '0' : int(WXK_NUMPAD0
)) + keysym
- GDK_KP_0
;
501 key_code
= isChar
? ' ' : int(WXK_NUMPAD_SPACE
);
505 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
509 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
513 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
517 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
521 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
525 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
529 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
533 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
537 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
541 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
545 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
548 case GDK_KP_Prior
: // == GDK_KP_Page_Up
549 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
552 case GDK_KP_Next
: // == GDK_KP_Page_Down
553 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
557 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
561 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
565 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
569 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
573 key_code
= isChar
? '=' : int(WXK_NUMPAD_EQUAL
);
576 case GDK_KP_Multiply
:
577 key_code
= isChar
? '*' : int(WXK_NUMPAD_MULTIPLY
);
581 key_code
= isChar
? '+' : int(WXK_NUMPAD_ADD
);
584 case GDK_KP_Separator
:
585 // FIXME: what is this?
586 key_code
= isChar
? '.' : int(WXK_NUMPAD_SEPARATOR
);
589 case GDK_KP_Subtract
:
590 key_code
= isChar
? '-' : int(WXK_NUMPAD_SUBTRACT
);
594 key_code
= isChar
? '.' : int(WXK_NUMPAD_DECIMAL
);
598 key_code
= isChar
? '/' : int(WXK_NUMPAD_DIVIDE
);
615 key_code
= WXK_F1
+ keysym
- GDK_F1
;
625 static inline bool wxIsAsciiKeysym(KeySym ks
)
630 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
632 GdkEventKey
*gdk_event
)
634 event
.SetTimestamp( gdk_event
->time
);
635 event
.SetId(win
->GetId());
637 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
638 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
639 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
640 event
.m_metaDown
= (gdk_event
->state
& GDK_META_MASK
) != 0;
642 // Normally we take the state of modifiers directly from the low level GDK
643 // event but unfortunately GDK uses a different convention from MSW for the
644 // key events corresponding to the modifier keys themselves: in it, when
645 // e.g. Shift key is pressed, GDK_SHIFT_MASK is not set while it is set
646 // when Shift is released. Under MSW the situation is exactly reversed and
647 // the modifier corresponding to the key is set when it is pressed and
648 // unset when it is released. To ensure consistent behaviour between
649 // platforms (and because it seems to make slightly more sense, although
650 // arguably both behaviours are reasonable) we follow MSW here.
652 // Final notice: we set the flags to the desired value instead of just
653 // inverting them because they are not set correctly (i.e. in the same way
654 // as for the real events generated by the user) for wxUIActionSimulator-
655 // produced events and it seems better to keep that class code the same
656 // among all platforms and fix the discrepancy here instead of adding
657 // wxGTK-specific code to wxUIActionSimulator.
658 const bool isPress
= gdk_event
->type
== GDK_KEY_PRESS
;
659 switch ( gdk_event
->keyval
)
663 event
.m_shiftDown
= isPress
;
668 event
.m_controlDown
= isPress
;
673 event
.m_altDown
= isPress
;
680 event
.m_metaDown
= isPress
;
684 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
685 event
.m_rawFlags
= gdk_event
->hardware_keycode
;
687 wxGetMousePosition(&event
.m_x
, &event
.m_y
);
688 win
->ScreenToClient(&event
.m_x
, &event
.m_y
);
689 event
.SetEventObject( win
);
694 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
696 GdkEventKey
*gdk_event
)
698 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
699 // but only event->keyval which is quite useless to us, so remember
700 // the last character from GDK_KEY_PRESS and reuse it as last resort
702 // NB: should be MT-safe as we're always called from the main thread only
707 } s_lastKeyPress
= { 0, 0 };
709 KeySym keysym
= gdk_event
->keyval
;
711 wxLogTrace(TRACE_KEYS
, wxT("Key %s event: keysym = %ld"),
712 event
.GetEventType() == wxEVT_KEY_UP
? wxT("release")
716 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
720 // do we have the translation or is it a plain ASCII character?
721 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
723 // we should use keysym if it is ASCII as X does some translations
724 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
725 // which we don't want here (but which we do use for OnChar())
726 if ( !wxIsAsciiKeysym(keysym
) )
728 keysym
= (KeySym
)gdk_event
->string
[0];
731 // we want to always get the same key code when the same key is
732 // pressed regardless of the state of the modifiers, i.e. on a
733 // standard US keyboard pressing '5' or '%' ('5' key with
734 // Shift) should result in the same key code in OnKeyDown():
735 // '5' (although OnChar() will get either '5' or '%').
737 // to do it we first translate keysym to keycode (== scan code)
738 // and then back but always using the lower register
739 Display
*dpy
= (Display
*)wxGetDisplay();
740 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
742 wxLogTrace(TRACE_KEYS
, wxT("\t-> keycode %d"), keycode
);
744 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
746 // use the normalized, i.e. lower register, keysym if we've
748 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
750 // as explained above, we want to have lower register key codes
751 // normally but for the letter keys we want to have the upper ones
753 // NB: don't use XConvertCase() here, we want to do it for letters
755 key_code
= toupper(key_code
);
757 else // non ASCII key, what to do?
759 // by default, ignore it
762 // but if we have cached information from the last KEY_PRESS
763 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
766 if ( keysym
== s_lastKeyPress
.keysym
)
768 key_code
= s_lastKeyPress
.keycode
;
773 if ( gdk_event
->type
== GDK_KEY_PRESS
)
775 // remember it to be reused for KEY_UP event later
776 s_lastKeyPress
.keysym
= keysym
;
777 s_lastKeyPress
.keycode
= key_code
;
781 wxLogTrace(TRACE_KEYS
, wxT("\t-> wxKeyCode %ld"), key_code
);
783 // sending unknown key events doesn't really make sense
787 event
.m_keyCode
= key_code
;
790 event
.m_uniChar
= gdk_keyval_to_unicode(key_code
? key_code
: keysym
);
791 if ( !event
.m_uniChar
&& event
.m_keyCode
<= WXK_DELETE
)
793 // Set Unicode key code to the ASCII equivalent for compatibility. E.g.
794 // let RETURN generate the key event with both key and Unicode key
796 event
.m_uniChar
= event
.m_keyCode
;
798 #endif // wxUSE_UNICODE
800 // now fill all the other fields
801 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
809 GtkIMContext
*context
;
810 GdkEventKey
*lastKeyEvent
;
814 context
= gtk_im_multicontext_new();
819 g_object_unref (context
);
826 // Send wxEVT_CHAR_HOOK event to the parent of the window and return true only
827 // if it was processed (and not skipped).
828 bool SendCharHookEvent(const wxKeyEvent
& event
, wxWindow
*win
)
830 // wxEVT_CHAR_HOOK must be sent to allow the parent windows (e.g. a dialog
831 // which typically closes when Esc key is pressed in any of its controls)
832 // to handle key events in all of its children unless the mouse is captured
833 // in which case we consider that the keyboard should be "captured" too.
834 if ( !g_captureWindow
)
836 wxKeyEvent
eventCharHook(wxEVT_CHAR_HOOK
, event
);
837 if ( win
->HandleWindowEvent(eventCharHook
)
838 && !event
.IsNextEventAllowed() )
845 // Adjust wxEVT_CHAR event key code fields. This function takes care of two
847 // (a) Ctrl-letter key presses generate key codes in range 1..26
848 // (b) Unicode key codes are same as key codes for the codes in 1..255 range
849 void AdjustCharEventKeyCodes(wxKeyEvent
& event
)
851 const int code
= event
.m_keyCode
;
853 // Check for (a) above.
854 if ( event
.ControlDown() )
856 // We intentionally don't use isupper/lower() here, we really need
857 // ASCII letters only as it doesn't make sense to translate any other
858 // ones into this range which has only 26 slots.
859 if ( code
>= 'a' && code
<= 'z' )
860 event
.m_keyCode
= code
- 'a' + 1;
861 else if ( code
>= 'A' && code
<= 'Z' )
862 event
.m_keyCode
= code
- 'A' + 1;
865 // Adjust the Unicode equivalent in the same way too.
866 if ( event
.m_keyCode
!= code
)
867 event
.m_uniChar
= event
.m_keyCode
;
868 #endif // wxUSE_UNICODE
872 // Check for (b) from above.
874 // FIXME: Should we do it for key codes up to 255?
875 if ( !event
.m_uniChar
&& code
< WXK_DELETE
)
876 event
.m_uniChar
= code
;
877 #endif // wxUSE_UNICODE
880 } // anonymous namespace
884 gtk_window_key_press_callback( GtkWidget
*WXUNUSED(widget
),
885 GdkEventKey
*gdk_event
,
890 if (g_blockEventsOnDrag
)
893 wxKeyEvent
event( wxEVT_KEY_DOWN
);
895 bool return_after_IM
= false;
897 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
899 // Send the CHAR_HOOK event first
900 if ( SendCharHookEvent(event
, win
) )
902 // Don't do anything at all with this event any more.
906 // Emit KEY_DOWN event
907 ret
= win
->HandleWindowEvent( event
);
911 // Return after IM processing as we cannot do
912 // anything with it anyhow.
913 return_after_IM
= true;
916 if (!ret
&& win
->m_imData
)
918 win
->m_imData
->lastKeyEvent
= gdk_event
;
920 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
921 // docs, if IM filter returns true, no further processing should be done.
922 // we should send the key_down event anyway.
923 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
924 win
->m_imData
->lastKeyEvent
= NULL
;
925 if (intercepted_by_IM
)
927 wxLogTrace(TRACE_KEYS
, wxT("Key event intercepted by IM"));
938 wxWindowGTK
*ancestor
= win
;
941 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
944 wxCommandEvent
menu_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
945 ret
= ancestor
->HandleWindowEvent( menu_event
);
949 // if the accelerator wasn't handled as menu event, try
950 // it as button click (for compatibility with other
952 wxCommandEvent
button_event( wxEVT_COMMAND_BUTTON_CLICKED
, command
);
953 ret
= ancestor
->HandleWindowEvent( button_event
);
958 if (ancestor
->IsTopLevel())
960 ancestor
= ancestor
->GetParent();
963 #endif // wxUSE_ACCEL
965 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
966 // will only be sent if it is not in an accelerator table.
970 KeySym keysym
= gdk_event
->keyval
;
971 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
972 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
975 if ( wxIsAsciiKeysym(keysym
) )
978 key_code
= (unsigned char)keysym
;
980 // gdk_event->string is actually deprecated
981 else if ( gdk_event
->length
== 1 )
983 key_code
= (unsigned char)gdk_event
->string
[0];
989 wxKeyEvent
eventChar(wxEVT_CHAR
, event
);
991 wxLogTrace(TRACE_KEYS
, wxT("Char event: %ld"), key_code
);
993 eventChar
.m_keyCode
= key_code
;
995 AdjustCharEventKeyCodes(eventChar
);
997 ret
= win
->HandleWindowEvent(eventChar
);
1007 gtk_wxwindow_commit_cb (GtkIMContext
* WXUNUSED(context
),
1011 wxKeyEvent
event( wxEVT_CHAR
);
1013 // take modifiers, cursor position, timestamp etc. from the last
1014 // key_press_event that was fed into Input Method:
1015 if (window
->m_imData
->lastKeyEvent
)
1017 wxFillOtherKeyEventFields(event
,
1018 window
, window
->m_imData
->lastKeyEvent
);
1022 event
.SetEventObject( window
);
1025 const wxString
data(wxGTK_CONV_BACK_SYS(str
));
1029 for( wxString::const_iterator pstr
= data
.begin(); pstr
!= data
.end(); ++pstr
)
1032 event
.m_uniChar
= *pstr
;
1033 // Backward compatible for ISO-8859-1
1034 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1035 wxLogTrace(TRACE_KEYS
, wxT("IM sent character '%c'"), event
.m_uniChar
);
1037 event
.m_keyCode
= (char)*pstr
;
1038 #endif // wxUSE_UNICODE
1040 AdjustCharEventKeyCodes(event
);
1042 window
->HandleWindowEvent(event
);
1048 //-----------------------------------------------------------------------------
1049 // "key_release_event" from any window
1050 //-----------------------------------------------------------------------------
1054 gtk_window_key_release_callback( GtkWidget
* WXUNUSED(widget
),
1055 GdkEventKey
*gdk_event
,
1061 if (g_blockEventsOnDrag
)
1064 wxKeyEvent
event( wxEVT_KEY_UP
);
1065 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1067 // unknown key pressed, ignore (the event would be useless anyhow)
1071 return win
->GTKProcessEvent(event
);
1075 //-----------------------------------------------------------------------------
1076 // key and mouse events, after, from m_widget
1077 //-----------------------------------------------------------------------------
1080 static gboolean
key_and_mouse_event_after(GtkWidget
* widget
, GdkEventKey
*, wxWindow
*)
1082 // If a widget does not handle a key or mouse event, GTK+ sends it up the
1083 // parent chain until it is handled. These events are not supposed to
1084 // propagate in wxWidgets, so prevent it unless widget is in a native
1086 return WX_IS_PIZZA(gtk_widget_get_parent(widget
));
1090 // ============================================================================
1092 // ============================================================================
1094 // ----------------------------------------------------------------------------
1095 // mouse event processing helpers
1096 // ----------------------------------------------------------------------------
1098 static void AdjustEventButtonState(wxMouseEvent
& event
)
1100 // GDK reports the old state of the button for a button press event, but
1101 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1102 // for a LEFT_DOWN event, not FALSE, so we will invert
1103 // left/right/middleDown for the corresponding click events
1105 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1106 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1107 (event
.GetEventType() == wxEVT_LEFT_UP
))
1109 event
.m_leftDown
= !event
.m_leftDown
;
1113 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1114 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1115 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1117 event
.m_middleDown
= !event
.m_middleDown
;
1121 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1122 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1123 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1125 event
.m_rightDown
= !event
.m_rightDown
;
1129 if ((event
.GetEventType() == wxEVT_AUX1_DOWN
) ||
1130 (event
.GetEventType() == wxEVT_AUX1_DCLICK
))
1132 event
.m_aux1Down
= true;
1136 if ((event
.GetEventType() == wxEVT_AUX2_DOWN
) ||
1137 (event
.GetEventType() == wxEVT_AUX2_DCLICK
))
1139 event
.m_aux2Down
= true;
1144 // find the window to send the mouse event to
1146 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1151 if (win
->m_wxwindow
)
1153 wxPizza
* pizza
= WX_PIZZA(win
->m_wxwindow
);
1154 xx
+= pizza
->m_scroll_x
;
1155 yy
+= pizza
->m_scroll_y
;
1158 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1161 wxWindowGTK
*child
= node
->GetData();
1163 node
= node
->GetNext();
1164 if (!child
->IsShown())
1167 if (child
->GTKIsTransparentForMouse())
1169 // wxStaticBox is transparent in the box itself
1170 int xx1
= child
->m_x
;
1171 int yy1
= child
->m_y
;
1172 int xx2
= child
->m_x
+ child
->m_width
;
1173 int yy2
= child
->m_y
+ child
->m_height
;
1176 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1178 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1180 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1182 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1193 if ((child
->m_wxwindow
== NULL
) &&
1194 !gtk_widget_get_has_window(child
->m_widget
) &&
1195 win
->IsClientAreaChild(child
) &&
1196 (child
->m_x
<= xx
) &&
1197 (child
->m_y
<= yy
) &&
1198 (child
->m_x
+child
->m_width
>= xx
) &&
1199 (child
->m_y
+child
->m_height
>= yy
))
1212 // ----------------------------------------------------------------------------
1213 // common event handlers helpers
1214 // ----------------------------------------------------------------------------
1216 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const
1218 // nothing special at this level
1219 return HandleWindowEvent(event
);
1222 bool wxWindowGTK::GTKShouldIgnoreEvent() const
1224 return !m_hasVMT
|| g_blockEventsOnDrag
;
1227 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1231 if (g_blockEventsOnDrag
)
1233 if (g_blockEventsOnScroll
)
1236 if (!GTKIsOwnWindow(event
->window
))
1242 // overloads for all GDK event types we use here: we need to have this as
1243 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1244 // derives from it in the sense that the structs have the same layout
1245 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1246 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1248 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1251 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1252 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1253 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1255 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1257 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1258 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1262 // all event handlers must have C linkage as they're called from GTK+ C code
1266 //-----------------------------------------------------------------------------
1267 // "button_press_event"
1268 //-----------------------------------------------------------------------------
1271 gtk_window_button_press_callback( GtkWidget
*widget
,
1272 GdkEventButton
*gdk_event
,
1275 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1277 g_lastButtonNumber
= gdk_event
->button
;
1279 // GDK sends surplus button down events
1280 // before a double click event. We
1281 // need to filter these out.
1282 if ((gdk_event
->type
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
))
1284 GdkEvent
*peek_event
= gdk_event_peek();
1287 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1288 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1290 gdk_event_free( peek_event
);
1295 gdk_event_free( peek_event
);
1300 wxEventType event_type
= wxEVT_NULL
;
1302 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1303 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1305 // Reset GDK internal timestamp variables in order to disable GDK
1306 // triple click events. GDK will then next time believe no button has
1307 // been clicked just before, and send a normal button click event.
1308 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1309 display
->button_click_time
[1] = 0;
1310 display
->button_click_time
[0] = 0;
1313 if (gdk_event
->button
== 1)
1315 // note that GDK generates triple click events which are not supported
1316 // by wxWidgets but still have to be passed to the app as otherwise
1317 // clicks would simply go missing
1318 switch (gdk_event
->type
)
1320 // we shouldn't get triple clicks at all for GTK2 because we
1321 // suppress them artificially using the code above but we still
1322 // should map them to something for GTK1 and not just ignore them
1323 // as this would lose clicks
1324 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1325 case GDK_BUTTON_PRESS
:
1326 event_type
= wxEVT_LEFT_DOWN
;
1329 case GDK_2BUTTON_PRESS
:
1330 event_type
= wxEVT_LEFT_DCLICK
;
1334 // just to silence gcc warnings
1338 else if (gdk_event
->button
== 2)
1340 switch (gdk_event
->type
)
1342 case GDK_3BUTTON_PRESS
:
1343 case GDK_BUTTON_PRESS
:
1344 event_type
= wxEVT_MIDDLE_DOWN
;
1347 case GDK_2BUTTON_PRESS
:
1348 event_type
= wxEVT_MIDDLE_DCLICK
;
1355 else if (gdk_event
->button
== 3)
1357 switch (gdk_event
->type
)
1359 case GDK_3BUTTON_PRESS
:
1360 case GDK_BUTTON_PRESS
:
1361 event_type
= wxEVT_RIGHT_DOWN
;
1364 case GDK_2BUTTON_PRESS
:
1365 event_type
= wxEVT_RIGHT_DCLICK
;
1373 else if (gdk_event
->button
== 8)
1375 switch (gdk_event
->type
)
1377 case GDK_3BUTTON_PRESS
:
1378 case GDK_BUTTON_PRESS
:
1379 event_type
= wxEVT_AUX1_DOWN
;
1382 case GDK_2BUTTON_PRESS
:
1383 event_type
= wxEVT_AUX1_DCLICK
;
1391 else if (gdk_event
->button
== 9)
1393 switch (gdk_event
->type
)
1395 case GDK_3BUTTON_PRESS
:
1396 case GDK_BUTTON_PRESS
:
1397 event_type
= wxEVT_AUX2_DOWN
;
1400 case GDK_2BUTTON_PRESS
:
1401 event_type
= wxEVT_AUX2_DCLICK
;
1409 if ( event_type
== wxEVT_NULL
)
1411 // unknown mouse button or click type
1415 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1417 wxMouseEvent
event( event_type
);
1418 InitMouseEvent( win
, event
, gdk_event
);
1420 AdjustEventButtonState(event
);
1422 // find the correct window to send the event to: it may be a different one
1423 // from the one which got it at GTK+ level because some controls don't have
1424 // their own X window and thus cannot get any events.
1425 if ( !g_captureWindow
)
1426 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1428 // reset the event object and id in case win changed.
1429 event
.SetEventObject( win
);
1430 event
.SetId( win
->GetId() );
1432 bool ret
= win
->GTKProcessEvent( event
);
1433 g_lastMouseEvent
= NULL
;
1437 if ((event_type
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&
1438 (gs_currentFocus
!= win
) /* && win->IsFocusable() */)
1443 if (event_type
== wxEVT_RIGHT_DOWN
)
1445 // generate a "context menu" event: this is similar to right mouse
1446 // click under many GUIs except that it is generated differently
1447 // (right up under MSW, ctrl-click under Mac, right down here) and
1449 // (a) it's a command event and so is propagated to the parent
1450 // (b) under some ports it can be generated from kbd too
1451 // (c) it uses screen coords (because of (a))
1452 wxContextMenuEvent
evtCtx(
1455 win
->ClientToScreen(event
.GetPosition()));
1456 evtCtx
.SetEventObject(win
);
1457 return win
->GTKProcessEvent(evtCtx
);
1463 //-----------------------------------------------------------------------------
1464 // "button_release_event"
1465 //-----------------------------------------------------------------------------
1468 gtk_window_button_release_callback( GtkWidget
*WXUNUSED(widget
),
1469 GdkEventButton
*gdk_event
,
1472 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1474 g_lastButtonNumber
= 0;
1476 wxEventType event_type
= wxEVT_NULL
;
1478 switch (gdk_event
->button
)
1481 event_type
= wxEVT_LEFT_UP
;
1485 event_type
= wxEVT_MIDDLE_UP
;
1489 event_type
= wxEVT_RIGHT_UP
;
1493 event_type
= wxEVT_AUX1_UP
;
1497 event_type
= wxEVT_AUX2_UP
;
1501 // unknown button, don't process
1505 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1507 wxMouseEvent
event( event_type
);
1508 InitMouseEvent( win
, event
, gdk_event
);
1510 AdjustEventButtonState(event
);
1512 if ( !g_captureWindow
)
1513 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1515 // reset the event object and id in case win changed.
1516 event
.SetEventObject( win
);
1517 event
.SetId( win
->GetId() );
1519 bool ret
= win
->GTKProcessEvent(event
);
1521 g_lastMouseEvent
= NULL
;
1526 //-----------------------------------------------------------------------------
1527 // "motion_notify_event"
1528 //-----------------------------------------------------------------------------
1531 gtk_window_motion_notify_callback( GtkWidget
* WXUNUSED(widget
),
1532 GdkEventMotion
*gdk_event
,
1535 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1537 if (gdk_event
->is_hint
)
1541 GdkModifierType state
;
1542 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1547 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1549 wxMouseEvent
event( wxEVT_MOTION
);
1550 InitMouseEvent(win
, event
, gdk_event
);
1552 if ( g_captureWindow
)
1554 // synthesise a mouse enter or leave event if needed
1555 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1556 // This seems to be necessary and actually been added to
1557 // GDK itself in version 2.0.X
1560 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1561 if ( hasMouse
!= g_captureWindowHasMouse
)
1563 // the mouse changed window
1564 g_captureWindowHasMouse
= hasMouse
;
1566 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1567 : wxEVT_LEAVE_WINDOW
);
1568 InitMouseEvent(win
, eventM
, gdk_event
);
1569 eventM
.SetEventObject(win
);
1570 win
->GTKProcessEvent(eventM
);
1575 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1577 // reset the event object and id in case win changed.
1578 event
.SetEventObject( win
);
1579 event
.SetId( win
->GetId() );
1582 if ( !g_captureWindow
)
1584 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1585 if (win
->GTKProcessEvent( cevent
))
1587 win
->SetCursor( cevent
.GetCursor() );
1591 bool ret
= win
->GTKProcessEvent(event
);
1593 g_lastMouseEvent
= NULL
;
1598 //-----------------------------------------------------------------------------
1599 // "scroll_event" (mouse wheel event)
1600 //-----------------------------------------------------------------------------
1603 window_scroll_event_hscrollbar(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1605 if (gdk_event
->direction
!= GDK_SCROLL_LEFT
&&
1606 gdk_event
->direction
!= GDK_SCROLL_RIGHT
)
1611 GtkRange
*range
= win
->m_scrollBar
[wxWindow::ScrollDir_Horz
];
1613 if (range
&& gtk_widget_get_visible(GTK_WIDGET(range
)))
1615 GtkAdjustment
* adj
= gtk_range_get_adjustment(range
);
1616 double delta
= gtk_adjustment_get_step_increment(adj
) * 3;
1617 if (gdk_event
->direction
== GDK_SCROLL_LEFT
)
1620 gtk_range_set_value(range
, gtk_adjustment_get_value(adj
) + delta
);
1629 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1631 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1632 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1637 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1638 InitMouseEvent(win
, event
, gdk_event
);
1640 // FIXME: Get these values from GTK or GDK
1641 event
.m_linesPerAction
= 3;
1642 event
.m_wheelDelta
= 120;
1643 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1644 event
.m_wheelRotation
= 120;
1646 event
.m_wheelRotation
= -120;
1648 if (win
->GTKProcessEvent(event
))
1651 GtkRange
*range
= win
->m_scrollBar
[wxWindow::ScrollDir_Vert
];
1653 if (range
&& gtk_widget_get_visible(GTK_WIDGET(range
)))
1655 GtkAdjustment
* adj
= gtk_range_get_adjustment(range
);
1656 double delta
= gtk_adjustment_get_step_increment(adj
) * 3;
1657 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1660 gtk_range_set_value(range
, gtk_adjustment_get_value(adj
) + delta
);
1668 //-----------------------------------------------------------------------------
1670 //-----------------------------------------------------------------------------
1672 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1674 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1675 event
.SetEventObject(win
);
1676 return win
->GTKProcessEvent(event
);
1679 //-----------------------------------------------------------------------------
1681 //-----------------------------------------------------------------------------
1684 gtk_window_focus_in_callback( GtkWidget
* WXUNUSED(widget
),
1685 GdkEventFocus
*WXUNUSED(event
),
1688 return win
->GTKHandleFocusIn();
1691 //-----------------------------------------------------------------------------
1692 // "focus_out_event"
1693 //-----------------------------------------------------------------------------
1696 gtk_window_focus_out_callback( GtkWidget
* WXUNUSED(widget
),
1697 GdkEventFocus
* WXUNUSED(gdk_event
),
1700 return win
->GTKHandleFocusOut();
1703 //-----------------------------------------------------------------------------
1705 //-----------------------------------------------------------------------------
1708 wx_window_focus_callback(GtkWidget
*widget
,
1709 GtkDirectionType
WXUNUSED(direction
),
1712 // the default handler for focus signal in GtkScrolledWindow sets
1713 // focus to the window itself even if it doesn't accept focus, i.e. has no
1714 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1715 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1716 // any children which might accept focus (we know we don't accept the focus
1717 // ourselves as this signal is only connected in this case)
1718 if ( win
->GetChildren().empty() )
1719 g_signal_stop_emission_by_name(widget
, "focus");
1721 // we didn't change the focus
1725 //-----------------------------------------------------------------------------
1726 // "enter_notify_event"
1727 //-----------------------------------------------------------------------------
1730 gtk_window_enter_callback( GtkWidget
*widget
,
1731 GdkEventCrossing
*gdk_event
,
1734 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1736 // Event was emitted after a grab
1737 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1741 GdkModifierType state
= (GdkModifierType
)0;
1743 gdk_window_get_pointer(gtk_widget_get_window(widget
), &x
, &y
, &state
);
1745 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1746 InitMouseEvent(win
, event
, gdk_event
);
1747 wxPoint pt
= win
->GetClientAreaOrigin();
1748 event
.m_x
= x
+ pt
.x
;
1749 event
.m_y
= y
+ pt
.y
;
1751 if ( !g_captureWindow
)
1753 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1754 if (win
->GTKProcessEvent( cevent
))
1756 win
->SetCursor( cevent
.GetCursor() );
1760 return win
->GTKProcessEvent(event
);
1763 //-----------------------------------------------------------------------------
1764 // "leave_notify_event"
1765 //-----------------------------------------------------------------------------
1768 gtk_window_leave_callback( GtkWidget
*widget
,
1769 GdkEventCrossing
*gdk_event
,
1772 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1774 // Event was emitted after an ungrab
1775 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1777 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1781 GdkModifierType state
= (GdkModifierType
)0;
1783 gdk_window_get_pointer(gtk_widget_get_window(widget
), &x
, &y
, &state
);
1785 InitMouseEvent(win
, event
, gdk_event
);
1787 return win
->GTKProcessEvent(event
);
1790 //-----------------------------------------------------------------------------
1791 // "value_changed" from scrollbar
1792 //-----------------------------------------------------------------------------
1795 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
1797 wxEventType eventType
= win
->GTKGetScrollEventType(range
);
1798 if (eventType
!= wxEVT_NULL
)
1800 // Convert scroll event type to scrollwin event type
1801 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
1803 // find the scrollbar which generated the event
1804 wxWindowGTK::ScrollDir dir
= win
->ScrollDirFromRange(range
);
1806 // generate the corresponding wx event
1807 const int orient
= wxWindow::OrientFromScrollDir(dir
);
1808 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
1809 event
.SetEventObject(win
);
1811 win
->GTKProcessEvent(event
);
1815 //-----------------------------------------------------------------------------
1816 // "button_press_event" from scrollbar
1817 //-----------------------------------------------------------------------------
1820 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
1822 g_blockEventsOnScroll
= true;
1823 win
->m_mouseButtonDown
= true;
1828 //-----------------------------------------------------------------------------
1829 // "event_after" from scrollbar
1830 //-----------------------------------------------------------------------------
1833 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
1835 if (event
->type
== GDK_BUTTON_RELEASE
)
1837 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1839 const int orient
= wxWindow::OrientFromScrollDir(
1840 win
->ScrollDirFromRange(range
));
1841 wxScrollWinEvent
evt(wxEVT_SCROLLWIN_THUMBRELEASE
,
1842 win
->GetScrollPos(orient
), orient
);
1843 evt
.SetEventObject(win
);
1844 win
->GTKProcessEvent(evt
);
1848 //-----------------------------------------------------------------------------
1849 // "button_release_event" from scrollbar
1850 //-----------------------------------------------------------------------------
1853 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
1855 g_blockEventsOnScroll
= false;
1856 win
->m_mouseButtonDown
= false;
1857 // If thumb tracking
1858 if (win
->m_isScrolling
)
1860 win
->m_isScrolling
= false;
1861 // Hook up handler to send thumb release event after this emission is finished.
1862 // To allow setting scroll position from event handler, sending event must
1863 // be deferred until after the GtkRange handler for this signal has run
1864 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1870 //-----------------------------------------------------------------------------
1871 // "realize" from m_widget
1872 //-----------------------------------------------------------------------------
1875 gtk_window_realized_callback(GtkWidget
* WXUNUSED(widget
), wxWindowGTK
* win
)
1877 win
->GTKHandleRealized();
1880 //-----------------------------------------------------------------------------
1881 // "unrealize" from m_wxwindow
1882 //-----------------------------------------------------------------------------
1884 static void unrealize(GtkWidget
*, wxWindowGTK
* win
)
1887 gtk_im_context_set_client_window(win
->m_imData
->context
, NULL
);
1890 //-----------------------------------------------------------------------------
1891 // "size_allocate" from m_wxwindow or m_widget
1892 //-----------------------------------------------------------------------------
1895 size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxWindow
* win
)
1897 int w
= alloc
->width
;
1898 int h
= alloc
->height
;
1899 if (win
->m_wxwindow
)
1901 int border_x
, border_y
;
1902 WX_PIZZA(win
->m_wxwindow
)->get_border_widths(border_x
, border_y
);
1908 if (win
->m_oldClientWidth
!= w
|| win
->m_oldClientHeight
!= h
)
1910 win
->m_oldClientWidth
= w
;
1911 win
->m_oldClientHeight
= h
;
1912 // this callback can be connected to m_wxwindow,
1913 // so always get size from m_widget->allocation
1915 gtk_widget_get_allocation(win
->m_widget
, &a
);
1916 win
->m_width
= a
.width
;
1917 win
->m_height
= a
.height
;
1918 if (!win
->m_nativeSizeEvent
)
1920 wxSizeEvent
event(win
->GetSize(), win
->GetId());
1921 event
.SetEventObject(win
);
1922 win
->GTKProcessEvent(event
);
1927 //-----------------------------------------------------------------------------
1929 //-----------------------------------------------------------------------------
1931 #if GTK_CHECK_VERSION(2, 8, 0)
1933 gtk_window_grab_broken( GtkWidget
*,
1934 GdkEventGrabBroken
*event
,
1937 // Mouse capture has been lost involuntarily, notify the application
1938 if(!event
->keyboard
&& wxWindow::GetCapture() == win
)
1940 wxMouseCaptureLostEvent
evt( win
->GetId() );
1941 evt
.SetEventObject( win
);
1942 win
->HandleWindowEvent( evt
);
1948 //-----------------------------------------------------------------------------
1950 //-----------------------------------------------------------------------------
1953 void gtk_window_style_set_callback( GtkWidget
*WXUNUSED(widget
),
1954 GtkStyle
*previous_style
,
1957 if (win
&& previous_style
)
1959 if (win
->IsTopLevel())
1961 wxSysColourChangedEvent event
;
1962 event
.SetEventObject(win
);
1963 win
->GTKProcessEvent(event
);
1967 // Border width could change, which will change client size.
1968 // Make sure size event occurs for this
1969 win
->m_oldClientWidth
= 0;
1976 void wxWindowGTK::GTKHandleRealized()
1980 gtk_im_context_set_client_window
1983 m_wxwindow
? GTKGetDrawingWindow()
1984 : gtk_widget_get_window(m_widget
)
1988 // Use composited window if background is transparent, if supported.
1989 if (m_backgroundStyle
== wxBG_STYLE_TRANSPARENT
)
1991 #if wxGTK_HAS_COMPOSITING_SUPPORT
1992 if (IsTransparentBackgroundSupported())
1994 GdkWindow
* const window
= GTKGetDrawingWindow();
1996 gdk_window_set_composited(window
, true);
1999 #endif // wxGTK_HAS_COMPOSITING_SUPPORT
2001 // We revert to erase mode if transparency is not supported
2002 m_backgroundStyle
= wxBG_STYLE_ERASE
;
2007 // We cannot set colours and fonts before the widget
2008 // been realized, so we do this directly after realization
2009 // or otherwise in idle time
2011 if (m_needsStyleChange
)
2013 SetBackgroundStyle(GetBackgroundStyle());
2014 m_needsStyleChange
= false;
2017 wxWindowCreateEvent
event(static_cast<wxWindow
*>(this));
2018 event
.SetEventObject( this );
2019 GTKProcessEvent( event
);
2021 GTKUpdateCursor(true, false);
2024 // ----------------------------------------------------------------------------
2025 // this wxWindowBase function is implemented here (in platform-specific file)
2026 // because it is static and so couldn't be made virtual
2027 // ----------------------------------------------------------------------------
2029 wxWindow
*wxWindowBase::DoFindFocus()
2031 wxWindowGTK
*focus
= gs_pendingFocus
? gs_pendingFocus
: gs_currentFocus
;
2032 // the cast is necessary when we compile in wxUniversal mode
2033 return static_cast<wxWindow
*>(focus
);
2036 void wxWindowGTK::AddChildGTK(wxWindowGTK
* child
)
2038 wxASSERT_MSG(m_wxwindow
, "Cannot add a child to a window without a client area");
2040 // the window might have been scrolled already, we
2041 // have to adapt the position
2042 wxPizza
* pizza
= WX_PIZZA(m_wxwindow
);
2043 child
->m_x
+= pizza
->m_scroll_x
;
2044 child
->m_y
+= pizza
->m_scroll_y
;
2046 gtk_widget_set_size_request(
2047 child
->m_widget
, child
->m_width
, child
->m_height
);
2048 pizza
->put(child
->m_widget
, child
->m_x
, child
->m_y
);
2051 //-----------------------------------------------------------------------------
2053 //-----------------------------------------------------------------------------
2055 wxWindow
*wxGetActiveWindow()
2057 return wxWindow::FindFocus();
2061 wxMouseState
wxGetMouseState()
2067 GdkModifierType mask
;
2069 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2073 ms
.SetLeftDown((mask
& GDK_BUTTON1_MASK
) != 0);
2074 ms
.SetMiddleDown((mask
& GDK_BUTTON2_MASK
) != 0);
2075 ms
.SetRightDown((mask
& GDK_BUTTON3_MASK
) != 0);
2076 // see the comment in InitMouseEvent()
2077 ms
.SetAux1Down((mask
& GDK_BUTTON4_MASK
) != 0);
2078 ms
.SetAux2Down((mask
& GDK_BUTTON5_MASK
) != 0);
2080 ms
.SetControlDown((mask
& GDK_CONTROL_MASK
) != 0);
2081 ms
.SetShiftDown((mask
& GDK_SHIFT_MASK
) != 0);
2082 ms
.SetAltDown((mask
& GDK_MOD1_MASK
) != 0);
2083 ms
.SetMetaDown((mask
& GDK_META_MASK
) != 0);
2088 //-----------------------------------------------------------------------------
2090 //-----------------------------------------------------------------------------
2092 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2094 #ifdef __WXUNIVERSAL__
2095 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2096 #endif // __WXUNIVERSAL__
2098 void wxWindowGTK::Init()
2103 m_focusWidget
= NULL
;
2113 m_showOnIdle
= false;
2116 m_nativeSizeEvent
= false;
2118 m_isScrolling
= false;
2119 m_mouseButtonDown
= false;
2121 // initialize scrolling stuff
2122 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2124 m_scrollBar
[dir
] = NULL
;
2125 m_scrollPos
[dir
] = 0;
2129 m_oldClientHeight
= 0;
2131 m_clipPaintRegion
= false;
2133 m_needsStyleChange
= false;
2135 m_cursor
= *wxSTANDARD_CURSOR
;
2138 m_dirtyTabOrder
= false;
2141 wxWindowGTK::wxWindowGTK()
2146 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2151 const wxString
&name
)
2155 Create( parent
, id
, pos
, size
, style
, name
);
2158 bool wxWindowGTK::Create( wxWindow
*parent
,
2163 const wxString
&name
)
2165 // Get default border
2166 wxBorder border
= GetBorder(style
);
2168 style
&= ~wxBORDER_MASK
;
2171 if (!PreCreation( parent
, pos
, size
) ||
2172 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2174 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2178 // We should accept the native look
2180 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2181 scroll_class
->scrollbar_spacing
= 0;
2185 m_wxwindow
= wxPizza::New(m_windowStyle
);
2186 #ifndef __WXUNIVERSAL__
2187 if (HasFlag(wxPizza::BORDER_STYLES
))
2189 g_signal_connect(m_wxwindow
, "parent_set",
2190 G_CALLBACK(parent_set
), this);
2193 if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
))
2194 m_widget
= m_wxwindow
;
2197 m_widget
= gtk_scrolled_window_new( NULL
, NULL
);
2199 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2201 // There is a conflict with default bindings at GTK+
2202 // level between scrolled windows and notebooks both of which want to use
2203 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2204 // direction and notebooks for changing pages -- we decide that if we don't
2205 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2206 // means we can get working keyboard navigation in notebooks
2207 if ( !HasFlag(wxHSCROLL
) )
2210 bindings
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
));
2213 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
);
2214 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
);
2218 if (HasFlag(wxALWAYS_SHOW_SB
))
2220 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
2224 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2227 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(gtk_scrolled_window_get_hscrollbar(scrolledWindow
));
2228 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(gtk_scrolled_window_get_vscrollbar(scrolledWindow
));
2229 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2230 gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE
);
2232 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2234 // connect various scroll-related events
2235 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2237 // these handlers block mouse events to any window during scrolling
2238 // such as motion events and prevent GTK and wxWidgets from fighting
2239 // over where the slider should be
2240 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2241 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2242 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2243 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2245 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2246 G_CALLBACK(gtk_scrollbar_event_after
), this);
2247 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2249 // these handlers get notified when scrollbar slider moves
2250 g_signal_connect_after(m_scrollBar
[dir
], "value_changed",
2251 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2254 gtk_widget_show( m_wxwindow
);
2256 g_object_ref(m_widget
);
2259 m_parent
->DoAddChild( this );
2261 m_focusWidget
= m_wxwindow
;
2263 SetCanFocus(AcceptsFocus());
2270 wxWindowGTK::~wxWindowGTK()
2274 if (gs_currentFocus
== this)
2275 gs_currentFocus
= NULL
;
2276 if (gs_pendingFocus
== this)
2277 gs_pendingFocus
= NULL
;
2279 if ( gs_deferredFocusOut
== this )
2280 gs_deferredFocusOut
= NULL
;
2284 // destroy children before destroying this window itself
2287 // unhook focus handlers to prevent stray events being
2288 // propagated to this (soon to be) dead object
2289 if (m_focusWidget
!= NULL
)
2291 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2292 (gpointer
) gtk_window_focus_in_callback
,
2294 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2295 (gpointer
) gtk_window_focus_out_callback
,
2302 // delete before the widgets to avoid a crash on solaris
2306 // avoid problem with GTK+ 2.18 where a frozen window causes the whole
2307 // TLW to be frozen, and if the window is then destroyed, nothing ever
2308 // gets painted again
2314 // Note that gtk_widget_destroy() does not destroy the widget, it just
2315 // emits the "destroy" signal. The widget is not actually destroyed
2316 // until its reference count drops to zero.
2317 gtk_widget_destroy(m_widget
);
2318 // Release our reference, should be the last one
2319 g_object_unref(m_widget
);
2325 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2327 if ( GTKNeedsParent() )
2329 wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") );
2332 // Use either the given size, or the default if -1 is given.
2333 // See wxWindowBase for these functions.
2334 m_width
= WidthDefault(size
.x
) ;
2335 m_height
= HeightDefault(size
.y
);
2343 void wxWindowGTK::PostCreation()
2345 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2347 #if wxGTK_HAS_COMPOSITING_SUPPORT
2348 // Set RGBA visual as soon as possible to minimize the possibility that
2349 // somebody uses the wrong one.
2350 if ( m_backgroundStyle
== wxBG_STYLE_TRANSPARENT
&&
2351 IsTransparentBackgroundSupported() )
2353 GdkScreen
*screen
= gtk_widget_get_screen (m_widget
);
2355 GdkColormap
*rgba_colormap
= gdk_screen_get_rgba_colormap (screen
);
2358 gtk_widget_set_colormap(m_widget
, rgba_colormap
);
2360 #endif // wxGTK_HAS_COMPOSITING_SUPPORT
2366 // these get reported to wxWidgets -> wxPaintEvent
2368 g_signal_connect (m_wxwindow
, "expose_event",
2369 G_CALLBACK (gtk_window_expose_callback
), this);
2371 if (GetLayoutDirection() == wxLayout_LeftToRight
)
2372 gtk_widget_set_redraw_on_allocate(m_wxwindow
, HasFlag(wxFULL_REPAINT_ON_RESIZE
));
2375 // Create input method handler
2376 m_imData
= new wxGtkIMData
;
2378 // Cannot handle drawing preedited text yet
2379 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2381 g_signal_connect (m_imData
->context
, "commit",
2382 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2383 g_signal_connect(m_wxwindow
, "unrealize", G_CALLBACK(unrealize
), this);
2388 if (!GTK_IS_WINDOW(m_widget
))
2390 if (m_focusWidget
== NULL
)
2391 m_focusWidget
= m_widget
;
2395 g_signal_connect (m_focusWidget
, "focus_in_event",
2396 G_CALLBACK (gtk_window_focus_in_callback
), this);
2397 g_signal_connect (m_focusWidget
, "focus_out_event",
2398 G_CALLBACK (gtk_window_focus_out_callback
), this);
2402 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2403 G_CALLBACK (gtk_window_focus_in_callback
), this);
2404 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2405 G_CALLBACK (gtk_window_focus_out_callback
), this);
2409 if ( !AcceptsFocusFromKeyboard() )
2413 g_signal_connect(m_widget
, "focus",
2414 G_CALLBACK(wx_window_focus_callback
), this);
2417 // connect to the various key and mouse handlers
2419 GtkWidget
*connect_widget
= GetConnectWidget();
2421 ConnectWidget( connect_widget
);
2423 // connect handler to prevent events from propagating up parent chain
2424 g_signal_connect_after(m_widget
,
2425 "key_press_event", G_CALLBACK(key_and_mouse_event_after
), this);
2426 g_signal_connect_after(m_widget
,
2427 "key_release_event", G_CALLBACK(key_and_mouse_event_after
), this);
2428 g_signal_connect_after(m_widget
,
2429 "button_press_event", G_CALLBACK(key_and_mouse_event_after
), this);
2430 g_signal_connect_after(m_widget
,
2431 "button_release_event", G_CALLBACK(key_and_mouse_event_after
), this);
2432 g_signal_connect_after(m_widget
,
2433 "motion_notify_event", G_CALLBACK(key_and_mouse_event_after
), this);
2435 // We cannot set colours, fonts and cursors before the widget has been
2436 // realized, so we do this directly after realization -- unless the widget
2437 // was in fact realized already.
2438 if ( gtk_widget_get_realized(connect_widget
) )
2440 gtk_window_realized_callback(connect_widget
, this);
2444 g_signal_connect (connect_widget
, "realize",
2445 G_CALLBACK (gtk_window_realized_callback
), this);
2450 g_signal_connect(m_wxwindow
? m_wxwindow
: m_widget
, "size_allocate",
2451 G_CALLBACK(size_allocate
), this);
2454 #if GTK_CHECK_VERSION(2, 8, 0)
2455 if ( gtk_check_version(2,8,0) == NULL
)
2457 // Make sure we can notify the app when mouse capture is lost
2460 g_signal_connect (m_wxwindow
, "grab_broken_event",
2461 G_CALLBACK (gtk_window_grab_broken
), this);
2464 if ( connect_widget
!= m_wxwindow
)
2466 g_signal_connect (connect_widget
, "grab_broken_event",
2467 G_CALLBACK (gtk_window_grab_broken
), this);
2470 #endif // GTK+ >= 2.8
2472 if ( GTKShouldConnectSizeRequest() )
2474 // This is needed if we want to add our windows into native
2475 // GTK controls, such as the toolbar. With this callback, the
2476 // toolbar gets to know the correct size (the one set by the
2477 // programmer). Sadly, it misbehaves for wxComboBox.
2478 g_signal_connect (m_widget
, "size_request",
2479 G_CALLBACK (wxgtk_window_size_request_callback
),
2483 InheritAttributes();
2487 SetLayoutDirection(wxLayout_Default
);
2489 // unless the window was created initially hidden (i.e. Hide() had been
2490 // called before Create()), we should show it at GTK+ level as well
2492 gtk_widget_show( m_widget
);
2496 wxWindowGTK::GTKConnectWidget(const char *signal
, wxGTKCallback callback
)
2498 return g_signal_connect(m_widget
, signal
, callback
, this);
2501 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2503 g_signal_connect (widget
, "key_press_event",
2504 G_CALLBACK (gtk_window_key_press_callback
), this);
2505 g_signal_connect (widget
, "key_release_event",
2506 G_CALLBACK (gtk_window_key_release_callback
), this);
2507 g_signal_connect (widget
, "button_press_event",
2508 G_CALLBACK (gtk_window_button_press_callback
), this);
2509 g_signal_connect (widget
, "button_release_event",
2510 G_CALLBACK (gtk_window_button_release_callback
), this);
2511 g_signal_connect (widget
, "motion_notify_event",
2512 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2514 g_signal_connect (widget
, "scroll_event",
2515 G_CALLBACK (window_scroll_event
), this);
2516 if (m_scrollBar
[ScrollDir_Horz
])
2517 g_signal_connect (m_scrollBar
[ScrollDir_Horz
], "scroll_event",
2518 G_CALLBACK (window_scroll_event_hscrollbar
), this);
2519 if (m_scrollBar
[ScrollDir_Vert
])
2520 g_signal_connect (m_scrollBar
[ScrollDir_Vert
], "scroll_event",
2521 G_CALLBACK (window_scroll_event
), this);
2523 g_signal_connect (widget
, "popup_menu",
2524 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2525 g_signal_connect (widget
, "enter_notify_event",
2526 G_CALLBACK (gtk_window_enter_callback
), this);
2527 g_signal_connect (widget
, "leave_notify_event",
2528 G_CALLBACK (gtk_window_leave_callback
), this);
2530 if (m_wxwindow
&& (IsTopLevel() || HasFlag(wxBORDER_RAISED
| wxBORDER_SUNKEN
| wxBORDER_THEME
)))
2531 g_signal_connect (m_wxwindow
, "style_set",
2532 G_CALLBACK (gtk_window_style_set_callback
), this);
2535 bool wxWindowGTK::Destroy()
2539 return wxWindowBase::Destroy();
2542 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2544 gtk_widget_set_size_request(m_widget
, width
, height
);
2546 // inform the parent to perform the move
2547 wxASSERT_MSG(m_parent
&& m_parent
->m_wxwindow
,
2548 "the parent window has no client area?");
2549 WX_PIZZA(m_parent
->m_wxwindow
)->move(m_widget
, x
, y
);
2552 void wxWindowGTK::ConstrainSize()
2555 // GPE's window manager doesn't like size hints at all, esp. when the user
2556 // has to use the virtual keyboard, so don't constrain size there
2560 const wxSize minSize
= GetMinSize();
2561 const wxSize maxSize
= GetMaxSize();
2562 if (minSize
.x
> 0 && m_width
< minSize
.x
) m_width
= minSize
.x
;
2563 if (minSize
.y
> 0 && m_height
< minSize
.y
) m_height
= minSize
.y
;
2564 if (maxSize
.x
> 0 && m_width
> maxSize
.x
) m_width
= maxSize
.x
;
2565 if (maxSize
.y
> 0 && m_height
> maxSize
.y
) m_height
= maxSize
.y
;
2569 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2571 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2572 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2574 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0 && (x
== -1 || y
== -1))
2576 int currentX
, currentY
;
2577 GetPosition(¤tX
, ¤tY
);
2583 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2585 // calculate the best size if we should auto size the window
2586 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2587 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2589 const wxSize sizeBest
= GetBestSize();
2590 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2592 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2593 height
= sizeBest
.y
;
2596 const wxSize
oldSize(m_width
, m_height
);
2602 if (m_parent
->m_wxwindow
)
2604 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2605 m_x
= x
+ pizza
->m_scroll_x
;
2606 m_y
= y
+ pizza
->m_scroll_y
;
2608 int left_border
= 0;
2609 int right_border
= 0;
2611 int bottom_border
= 0;
2613 /* the default button has a border around it */
2614 if (gtk_widget_get_can_default(m_widget
))
2616 GtkBorder
*default_border
= NULL
;
2617 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2620 left_border
+= default_border
->left
;
2621 right_border
+= default_border
->right
;
2622 top_border
+= default_border
->top
;
2623 bottom_border
+= default_border
->bottom
;
2624 gtk_border_free( default_border
);
2628 DoMoveWindow( m_x
- left_border
,
2630 m_width
+left_border
+right_border
,
2631 m_height
+top_border
+bottom_border
);
2634 if (m_width
!= oldSize
.x
|| m_height
!= oldSize
.y
)
2636 // update these variables to keep size_allocate handler
2637 // from sending another size event for this change
2638 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2640 gtk_widget_queue_resize(m_widget
);
2641 if (!m_nativeSizeEvent
)
2643 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2644 event
.SetEventObject( this );
2645 HandleWindowEvent( event
);
2648 if (sizeFlags
& wxSIZE_FORCE_EVENT
)
2650 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2651 event
.SetEventObject( this );
2652 HandleWindowEvent( event
);
2656 bool wxWindowGTK::GTKShowFromOnIdle()
2658 if (IsShown() && m_showOnIdle
&& !gtk_widget_get_visible (m_widget
))
2660 GtkAllocation alloc
;
2663 alloc
.width
= m_width
;
2664 alloc
.height
= m_height
;
2665 gtk_widget_size_allocate( m_widget
, &alloc
);
2666 gtk_widget_show( m_widget
);
2667 wxShowEvent
eventShow(GetId(), true);
2668 eventShow
.SetEventObject(this);
2669 HandleWindowEvent(eventShow
);
2670 m_showOnIdle
= false;
2677 void wxWindowGTK::OnInternalIdle()
2679 if ( gs_deferredFocusOut
)
2680 GTKHandleDeferredFocusOut();
2682 // Check if we have to show window now
2683 if (GTKShowFromOnIdle()) return;
2685 if ( m_dirtyTabOrder
)
2687 m_dirtyTabOrder
= false;
2691 wxWindowBase::OnInternalIdle();
2694 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2696 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2698 if (width
) (*width
) = m_width
;
2699 if (height
) (*height
) = m_height
;
2702 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2704 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2706 const wxSize size
= GetSize();
2707 const wxSize clientSize
= GetClientSize();
2708 SetSize(width
+ (size
.x
- clientSize
.x
), height
+ (size
.y
- clientSize
.y
));
2711 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2713 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2720 // if window is scrollable, account for scrollbars
2721 if ( GTK_IS_SCROLLED_WINDOW(m_widget
) )
2723 GtkPolicyType policy
[ScrollDir_Max
];
2724 gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(m_widget
),
2725 &policy
[ScrollDir_Horz
],
2726 &policy
[ScrollDir_Vert
]);
2728 for ( int i
= 0; i
< ScrollDir_Max
; i
++ )
2730 // don't account for the scrollbars we don't have
2731 GtkRange
* const range
= m_scrollBar
[i
];
2735 // nor for the ones we have but don't current show
2736 switch ( policy
[i
] )
2738 case GTK_POLICY_NEVER
:
2739 // never shown so doesn't take any place
2742 case GTK_POLICY_ALWAYS
:
2743 // no checks necessary
2746 case GTK_POLICY_AUTOMATIC
:
2747 // may be shown or not, check
2748 GtkAdjustment
*adj
= gtk_range_get_adjustment(range
);
2749 if (gtk_adjustment_get_upper(adj
) <= gtk_adjustment_get_page_size(adj
))
2753 GtkScrolledWindowClass
*scroll_class
=
2754 GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2757 gtk_widget_size_request(GTK_WIDGET(range
), &req
);
2758 if (i
== ScrollDir_Horz
)
2759 h
-= req
.height
+ scroll_class
->scrollbar_spacing
;
2761 w
-= req
.width
+ scroll_class
->scrollbar_spacing
;
2765 const wxSize sizeBorders
= DoGetBorderSize();
2775 if (width
) *width
= w
;
2776 if (height
) *height
= h
;
2779 wxSize
wxWindowGTK::DoGetBorderSize() const
2782 return wxWindowBase::DoGetBorderSize();
2785 WX_PIZZA(m_wxwindow
)->get_border_widths(x
, y
);
2787 return 2*wxSize(x
, y
);
2790 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2792 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2796 if (!IsTopLevel() && m_parent
&& m_parent
->m_wxwindow
)
2798 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2799 dx
= pizza
->m_scroll_x
;
2800 dy
= pizza
->m_scroll_y
;
2803 if (m_x
== -1 && m_y
== -1)
2805 GdkWindow
*source
= NULL
;
2807 source
= gtk_widget_get_window(m_wxwindow
);
2809 source
= gtk_widget_get_window(m_widget
);
2815 gdk_window_get_origin( source
, &org_x
, &org_y
);
2818 m_parent
->ScreenToClient(&org_x
, &org_y
);
2820 const_cast<wxWindowGTK
*>(this)->m_x
= org_x
;
2821 const_cast<wxWindowGTK
*>(this)->m_y
= org_y
;
2825 if (x
) (*x
) = m_x
- dx
;
2826 if (y
) (*y
) = m_y
- dy
;
2829 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2831 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2833 if (gtk_widget_get_window(m_widget
) == NULL
) return;
2835 GdkWindow
*source
= NULL
;
2837 source
= gtk_widget_get_window(m_wxwindow
);
2839 source
= gtk_widget_get_window(m_widget
);
2843 gdk_window_get_origin( source
, &org_x
, &org_y
);
2847 if (!gtk_widget_get_has_window(m_widget
))
2850 gtk_widget_get_allocation(m_widget
, &a
);
2859 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2860 *x
= (GetClientSize().x
- *x
) + org_x
;
2868 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
2870 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2872 if (!gtk_widget_get_realized(m_widget
)) return;
2874 GdkWindow
*source
= NULL
;
2876 source
= gtk_widget_get_window(m_wxwindow
);
2878 source
= gtk_widget_get_window(m_widget
);
2882 gdk_window_get_origin( source
, &org_x
, &org_y
);
2886 if (!gtk_widget_get_has_window(m_widget
))
2889 gtk_widget_get_allocation(m_widget
, &a
);
2897 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2898 *x
= (GetClientSize().x
- *x
) - org_x
;
2905 bool wxWindowGTK::Show( bool show
)
2907 if ( !wxWindowBase::Show(show
) )
2913 // notice that we may call Hide() before the window is created and this is
2914 // actually useful to create it hidden initially -- but we can't call
2915 // Show() before it is created
2918 wxASSERT_MSG( !show
, "can't show invalid window" );
2926 // defer until later
2930 gtk_widget_show(m_widget
);
2934 gtk_widget_hide(m_widget
);
2937 wxShowEvent
eventShow(GetId(), show
);
2938 eventShow
.SetEventObject(this);
2939 HandleWindowEvent(eventShow
);
2944 void wxWindowGTK::DoEnable( bool enable
)
2946 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2948 gtk_widget_set_sensitive( m_widget
, enable
);
2949 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2950 gtk_widget_set_sensitive( m_wxwindow
, enable
);
2953 int wxWindowGTK::GetCharHeight() const
2955 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
2957 wxFont font
= GetFont();
2958 wxCHECK_MSG( font
.IsOk(), 12, wxT("invalid font") );
2960 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2965 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2966 PangoLayout
*layout
= pango_layout_new(context
);
2967 pango_layout_set_font_description(layout
, desc
);
2968 pango_layout_set_text(layout
, "H", 1);
2969 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2971 PangoRectangle rect
;
2972 pango_layout_line_get_extents(line
, NULL
, &rect
);
2974 g_object_unref (layout
);
2976 return (int) PANGO_PIXELS(rect
.height
);
2979 int wxWindowGTK::GetCharWidth() const
2981 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
2983 wxFont font
= GetFont();
2984 wxCHECK_MSG( font
.IsOk(), 8, wxT("invalid font") );
2986 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2991 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2992 PangoLayout
*layout
= pango_layout_new(context
);
2993 pango_layout_set_font_description(layout
, desc
);
2994 pango_layout_set_text(layout
, "g", 1);
2995 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2997 PangoRectangle rect
;
2998 pango_layout_line_get_extents(line
, NULL
, &rect
);
3000 g_object_unref (layout
);
3002 return (int) PANGO_PIXELS(rect
.width
);
3005 void wxWindowGTK::DoGetTextExtent( const wxString
& string
,
3009 int *externalLeading
,
3010 const wxFont
*theFont
) const
3012 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3014 wxCHECK_RET( fontToUse
.IsOk(), wxT("invalid font") );
3023 PangoContext
*context
= NULL
;
3025 context
= gtk_widget_get_pango_context( m_widget
);
3034 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3035 PangoLayout
*layout
= pango_layout_new(context
);
3036 pango_layout_set_font_description(layout
, desc
);
3038 const wxCharBuffer data
= wxGTK_CONV( string
);
3040 pango_layout_set_text(layout
, data
, strlen(data
));
3043 PangoRectangle rect
;
3044 pango_layout_get_extents(layout
, NULL
, &rect
);
3046 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3047 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3050 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3051 int baseline
= pango_layout_iter_get_baseline(iter
);
3052 pango_layout_iter_free(iter
);
3053 *descent
= *y
- PANGO_PIXELS(baseline
);
3055 if (externalLeading
) (*externalLeading
) = 0; // ??
3057 g_object_unref (layout
);
3060 void wxWindowGTK::GTKDisableFocusOutEvent()
3062 g_signal_handlers_block_by_func( m_focusWidget
,
3063 (gpointer
) gtk_window_focus_out_callback
, this);
3066 void wxWindowGTK::GTKEnableFocusOutEvent()
3068 g_signal_handlers_unblock_by_func( m_focusWidget
,
3069 (gpointer
) gtk_window_focus_out_callback
, this);
3072 bool wxWindowGTK::GTKHandleFocusIn()
3074 // Disable default focus handling for custom windows since the default GTK+
3075 // handler issues a repaint
3076 const bool retval
= m_wxwindow
? true : false;
3079 // NB: if there's still unprocessed deferred focus-out event (see
3080 // GTKHandleFocusOut() for explanation), we need to process it first so
3081 // that the order of focus events -- focus-out first, then focus-in
3082 // elsewhere -- is preserved
3083 if ( gs_deferredFocusOut
)
3085 if ( GTKNeedsToFilterSameWindowFocus() &&
3086 gs_deferredFocusOut
== this )
3088 // GTK+ focus changed from this wxWindow back to itself, so don't
3089 // emit any events at all
3090 wxLogTrace(TRACE_FOCUS
,
3091 "filtered out spurious focus change within %s(%p, %s)",
3092 GetClassInfo()->GetClassName(), this, GetLabel());
3093 gs_deferredFocusOut
= NULL
;
3097 // otherwise we need to send focus-out first
3098 wxASSERT_MSG ( gs_deferredFocusOut
!= this,
3099 "GTKHandleFocusIn(GTKFocus_Normal) called even though focus changed back to itself - derived class should handle this" );
3100 GTKHandleDeferredFocusOut();
3104 wxLogTrace(TRACE_FOCUS
,
3105 "handling focus_in event for %s(%p, %s)",
3106 GetClassInfo()->GetClassName(), this, GetLabel());
3109 gtk_im_context_focus_in(m_imData
->context
);
3111 gs_currentFocus
= this;
3112 gs_pendingFocus
= NULL
;
3115 // caret needs to be informed about focus change
3116 wxCaret
*caret
= GetCaret();
3119 caret
->OnSetFocus();
3121 #endif // wxUSE_CARET
3123 // Notify the parent keeping track of focus for the kbd navigation
3124 // purposes that we got it.
3125 wxChildFocusEvent
eventChildFocus(static_cast<wxWindow
*>(this));
3126 GTKProcessEvent(eventChildFocus
);
3128 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, GetId());
3129 eventFocus
.SetEventObject(this);
3130 GTKProcessEvent(eventFocus
);
3135 bool wxWindowGTK::GTKHandleFocusOut()
3137 // Disable default focus handling for custom windows since the default GTK+
3138 // handler issues a repaint
3139 const bool retval
= m_wxwindow
? true : false;
3142 // NB: If a control is composed of several GtkWidgets and when focus
3143 // changes from one of them to another within the same wxWindow, we get
3144 // a focus-out event followed by focus-in for another GtkWidget owned
3145 // by the same wx control. We don't want to generate two spurious
3146 // wxEVT_SET_FOCUS events in this case, so we defer sending wx events
3147 // from GTKHandleFocusOut() until we know for sure it's not coming back
3148 // (i.e. in GTKHandleFocusIn() or at idle time).
3149 if ( GTKNeedsToFilterSameWindowFocus() )
3151 wxASSERT_MSG( gs_deferredFocusOut
== NULL
,
3152 "deferred focus out event already pending" );
3153 wxLogTrace(TRACE_FOCUS
,
3154 "deferring focus_out event for %s(%p, %s)",
3155 GetClassInfo()->GetClassName(), this, GetLabel());
3156 gs_deferredFocusOut
= this;
3160 GTKHandleFocusOutNoDeferring();
3165 void wxWindowGTK::GTKHandleFocusOutNoDeferring()
3167 wxLogTrace(TRACE_FOCUS
,
3168 "handling focus_out event for %s(%p, %s)",
3169 GetClassInfo()->GetClassName(), this, GetLabel());
3172 gtk_im_context_focus_out(m_imData
->context
);
3174 if ( gs_currentFocus
!= this )
3176 // Something is terribly wrong, gs_currentFocus is out of sync with the
3177 // real focus. We will reset it to NULL anyway, because after this
3178 // focus-out event is handled, one of the following with happen:
3180 // * either focus will go out of the app altogether, in which case
3181 // gs_currentFocus _should_ be NULL
3183 // * or it goes to another control, in which case focus-in event will
3184 // follow immediately and it will set gs_currentFocus to the right
3186 wxLogDebug("window %s(%p, %s) lost focus even though it didn't have it",
3187 GetClassInfo()->GetClassName(), this, GetLabel());
3189 gs_currentFocus
= NULL
;
3192 // caret needs to be informed about focus change
3193 wxCaret
*caret
= GetCaret();
3196 caret
->OnKillFocus();
3198 #endif // wxUSE_CARET
3200 wxFocusEvent
event( wxEVT_KILL_FOCUS
, GetId() );
3201 event
.SetEventObject( this );
3202 event
.SetWindow( FindFocus() );
3203 GTKProcessEvent( event
);
3207 void wxWindowGTK::GTKHandleDeferredFocusOut()
3209 // NB: See GTKHandleFocusOut() for explanation. This function is called
3210 // from either GTKHandleFocusIn() or OnInternalIdle() to process
3212 if ( gs_deferredFocusOut
)
3214 wxWindowGTK
*win
= gs_deferredFocusOut
;
3215 gs_deferredFocusOut
= NULL
;
3217 wxLogTrace(TRACE_FOCUS
,
3218 "processing deferred focus_out event for %s(%p, %s)",
3219 win
->GetClassInfo()->GetClassName(), win
, win
->GetLabel());
3221 win
->GTKHandleFocusOutNoDeferring();
3225 void wxWindowGTK::SetFocus()
3227 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3229 // Setting "physical" focus is not immediate in GTK+ and while
3230 // gtk_widget_is_focus ("determines if the widget is the focus widget
3231 // within its toplevel", i.e. returns true for one widget per TLW, not
3232 // globally) returns true immediately after grabbing focus,
3233 // GTK_WIDGET_HAS_FOCUS (which returns true only for the one widget that
3234 // has focus at the moment) takes effect only after the window is shown
3235 // (if it was hidden at the moment of the call) or at the next event loop
3238 // Because we want to FindFocus() call immediately following
3239 // foo->SetFocus() to return foo, we have to keep track of "pending" focus
3241 gs_pendingFocus
= this;
3243 GtkWidget
*widget
= m_wxwindow
? m_wxwindow
: m_focusWidget
;
3245 if ( GTK_IS_CONTAINER(widget
) &&
3246 !gtk_widget_get_can_focus(widget
) )
3248 wxLogTrace(TRACE_FOCUS
,
3249 wxT("Setting focus to a child of %s(%p, %s)"),
3250 GetClassInfo()->GetClassName(), this, GetLabel().c_str());
3251 gtk_widget_child_focus(widget
, GTK_DIR_TAB_FORWARD
);
3255 wxLogTrace(TRACE_FOCUS
,
3256 wxT("Setting focus to %s(%p, %s)"),
3257 GetClassInfo()->GetClassName(), this, GetLabel().c_str());
3258 gtk_widget_grab_focus(widget
);
3262 void wxWindowGTK::SetCanFocus(bool canFocus
)
3264 gtk_widget_set_can_focus(m_widget
, canFocus
);
3266 if ( m_wxwindow
&& (m_widget
!= m_wxwindow
) )
3268 gtk_widget_set_can_focus(m_wxwindow
, canFocus
);
3272 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3274 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3276 wxWindowGTK
* const newParent
= (wxWindowGTK
*)newParentBase
;
3278 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3280 if ( !wxWindowBase::Reparent(newParent
) )
3283 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3285 // Notice that old m_parent pointer might be non-NULL here but the widget
3286 // still not have any parent at GTK level if it's a notebook page that had
3287 // been removed from the notebook so test this at GTK level and not wx one.
3288 if ( GtkWidget
*parentGTK
= gtk_widget_get_parent(m_widget
) )
3289 gtk_container_remove(GTK_CONTAINER(parentGTK
), m_widget
);
3291 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3295 if (gtk_widget_get_visible (newParent
->m_widget
))
3297 m_showOnIdle
= true;
3298 gtk_widget_hide( m_widget
);
3300 /* insert GTK representation */
3301 newParent
->AddChildGTK(this);
3304 SetLayoutDirection(wxLayout_Default
);
3309 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3311 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3312 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3317 /* insert GTK representation */
3321 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3323 wxWindowBase::AddChild(child
);
3324 m_dirtyTabOrder
= true;
3325 wxTheApp
->WakeUpIdle();
3328 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3330 wxWindowBase::RemoveChild(child
);
3331 m_dirtyTabOrder
= true;
3332 wxTheApp
->WakeUpIdle();
3336 wxLayoutDirection
wxWindowGTK::GTKGetLayout(GtkWidget
*widget
)
3338 return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
3339 ? wxLayout_RightToLeft
3340 : wxLayout_LeftToRight
;
3344 void wxWindowGTK::GTKSetLayout(GtkWidget
*widget
, wxLayoutDirection dir
)
3346 wxASSERT_MSG( dir
!= wxLayout_Default
, wxT("invalid layout direction") );
3348 gtk_widget_set_direction(widget
,
3349 dir
== wxLayout_RightToLeft
? GTK_TEXT_DIR_RTL
3350 : GTK_TEXT_DIR_LTR
);
3353 wxLayoutDirection
wxWindowGTK::GetLayoutDirection() const
3355 return GTKGetLayout(m_widget
);
3358 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
)
3360 if ( dir
== wxLayout_Default
)
3362 const wxWindow
*const parent
= GetParent();
3365 // inherit layout from parent.
3366 dir
= parent
->GetLayoutDirection();
3368 else // no parent, use global default layout
3370 dir
= wxTheApp
->GetLayoutDirection();
3374 if ( dir
== wxLayout_Default
)
3377 GTKSetLayout(m_widget
, dir
);
3379 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3380 GTKSetLayout(m_wxwindow
, dir
);
3384 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
,
3385 wxCoord
WXUNUSED(width
),
3386 wxCoord
WXUNUSED(widthTotal
)) const
3388 // We now mirror the coordinates of RTL windows in wxPizza
3392 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, WindowOrder move
)
3394 wxWindowBase::DoMoveInTabOrder(win
, move
);
3395 m_dirtyTabOrder
= true;
3396 wxTheApp
->WakeUpIdle();
3399 bool wxWindowGTK::DoNavigateIn(int flags
)
3401 if ( flags
& wxNavigationKeyEvent::WinChange
)
3403 wxFAIL_MSG( wxT("not implemented") );
3407 else // navigate inside the container
3409 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3410 wxCHECK_MSG( parent
, false, wxT("every window must have a TLW parent") );
3412 GtkDirectionType dir
;
3413 dir
= flags
& wxNavigationKeyEvent::IsForward
? GTK_DIR_TAB_FORWARD
3414 : GTK_DIR_TAB_BACKWARD
;
3417 g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
);
3423 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3425 // none needed by default
3429 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3431 // nothing to do by default since none is needed
3434 void wxWindowGTK::RealizeTabOrder()
3438 if ( !m_children
.empty() )
3440 // we don't only construct the correct focus chain but also use
3441 // this opportunity to update the mnemonic widgets for the widgets
3444 GList
*chain
= NULL
;
3445 wxWindowGTK
* mnemonicWindow
= NULL
;
3447 for ( wxWindowList::const_iterator i
= m_children
.begin();
3448 i
!= m_children
.end();
3451 wxWindowGTK
*win
= *i
;
3453 bool focusableFromKeyboard
= win
->AcceptsFocusFromKeyboard();
3455 if ( mnemonicWindow
)
3457 if ( focusableFromKeyboard
)
3459 // wxComboBox et al. needs to focus on on a different
3460 // widget than m_widget, so if the main widget isn't
3461 // focusable try the connect widget
3462 GtkWidget
* w
= win
->m_widget
;
3463 if ( !gtk_widget_get_can_focus(w
) )
3465 w
= win
->GetConnectWidget();
3466 if ( !gtk_widget_get_can_focus(w
) )
3472 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3473 mnemonicWindow
= NULL
;
3477 else if ( win
->GTKWidgetNeedsMnemonic() )
3479 mnemonicWindow
= win
;
3482 if ( focusableFromKeyboard
)
3483 chain
= g_list_prepend(chain
, win
->m_widget
);
3486 chain
= g_list_reverse(chain
);
3488 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3493 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3498 void wxWindowGTK::Raise()
3500 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3502 if (m_wxwindow
&& gtk_widget_get_window(m_wxwindow
))
3504 gdk_window_raise(gtk_widget_get_window(m_wxwindow
));
3506 else if (gtk_widget_get_window(m_widget
))
3508 gdk_window_raise(gtk_widget_get_window(m_widget
));
3512 void wxWindowGTK::Lower()
3514 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3516 if (m_wxwindow
&& gtk_widget_get_window(m_wxwindow
))
3518 gdk_window_lower(gtk_widget_get_window(m_wxwindow
));
3520 else if (gtk_widget_get_window(m_widget
))
3522 gdk_window_lower(gtk_widget_get_window(m_widget
));
3526 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3528 if ( !wxWindowBase::SetCursor(cursor
.IsOk() ? cursor
: *wxSTANDARD_CURSOR
) )
3536 void wxWindowGTK::GTKUpdateCursor(bool update_self
/*=true*/, bool recurse
/*=true*/)
3540 wxCursor
cursor(g_globalCursor
.IsOk() ? g_globalCursor
: GetCursor());
3541 if ( cursor
.IsOk() )
3543 wxArrayGdkWindows windowsThis
;
3544 GdkWindow
* window
= GTKGetWindow(windowsThis
);
3546 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3549 const size_t count
= windowsThis
.size();
3550 for ( size_t n
= 0; n
< count
; n
++ )
3552 GdkWindow
*win
= windowsThis
[n
];
3553 // It can be zero if the window has not been realized yet.
3556 gdk_window_set_cursor(win
, cursor
.GetCursor());
3565 for (wxWindowList::iterator it
= GetChildren().begin(); it
!= GetChildren().end(); ++it
)
3567 (*it
)->GTKUpdateCursor( true );
3572 void wxWindowGTK::WarpPointer( int x
, int y
)
3574 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3576 ClientToScreen(&x
, &y
);
3577 GdkDisplay
* display
= gtk_widget_get_display(m_widget
);
3578 GdkScreen
* screen
= gtk_widget_get_screen(m_widget
);
3580 GdkDeviceManager
* manager
= gdk_display_get_device_manager(display
);
3581 gdk_device_warp(gdk_device_manager_get_client_pointer(manager
), screen
, x
, y
);
3583 XWarpPointer(GDK_DISPLAY_XDISPLAY(display
),
3585 GDK_WINDOW_XID(gdk_screen_get_root_window(screen
)),
3590 wxWindowGTK::ScrollDir
wxWindowGTK::ScrollDirFromRange(GtkRange
*range
) const
3592 // find the scrollbar which generated the event
3593 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3595 if ( range
== m_scrollBar
[dir
] )
3596 return (ScrollDir
)dir
;
3599 wxFAIL_MSG( wxT("event from unknown scrollbar received") );
3601 return ScrollDir_Max
;
3604 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3606 bool changed
= false;
3607 GtkRange
* range
= m_scrollBar
[dir
];
3608 if ( range
&& units
)
3610 GtkAdjustment
* adj
= gtk_range_get_adjustment(range
);
3611 double inc
= unit
== ScrollUnit_Line
? gtk_adjustment_get_step_increment(adj
)
3612 : gtk_adjustment_get_page_increment(adj
);
3614 const int posOld
= wxRound(gtk_adjustment_get_value(adj
));
3615 gtk_range_set_value(range
, posOld
+ units
*inc
);
3617 changed
= wxRound(gtk_adjustment_get_value(adj
)) != posOld
;
3623 bool wxWindowGTK::ScrollLines(int lines
)
3625 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3628 bool wxWindowGTK::ScrollPages(int pages
)
3630 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3633 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground
),
3638 if (gtk_widget_get_mapped(m_wxwindow
))
3640 GdkWindow
* window
= gtk_widget_get_window(m_wxwindow
);
3643 GdkRectangle r
= { rect
->x
, rect
->y
, rect
->width
, rect
->height
};
3644 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3645 r
.x
= gdk_window_get_width(window
) - r
.x
- rect
->width
;
3646 gdk_window_invalidate_rect(window
, &r
, true);
3649 gdk_window_invalidate_rect(window
, NULL
, true);
3654 if (gtk_widget_get_mapped(m_widget
))
3657 gtk_widget_queue_draw_area(m_widget
, rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3659 gtk_widget_queue_draw(m_widget
);
3664 void wxWindowGTK::Update()
3666 if (m_widget
&& gtk_widget_get_mapped(m_widget
))
3668 GdkDisplay
* display
= gtk_widget_get_display(m_widget
);
3669 // Flush everything out to the server, and wait for it to finish.
3670 // This ensures nothing will overwrite the drawing we are about to do.
3671 gdk_display_sync(display
);
3673 GdkWindow
* window
= GTKGetDrawingWindow();
3675 window
= gtk_widget_get_window(m_widget
);
3676 gdk_window_process_updates(window
, true);
3678 // Flush again, but no need to wait for it to finish
3679 gdk_display_flush(display
);
3683 bool wxWindowGTK::DoIsExposed( int x
, int y
) const
3685 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
3688 bool wxWindowGTK::DoIsExposed( int x
, int y
, int w
, int h
) const
3690 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3691 return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
;
3693 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
3696 void wxWindowGTK::GtkSendPaintEvents()
3700 m_updateRegion
.Clear();
3703 #if wxGTK_HAS_COMPOSITING_SUPPORT
3706 // Clip to paint region in wxClientDC
3707 m_clipPaintRegion
= true;
3709 m_nativeUpdateRegion
= m_updateRegion
;
3711 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3713 // Transform m_updateRegion under RTL
3714 m_updateRegion
.Clear();
3717 gdk_drawable_get_size(gtk_widget_get_window(m_wxwindow
), &width
, NULL
);
3719 wxRegionIterator
upd( m_nativeUpdateRegion
);
3723 rect
.x
= upd
.GetX();
3724 rect
.y
= upd
.GetY();
3725 rect
.width
= upd
.GetWidth();
3726 rect
.height
= upd
.GetHeight();
3728 rect
.x
= width
- rect
.x
- rect
.width
;
3729 m_updateRegion
.Union( rect
);
3735 switch ( GetBackgroundStyle() )
3737 case wxBG_STYLE_TRANSPARENT
:
3738 #if wxGTK_HAS_COMPOSITING_SUPPORT
3739 if (IsTransparentBackgroundSupported())
3741 // Set a transparent background, so that overlaying in parent
3742 // might indeed let see through where this child did not
3743 // explicitly paint.
3744 // NB: it works also for top level windows (but this is the
3745 // windows manager which then does the compositing job)
3746 cr
= gdk_cairo_create(m_wxwindow
->window
);
3747 gdk_cairo_region(cr
, m_nativeUpdateRegion
.GetRegion());
3750 cairo_set_operator(cr
, CAIRO_OPERATOR_CLEAR
);
3752 cairo_set_operator(cr
, CAIRO_OPERATOR_OVER
);
3753 cairo_surface_flush(cairo_get_target(cr
));
3755 #endif // wxGTK_HAS_COMPOSITING_SUPPORT
3758 case wxBG_STYLE_ERASE
:
3760 wxWindowDC
dc( (wxWindow
*)this );
3761 dc
.SetDeviceClippingRegion( m_updateRegion
);
3763 // Work around gtk-qt <= 0.60 bug whereby the window colour
3767 GetOptionInt("gtk.window.force-background-colour") )
3769 dc
.SetBackground(GetBackgroundColour());
3773 wxEraseEvent
erase_event( GetId(), &dc
);
3774 erase_event
.SetEventObject( this );
3776 if ( HandleWindowEvent(erase_event
) )
3778 // background erased, don't do it again
3784 case wxBG_STYLE_SYSTEM
:
3785 if ( GetThemeEnabled() )
3787 // find ancestor from which to steal background
3788 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3790 parent
= (wxWindow
*)this;
3792 if (gtk_widget_get_mapped(parent
->m_widget
))
3794 wxRegionIterator
upd( m_nativeUpdateRegion
);
3798 rect
.x
= upd
.GetX();
3799 rect
.y
= upd
.GetY();
3800 rect
.width
= upd
.GetWidth();
3801 rect
.height
= upd
.GetHeight();
3803 gtk_paint_flat_box(gtk_widget_get_style(parent
->m_widget
),
3804 GTKGetDrawingWindow(),
3805 gtk_widget_get_state(m_wxwindow
),
3818 case wxBG_STYLE_PAINT
:
3819 // nothing to do: window will be painted over in EVT_PAINT
3823 wxFAIL_MSG( "unsupported background style" );
3826 wxNcPaintEvent
nc_paint_event( GetId() );
3827 nc_paint_event
.SetEventObject( this );
3828 HandleWindowEvent( nc_paint_event
);
3830 wxPaintEvent
paint_event( GetId() );
3831 paint_event
.SetEventObject( this );
3832 HandleWindowEvent( paint_event
);
3834 #if wxGTK_HAS_COMPOSITING_SUPPORT
3835 if (IsTransparentBackgroundSupported())
3836 { // now composite children which need it
3837 // Overlay all our composite children on top of the painted area
3838 wxWindowList::compatibility_iterator node
;
3839 for ( node
= m_children
.GetFirst(); node
; node
= node
->GetNext() )
3841 wxWindow
*compositeChild
= node
->GetData();
3842 if (compositeChild
->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT
)
3846 cr
= gdk_cairo_create(m_wxwindow
->window
);
3847 gdk_cairo_region(cr
, m_nativeUpdateRegion
.GetRegion());
3851 GtkWidget
*child
= compositeChild
->m_wxwindow
;
3852 GtkAllocation alloc
;
3853 gtk_widget_get_allocation(child
, &alloc
);
3855 // The source data is the (composited) child
3856 gdk_cairo_set_source_window(
3857 cr
, gtk_widget_get_window(child
), alloc
.x
, alloc
.y
);
3865 #endif // wxGTK_HAS_COMPOSITING_SUPPORT
3867 m_clipPaintRegion
= false;
3869 m_updateRegion
.Clear();
3870 m_nativeUpdateRegion
.Clear();
3873 void wxWindowGTK::SetDoubleBuffered( bool on
)
3875 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3878 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3881 bool wxWindowGTK::IsDoubleBuffered() const
3883 return gtk_widget_get_double_buffered( m_wxwindow
);
3886 void wxWindowGTK::ClearBackground()
3888 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3892 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3894 if (m_tooltip
!= tip
)
3896 wxWindowBase::DoSetToolTip(tip
);
3899 m_tooltip
->GTKSetWindow(static_cast<wxWindow
*>(this));
3901 GTKApplyToolTip(NULL
);
3905 void wxWindowGTK::GTKApplyToolTip(const char* tip
)
3907 wxToolTip::GTKApply(GetConnectWidget(), tip
);
3909 #endif // wxUSE_TOOLTIPS
3911 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3913 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3915 if (!wxWindowBase::SetBackgroundColour(colour
))
3920 // We need the pixel value e.g. for background clearing.
3921 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3924 // apply style change (forceStyle=true so that new style is applied
3925 // even if the bg colour changed from valid to wxNullColour)
3926 GTKApplyWidgetStyle(true);
3931 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3933 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3935 if (!wxWindowBase::SetForegroundColour(colour
))
3942 // We need the pixel value e.g. for background clearing.
3943 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3946 // apply style change (forceStyle=true so that new style is applied
3947 // even if the bg colour changed from valid to wxNullColour):
3948 GTKApplyWidgetStyle(true);
3953 PangoContext
*wxWindowGTK::GTKGetPangoDefaultContext()
3955 return gtk_widget_get_pango_context( m_widget
);
3958 GtkRcStyle
*wxWindowGTK::GTKCreateWidgetStyle(bool forceStyle
)
3960 // do we need to apply any changes at all?
3963 !m_foregroundColour
.IsOk() && !m_backgroundColour
.IsOk() )
3968 GtkRcStyle
*style
= gtk_rc_style_new();
3970 if ( m_font
.IsOk() )
3973 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3976 int flagsNormal
= 0,
3979 flagsInsensitive
= 0;
3981 if ( m_foregroundColour
.IsOk() )
3983 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3985 style
->fg
[GTK_STATE_NORMAL
] =
3986 style
->text
[GTK_STATE_NORMAL
] = *fg
;
3987 flagsNormal
|= GTK_RC_FG
| GTK_RC_TEXT
;
3989 style
->fg
[GTK_STATE_PRELIGHT
] =
3990 style
->text
[GTK_STATE_PRELIGHT
] = *fg
;
3991 flagsPrelight
|= GTK_RC_FG
| GTK_RC_TEXT
;
3993 style
->fg
[GTK_STATE_ACTIVE
] =
3994 style
->text
[GTK_STATE_ACTIVE
] = *fg
;
3995 flagsActive
|= GTK_RC_FG
| GTK_RC_TEXT
;
3998 if ( m_backgroundColour
.IsOk() )
4000 const GdkColor
*bg
= m_backgroundColour
.GetColor();
4002 style
->bg
[GTK_STATE_NORMAL
] =
4003 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4004 flagsNormal
|= GTK_RC_BG
| GTK_RC_BASE
;
4006 style
->bg
[GTK_STATE_PRELIGHT
] =
4007 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4008 flagsPrelight
|= GTK_RC_BG
| GTK_RC_BASE
;
4010 style
->bg
[GTK_STATE_ACTIVE
] =
4011 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4012 flagsActive
|= GTK_RC_BG
| GTK_RC_BASE
;
4014 style
->bg
[GTK_STATE_INSENSITIVE
] =
4015 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4016 flagsInsensitive
|= GTK_RC_BG
| GTK_RC_BASE
;
4019 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
;
4020 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
;
4021 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
;
4022 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
;
4027 void wxWindowGTK::GTKApplyWidgetStyle(bool forceStyle
)
4029 GtkRcStyle
*style
= GTKCreateWidgetStyle(forceStyle
);
4032 DoApplyWidgetStyle(style
);
4033 g_object_unref(style
);
4036 // Style change may affect GTK+'s size calculation:
4037 InvalidateBestSize();
4040 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4044 // block the signal temporarily to avoid sending
4045 // wxSysColourChangedEvents when we change the colours ourselves
4046 bool unblock
= false;
4050 g_signal_handlers_block_by_func(
4051 m_wxwindow
, (void *)gtk_window_style_set_callback
, this);
4054 gtk_widget_modify_style(m_wxwindow
, style
);
4058 g_signal_handlers_unblock_by_func(
4059 m_wxwindow
, (void *)gtk_window_style_set_callback
, this);
4064 gtk_widget_modify_style(m_widget
, style
);
4068 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4070 if (!wxWindowBase::SetBackgroundStyle(style
))
4076 window
= GTKGetDrawingWindow();
4080 GtkWidget
* const w
= GetConnectWidget();
4081 window
= w
? gtk_widget_get_window(w
) : NULL
;
4084 bool wantNoBackPixmap
= style
== wxBG_STYLE_PAINT
|| style
== wxBG_STYLE_TRANSPARENT
;
4086 if ( wantNoBackPixmap
)
4090 // Make sure GDK/X11 doesn't refresh the window
4092 gdk_window_set_back_pixmap( window
, None
, False
);
4093 m_needsStyleChange
= false;
4095 else // window not realized yet
4097 // Do when window is realized
4098 m_needsStyleChange
= true;
4101 // Don't apply widget style, or we get a grey background
4105 // apply style change (forceStyle=true so that new style is applied
4106 // even if the bg colour changed from valid to wxNullColour):
4107 GTKApplyWidgetStyle(true);
4113 bool wxWindowGTK::IsTransparentBackgroundSupported(wxString
* reason
) const
4115 #if wxGTK_HAS_COMPOSITING_SUPPORT
4116 if (gtk_check_version(wxGTK_VERSION_REQUIRED_FOR_COMPOSITING
) != NULL
)
4120 *reason
= _("GTK+ installed on this machine is too old to "
4121 "support screen compositing, please install "
4122 "GTK+ 2.12 or later.");
4128 // NB: We don't check here if the particular kind of widget supports
4129 // transparency, we check only if it would be possible for a generic window
4131 wxCHECK_MSG ( m_widget
, false, "Window must be created first" );
4133 if (!gdk_screen_is_composited(gtk_widget_get_screen(m_widget
)))
4137 *reason
= _("Compositing not supported by this system, "
4138 "please enable it in your Window Manager.");
4148 *reason
= _("This program was compiled with a too old version of GTK+, "
4149 "please rebuild with GTK+ 2.12 or newer.");
4151 #endif // wxGTK_HAS_COMPOSITING_SUPPORT/!wxGTK_HAS_COMPOSITING_SUPPORT
4156 // ----------------------------------------------------------------------------
4157 // Pop-up menu stuff
4158 // ----------------------------------------------------------------------------
4160 #if wxUSE_MENUS_NATIVE
4164 void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4166 gboolean
* WXUNUSED(whatever
),
4167 gpointer user_data
)
4169 // ensure that the menu appears entirely on screen
4171 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4173 wxSize sizeScreen
= wxGetDisplaySize();
4174 wxPoint
*pos
= (wxPoint
*)user_data
;
4176 gint xmax
= sizeScreen
.x
- req
.width
,
4177 ymax
= sizeScreen
.y
- req
.height
;
4179 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4180 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4184 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4186 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4188 // For compatibility with other ports, pretend that the window showing the
4189 // menu has focus while the menu is shown. This is needed because the popup
4190 // menu actually steals the focus from the window it's associated it in
4191 // wxGTK unlike, say, wxMSW.
4192 wxWindowGTK
* const oldPendingFocus
= gs_pendingFocus
;
4193 gs_pendingFocus
= this;
4194 wxON_BLOCK_EXIT_SET( gs_pendingFocus
, oldPendingFocus
);
4200 GtkMenuPositionFunc posfunc
;
4201 if ( x
== -1 && y
== -1 )
4203 // use GTK's default positioning algorithm
4209 pos
= ClientToScreen(wxPoint(x
, y
));
4211 posfunc
= wxPopupMenuPositionCallback
;
4214 menu
->m_popupShown
= true;
4216 GTK_MENU(menu
->m_menu
),
4217 NULL
, // parent menu shell
4218 NULL
, // parent menu item
4219 posfunc
, // function to position it
4220 userdata
, // client data
4221 0, // button used to activate it
4222 gtk_get_current_event_time()
4225 while (menu
->m_popupShown
)
4227 gtk_main_iteration();
4233 #endif // wxUSE_MENUS_NATIVE
4235 #if wxUSE_DRAG_AND_DROP
4237 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4239 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4241 GtkWidget
*dnd_widget
= GetConnectWidget();
4243 if (m_dropTarget
) m_dropTarget
->GtkUnregisterWidget( dnd_widget
);
4245 if (m_dropTarget
) delete m_dropTarget
;
4246 m_dropTarget
= dropTarget
;
4248 if (m_dropTarget
) m_dropTarget
->GtkRegisterWidget( dnd_widget
);
4251 #endif // wxUSE_DRAG_AND_DROP
4253 GtkWidget
* wxWindowGTK::GetConnectWidget()
4255 GtkWidget
*connect_widget
= m_widget
;
4256 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4258 return connect_widget
;
4261 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow
*window
) const
4263 wxArrayGdkWindows windowsThis
;
4264 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
4266 return winThis
? window
== winThis
4267 : windowsThis
.Index(window
) != wxNOT_FOUND
;
4270 GdkWindow
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
4272 return m_wxwindow
? GTKGetDrawingWindow() : gtk_widget_get_window(m_widget
);
4275 bool wxWindowGTK::SetFont( const wxFont
&font
)
4277 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4279 if (!wxWindowBase::SetFont(font
))
4282 // apply style change (forceStyle=true so that new style is applied
4283 // even if the font changed from valid to wxNullFont):
4284 GTKApplyWidgetStyle(true);
4289 void wxWindowGTK::DoCaptureMouse()
4291 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4293 GdkWindow
*window
= NULL
;
4295 window
= GTKGetDrawingWindow();
4297 window
= gtk_widget_get_window(GetConnectWidget());
4299 wxCHECK_RET( window
, wxT("CaptureMouse() failed") );
4301 const wxCursor
* cursor
= &m_cursor
;
4302 if (!cursor
->IsOk())
4303 cursor
= wxSTANDARD_CURSOR
;
4305 gdk_pointer_grab( window
, FALSE
,
4307 (GDK_BUTTON_PRESS_MASK
|
4308 GDK_BUTTON_RELEASE_MASK
|
4309 GDK_POINTER_MOTION_HINT_MASK
|
4310 GDK_POINTER_MOTION_MASK
),
4312 cursor
->GetCursor(),
4313 (guint32
)GDK_CURRENT_TIME
);
4314 g_captureWindow
= this;
4315 g_captureWindowHasMouse
= true;
4318 void wxWindowGTK::DoReleaseMouse()
4320 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4322 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4324 g_captureWindow
= NULL
;
4326 GdkWindow
*window
= NULL
;
4328 window
= GTKGetDrawingWindow();
4330 window
= gtk_widget_get_window(GetConnectWidget());
4335 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4338 void wxWindowGTK::GTKReleaseMouseAndNotify()
4341 wxMouseCaptureLostEvent
evt(GetId());
4342 evt
.SetEventObject( this );
4343 HandleWindowEvent( evt
);
4347 wxWindow
*wxWindowBase::GetCapture()
4349 return (wxWindow
*)g_captureWindow
;
4352 bool wxWindowGTK::IsRetained() const
4357 void wxWindowGTK::SetScrollbar(int orient
,
4361 bool WXUNUSED(update
))
4363 const int dir
= ScrollDirFromOrient(orient
);
4364 GtkRange
* const sb
= m_scrollBar
[dir
];
4365 wxCHECK_RET( sb
, wxT("this window is not scrollable") );
4369 // GtkRange requires upper > lower
4374 g_signal_handlers_block_by_func(
4375 sb
, (void*)gtk_scrollbar_value_changed
, this);
4377 gtk_range_set_increments(sb
, 1, thumbVisible
);
4378 gtk_adjustment_set_page_size(gtk_range_get_adjustment(sb
), thumbVisible
);
4379 gtk_range_set_range(sb
, 0, range
);
4380 gtk_range_set_value(sb
, pos
);
4381 m_scrollPos
[dir
] = gtk_range_get_value(sb
);
4383 g_signal_handlers_unblock_by_func(
4384 sb
, (void*)gtk_scrollbar_value_changed
, this);
4387 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4389 const int dir
= ScrollDirFromOrient(orient
);
4390 GtkRange
* const sb
= m_scrollBar
[dir
];
4391 wxCHECK_RET( sb
, wxT("this window is not scrollable") );
4393 // This check is more than an optimization. Without it, the slider
4394 // will not move smoothly while tracking when using wxScrollHelper.
4395 if (GetScrollPos(orient
) != pos
)
4397 g_signal_handlers_block_by_func(
4398 sb
, (void*)gtk_scrollbar_value_changed
, this);
4400 gtk_range_set_value(sb
, pos
);
4401 m_scrollPos
[dir
] = gtk_range_get_value(sb
);
4403 g_signal_handlers_unblock_by_func(
4404 sb
, (void*)gtk_scrollbar_value_changed
, this);
4408 int wxWindowGTK::GetScrollThumb(int orient
) const
4410 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4411 wxCHECK_MSG( sb
, 0, wxT("this window is not scrollable") );
4413 return wxRound(gtk_adjustment_get_page_size(gtk_range_get_adjustment(sb
)));
4416 int wxWindowGTK::GetScrollPos( int orient
) const
4418 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4419 wxCHECK_MSG( sb
, 0, wxT("this window is not scrollable") );
4421 return wxRound(gtk_range_get_value(sb
));
4424 int wxWindowGTK::GetScrollRange( int orient
) const
4426 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4427 wxCHECK_MSG( sb
, 0, wxT("this window is not scrollable") );
4429 return wxRound(gtk_adjustment_get_upper(gtk_range_get_adjustment(sb
)));
4432 // Determine if increment is the same as +/-x, allowing for some small
4433 // difference due to possible inexactness in floating point arithmetic
4434 static inline bool IsScrollIncrement(double increment
, double x
)
4436 wxASSERT(increment
> 0);
4437 const double tolerance
= 1.0 / 1024;
4438 return fabs(increment
- fabs(x
)) < tolerance
;
4441 wxEventType
wxWindowGTK::GTKGetScrollEventType(GtkRange
* range
)
4443 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4445 const int barIndex
= range
== m_scrollBar
[1];
4447 const double value
= gtk_range_get_value(range
);
4449 // save previous position
4450 const double oldPos
= m_scrollPos
[barIndex
];
4451 // update current position
4452 m_scrollPos
[barIndex
] = value
;
4453 // If event should be ignored, or integral position has not changed
4454 if (!m_hasVMT
|| g_blockEventsOnDrag
|| wxRound(value
) == wxRound(oldPos
))
4459 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4462 // Difference from last change event
4463 const double diff
= value
- oldPos
;
4464 const bool isDown
= diff
> 0;
4466 GtkAdjustment
* adj
= gtk_range_get_adjustment(range
);
4467 if (IsScrollIncrement(gtk_adjustment_get_step_increment(adj
), diff
))
4469 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4471 else if (IsScrollIncrement(gtk_adjustment_get_page_increment(adj
), diff
))
4473 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4475 else if (m_mouseButtonDown
)
4477 // Assume track event
4478 m_isScrolling
= true;
4484 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4486 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4488 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4490 // No scrolling requested.
4491 if ((dx
== 0) && (dy
== 0)) return;
4493 m_clipPaintRegion
= true;
4495 WX_PIZZA(m_wxwindow
)->scroll(dx
, dy
);
4497 m_clipPaintRegion
= false;
4500 bool restoreCaret
= (GetCaret() != NULL
&& GetCaret()->IsVisible());
4503 wxRect
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4505 caretRect
.width
+= dx
;
4508 caretRect
.x
+= dx
; caretRect
.width
-= dx
;
4511 caretRect
.height
+= dy
;
4514 caretRect
.y
+= dy
; caretRect
.height
-= dy
;
4517 RefreshRect(caretRect
);
4519 #endif // wxUSE_CARET
4522 void wxWindowGTK::GTKScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4524 //RN: Note that static controls usually have no border on gtk, so maybe
4525 //it makes sense to treat that as simply no border at the wx level
4527 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4529 GtkShadowType gtkstyle
;
4531 if(wxstyle
& wxBORDER_RAISED
)
4532 gtkstyle
= GTK_SHADOW_OUT
;
4533 else if ((wxstyle
& wxBORDER_SUNKEN
) || (wxstyle
& wxBORDER_THEME
))
4534 gtkstyle
= GTK_SHADOW_IN
;
4537 else if (wxstyle
& wxBORDER_DOUBLE
)
4538 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4541 gtkstyle
= GTK_SHADOW_IN
;
4543 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4548 // Find the wxWindow at the current mouse position, also returning the mouse
4550 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4552 pt
= wxGetMousePosition();
4553 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4557 // Get the current mouse position.
4558 wxPoint
wxGetMousePosition()
4560 wxWindow
* tlw
= NULL
;
4561 if (!wxTopLevelWindows
.empty())
4562 tlw
= wxTopLevelWindows
.front();
4563 GdkDisplay
* display
;
4564 if (tlw
&& tlw
->m_widget
)
4565 display
= gtk_widget_get_display(tlw
->m_widget
);
4567 display
= gdk_display_get_default();
4570 gdk_display_get_pointer(display
, NULL
, &x
, &y
, NULL
);
4571 return wxPoint(x
, y
);
4574 GdkWindow
* wxWindowGTK::GTKGetDrawingWindow() const
4576 GdkWindow
* window
= NULL
;
4578 window
= gtk_widget_get_window(m_wxwindow
);
4582 // ----------------------------------------------------------------------------
4584 // ----------------------------------------------------------------------------
4589 // this is called if we attempted to freeze unrealized widget when it finally
4590 // is realized (and so can be frozen):
4591 static void wx_frozen_widget_realize(GtkWidget
* w
, wxWindowGTK
* win
)
4593 wxASSERT( w
&& gtk_widget_get_has_window(w
) );
4594 wxASSERT( gtk_widget_get_realized(w
) );
4596 g_signal_handlers_disconnect_by_func
4599 (void*)wx_frozen_widget_realize
,
4604 if (w
== win
->m_wxwindow
)
4605 window
= win
->GTKGetDrawingWindow();
4607 window
= gtk_widget_get_window(w
);
4608 gdk_window_freeze_updates(window
);
4613 void wxWindowGTK::GTKFreezeWidget(GtkWidget
*w
)
4615 if ( !w
|| !gtk_widget_get_has_window(w
) )
4616 return; // window-less widget, cannot be frozen
4618 GdkWindow
* window
= gtk_widget_get_window(w
);
4621 // we can't thaw unrealized widgets because they don't have GdkWindow,
4622 // so set it up to be done immediately after realization:
4623 g_signal_connect_after
4627 G_CALLBACK(wx_frozen_widget_realize
),
4633 if (w
== m_wxwindow
)
4634 window
= GTKGetDrawingWindow();
4635 gdk_window_freeze_updates(window
);
4638 void wxWindowGTK::GTKThawWidget(GtkWidget
*w
)
4640 if ( !w
|| !gtk_widget_get_has_window(w
) )
4641 return; // window-less widget, cannot be frozen
4643 GdkWindow
* window
= gtk_widget_get_window(w
);
4646 // the widget wasn't realized yet, no need to thaw
4647 g_signal_handlers_disconnect_by_func
4650 (void*)wx_frozen_widget_realize
,
4656 if (w
== m_wxwindow
)
4657 window
= GTKGetDrawingWindow();
4658 gdk_window_thaw_updates(window
);
4661 void wxWindowGTK::DoFreeze()
4663 GTKFreezeWidget(m_widget
);
4664 if ( m_wxwindow
&& m_widget
!= m_wxwindow
)
4665 GTKFreezeWidget(m_wxwindow
);
4668 void wxWindowGTK::DoThaw()
4670 GTKThawWidget(m_widget
);
4671 if ( m_wxwindow
&& m_widget
!= m_wxwindow
)
4672 GTKThawWidget(m_wxwindow
);