1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/window.cpp
3 // Purpose: wxWindowGTK implementation
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
22 #include "wx/toplevel.h"
23 #include "wx/dcclient.h"
25 #include "wx/settings.h"
26 #include "wx/msgdlg.h"
31 #include "wx/tooltip.h"
33 #include "wx/fontutil.h"
34 #include "wx/sysopt.h"
38 #include "wx/gtk/private.h"
39 #include "wx/gtk/private/win_gtk.h"
40 #include <gdk/gdkkeysyms.h>
43 #if !GTK_CHECK_VERSION(2,10,0)
44 // GTK+ can reliably detect Meta key state only since 2.10 when
45 // GDK_META_MASK was introduced -- there wasn't any way to detect it
46 // in older versions. wxGTK used GDK_MOD2_MASK for this purpose, but
47 // GDK_MOD2_MASK is documented as:
49 // the fifth modifier key (it depends on the modifier mapping of the X
50 // server which key is interpreted as this modifier)
52 // In other words, it isn't guaranteed to map to Meta. This is a real
53 // problem: it is common to map NumLock to it (in fact, it's an exception
54 // if the X server _doesn't_ use it for NumLock). So the old code caused
55 // wxKeyEvent::MetaDown() to always return true as long as NumLock was on
56 // on many systems, which broke all applications using
57 // wxKeyEvent::GetModifiers() to check modifiers state (see e.g. here:
58 // http://tinyurl.com/56lsk2).
60 // Because of this, it's better to not detect Meta key state at all than
61 // to detect it incorrectly. Hence the following #define, which causes
62 // m_metaDown to be always set to false.
63 #define GDK_META_MASK 0
66 //-----------------------------------------------------------------------------
67 // documentation on internals
68 //-----------------------------------------------------------------------------
71 I have been asked several times about writing some documentation about
72 the GTK port of wxWidgets, especially its internal structures. Obviously,
73 you cannot understand wxGTK without knowing a little about the GTK, but
74 some more information about what the wxWindow, which is the base class
75 for all other window classes, does seems required as well.
79 What does wxWindow do? It contains the common interface for the following
80 jobs of its descendants:
82 1) Define the rudimentary behaviour common to all window classes, such as
83 resizing, intercepting user input (so as to make it possible to use these
84 events for special purposes in a derived class), window names etc.
86 2) Provide the possibility to contain and manage children, if the derived
87 class is allowed to contain children, which holds true for those window
88 classes which do not display a native GTK widget. To name them, these
89 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
90 work classes are a special case and are handled a bit differently from
91 the rest. The same holds true for the wxNotebook class.
93 3) Provide the possibility to draw into a client area of a window. This,
94 too, only holds true for classes that do not display a native GTK widget
97 4) Provide the entire mechanism for scrolling widgets. This actual inter-
98 face for this is usually in wxScrolledWindow, but the GTK implementation
101 5) A multitude of helper or extra methods for special purposes, such as
102 Drag'n'Drop, managing validators etc.
104 6) Display a border (sunken, raised, simple or none).
106 Normally one might expect, that one wxWidgets window would always correspond
107 to one GTK widget. Under GTK, there is no such all-round widget that has all
108 the functionality. Moreover, the GTK defines a client area as a different
109 widget from the actual widget you are handling. Last but not least some
110 special classes (e.g. wxFrame) handle different categories of widgets and
111 still have the possibility to draw something in the client area.
112 It was therefore required to write a special purpose GTK widget, that would
113 represent a client area in the sense of wxWidgets capable to do the jobs
114 2), 3) and 4). I have written this class and it resides in win_gtk.c of
117 All windows must have a widget, with which they interact with other under-
118 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
119 the wxWindow class has a member variable called m_widget which holds a
120 pointer to this widget. When the window class represents a GTK native widget,
121 this is (in most cases) the only GTK widget the class manages. E.g. the
122 wxStaticText class handles only a GtkLabel widget a pointer to which you
123 can find in m_widget (defined in wxWindow)
125 When the class has a client area for drawing into and for containing children
126 it has to handle the client area widget (of the type wxPizza, defined in
127 win_gtk.cpp), but there could be any number of widgets, handled by a class.
128 The common rule for all windows is only, that the widget that interacts with
129 the rest of GTK must be referenced in m_widget and all other widgets must be
130 children of this widget on the GTK level. The top-most widget, which also
131 represents the client area, must be in the m_wxwindow field and must be of
134 As I said, the window classes that display a GTK native widget only have
135 one widget, so in the case of e.g. the wxButton class m_widget holds a
136 pointer to a GtkButton widget. But windows with client areas (for drawing
137 and children) have a m_widget field that is a pointer to a GtkScrolled-
138 Window and a m_wxwindow field that is pointer to a wxPizza and this
139 one is (in the GTK sense) a child of the GtkScrolledWindow.
141 If the m_wxwindow field is set, then all input to this widget is inter-
142 cepted and sent to the wxWidgets class. If not, all input to the widget
143 that gets pointed to by m_widget gets intercepted and sent to the class.
147 The design of scrolling in wxWidgets is markedly different from that offered
148 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
149 clicking on a scrollbar belonging to scrolled window will inevitably move
150 the window. In wxWidgets, the scrollbar will only emit an event, send this
151 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
152 which actually moves the window and its sub-windows. Note that wxPizza
153 memorizes how much it has been scrolled but that wxWidgets forgets this
154 so that the two coordinates systems have to be kept in synch. This is done
155 in various places using the pizza->m_scroll_x and pizza->m_scroll_y values.
159 Singularly the most broken code in GTK is the code that is supposed to
160 inform subwindows (child windows) about new positions. Very often, duplicate
161 events are sent without changes in size or position, equally often no
162 events are sent at all (All this is due to a bug in the GtkContainer code
163 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
164 GTK's own system and it simply waits for size events for toplevel windows
165 and then iterates down the respective size events to all window. This has
166 the disadvantage that windows might get size events before the GTK widget
167 actually has the reported size. This doesn't normally pose any problem, but
168 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
169 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
170 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
171 window that is used for OpenGL output really has that size (as reported by
176 If someone at some point of time feels the immense desire to have a look at,
177 change or attempt to optimise the Refresh() logic, this person will need an
178 intimate understanding of what "draw" and "expose" events are and what
179 they are used for, in particular when used in connection with GTK's
180 own windowless widgets. Beware.
184 Cursors, too, have been a constant source of pleasure. The main difficulty
185 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
186 for the parent. To prevent this from doing too much harm, SetCursor calls
187 GTKUpdateCursor, which will recursively re-set the cursors of all child windows.
188 Also don't forget that cursors (like much else) are connected to GdkWindows,
189 not GtkWidgets and that the "window" field of a GtkWidget might very well
190 point to the GdkWindow of the parent widget (-> "window-less widget") and
191 that the two obviously have very different meanings.
194 //-----------------------------------------------------------------------------
196 //-----------------------------------------------------------------------------
198 // Don't allow event propagation during drag
199 bool g_blockEventsOnDrag
;
200 // Don't allow mouse event propagation during scroll
201 bool g_blockEventsOnScroll
;
202 extern wxCursor g_globalCursor
;
204 // mouse capture state: the window which has it and if the mouse is currently
206 static wxWindowGTK
*g_captureWindow
= NULL
;
207 static bool g_captureWindowHasMouse
= false;
209 // The window that currently has focus:
210 static wxWindowGTK
*gs_currentFocus
= NULL
;
211 // The window that is scheduled to get focus in the next event loop iteration
212 // or NULL if there's no pending focus change:
213 static wxWindowGTK
*gs_pendingFocus
= NULL
;
215 // the window that has deferred focus-out event pending, if any (see
216 // GTKAddDeferredFocusOut() for details)
217 static wxWindowGTK
*gs_deferredFocusOut
= NULL
;
219 // global variables because GTK+ DnD want to have the
220 // mouse event that caused it
221 GdkEvent
*g_lastMouseEvent
= NULL
;
222 int g_lastButtonNumber
= 0;
224 //-----------------------------------------------------------------------------
226 //-----------------------------------------------------------------------------
228 // the trace mask used for the focus debugging messages
229 #define TRACE_FOCUS wxT("focus")
231 //-----------------------------------------------------------------------------
232 // missing gdk functions
233 //-----------------------------------------------------------------------------
236 gdk_window_warp_pointer (GdkWindow
*window
,
241 window
= gdk_get_default_root_window();
243 if (!GDK_WINDOW_DESTROYED(window
))
245 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
246 None
, /* not source window -> move from anywhere */
247 GDK_WINDOW_XID(window
), /* dest window */
248 0, 0, 0, 0, /* not source window -> move from anywhere */
254 //-----------------------------------------------------------------------------
255 // "size_request" of m_widget
256 //-----------------------------------------------------------------------------
260 wxgtk_window_size_request_callback(GtkWidget
* WXUNUSED(widget
),
261 GtkRequisition
*requisition
,
265 win
->GetSize( &w
, &h
);
271 requisition
->height
= h
;
272 requisition
->width
= w
;
276 //-----------------------------------------------------------------------------
277 // "expose_event" of m_wxwindow
278 //-----------------------------------------------------------------------------
282 gtk_window_expose_callback( GtkWidget
*,
283 GdkEventExpose
*gdk_event
,
286 if (gdk_event
->window
== win
->GTKGetDrawingWindow())
288 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
289 win
->GtkSendPaintEvents();
291 // Let parent window draw window-less widgets
296 #ifndef __WXUNIVERSAL__
297 //-----------------------------------------------------------------------------
298 // "expose_event" from m_wxwindow->parent, for drawing border
299 //-----------------------------------------------------------------------------
303 expose_event_border(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxWindow
* win
)
305 if (gdk_event
->window
!= gtk_widget_get_parent_window(win
->m_wxwindow
))
311 const GtkAllocation
& alloc
= win
->m_wxwindow
->allocation
;
312 const int x
= alloc
.x
;
313 const int y
= alloc
.y
;
314 const int w
= alloc
.width
;
315 const int h
= alloc
.height
;
317 if (w
<= 0 || h
<= 0)
320 if (win
->HasFlag(wxBORDER_SIMPLE
))
322 gdk_draw_rectangle(gdk_event
->window
,
323 widget
->style
->black_gc
, false, x
, y
, w
- 1, h
- 1);
327 GtkShadowType shadow
= GTK_SHADOW_IN
;
328 if (win
->HasFlag(wxBORDER_RAISED
))
329 shadow
= GTK_SHADOW_OUT
;
331 // Style detail to use
333 if (win
->m_widget
== win
->m_wxwindow
)
334 // for non-scrollable wxWindows
337 // for scrollable ones
341 win
->m_wxwindow
->style
, gdk_event
->window
, GTK_STATE_NORMAL
,
342 shadow
, NULL
, wxGTKPrivate
::GetEntryWidget(), detail
, x
, y
, w
, h
);
348 //-----------------------------------------------------------------------------
349 // "parent_set" from m_wxwindow
350 //-----------------------------------------------------------------------------
354 parent_set(GtkWidget
* widget
, GtkObject
* old_parent
, wxWindow
* win
)
358 g_signal_handlers_disconnect_by_func(
359 old_parent
, (void*)expose_event_border
, win
);
363 g_signal_connect_after(widget
->parent
, "expose_event",
364 G_CALLBACK(expose_event_border
), win
);
368 #endif // !__WXUNIVERSAL__
370 //-----------------------------------------------------------------------------
371 // "key_press_event" from any window
372 //-----------------------------------------------------------------------------
374 // These are used when transforming Ctrl-alpha to ascii values 1-26
375 inline bool wxIsLowerChar(int code
)
377 return (code
>= 'a' && code
<= 'z' );
380 inline bool wxIsUpperChar(int code
)
382 return (code
>= 'A' && code
<= 'Z' );
386 // set WXTRACE to this to see the key event codes on the console
387 #define TRACE_KEYS wxT("keyevent")
389 // translates an X key symbol to WXK_XXX value
391 // if isChar is true it means that the value returned will be used for EVT_CHAR
392 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
393 // for example, while if it is false it means that the value is going to be
394 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
396 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
402 // Shift, Control and Alt don't generate the CHAR events at all
405 key_code
= isChar ?
0 : WXK_SHIFT
;
409 key_code
= isChar ?
0 : WXK_CONTROL
;
417 key_code
= isChar ?
0 : WXK_ALT
;
420 // neither do the toggle modifies
421 case GDK_Scroll_Lock
:
422 key_code
= isChar ?
0 : WXK_SCROLL
;
426 key_code
= isChar ?
0 : WXK_CAPITAL
;
430 key_code
= isChar ?
0 : WXK_NUMLOCK
;
434 // various other special keys
447 case GDK_ISO_Left_Tab
:
454 key_code
= WXK_RETURN
;
458 key_code
= WXK_CLEAR
;
462 key_code
= WXK_PAUSE
;
466 key_code
= WXK_SELECT
;
470 key_code
= WXK_PRINT
;
474 key_code
= WXK_EXECUTE
;
478 key_code
= WXK_ESCAPE
;
481 // cursor and other extended keyboard keys
483 key_code
= WXK_DELETE
;
499 key_code
= WXK_RIGHT
;
506 case GDK_Prior
: // == GDK_Page_Up
507 key_code
= WXK_PAGEUP
;
510 case GDK_Next
: // == GDK_Page_Down
511 key_code
= WXK_PAGEDOWN
;
523 key_code
= WXK_INSERT
;
538 key_code
= (isChar ?
'0' : int(WXK_NUMPAD0
)) + keysym
- GDK_KP_0
;
542 key_code
= isChar ?
' ' : int(WXK_NUMPAD_SPACE
);
546 key_code
= isChar ? WXK_TAB
: WXK_NUMPAD_TAB
;
550 key_code
= isChar ? WXK_RETURN
: WXK_NUMPAD_ENTER
;
554 key_code
= isChar ? WXK_F1
: WXK_NUMPAD_F1
;
558 key_code
= isChar ? WXK_F2
: WXK_NUMPAD_F2
;
562 key_code
= isChar ? WXK_F3
: WXK_NUMPAD_F3
;
566 key_code
= isChar ? WXK_F4
: WXK_NUMPAD_F4
;
570 key_code
= isChar ? WXK_HOME
: WXK_NUMPAD_HOME
;
574 key_code
= isChar ? WXK_LEFT
: WXK_NUMPAD_LEFT
;
578 key_code
= isChar ? WXK_UP
: WXK_NUMPAD_UP
;
582 key_code
= isChar ? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
586 key_code
= isChar ? WXK_DOWN
: WXK_NUMPAD_DOWN
;
589 case GDK_KP_Prior
: // == GDK_KP_Page_Up
590 key_code
= isChar ? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
593 case GDK_KP_Next
: // == GDK_KP_Page_Down
594 key_code
= isChar ? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
598 key_code
= isChar ? WXK_END
: WXK_NUMPAD_END
;
602 key_code
= isChar ? WXK_HOME
: WXK_NUMPAD_BEGIN
;
606 key_code
= isChar ? WXK_INSERT
: WXK_NUMPAD_INSERT
;
610 key_code
= isChar ? WXK_DELETE
: WXK_NUMPAD_DELETE
;
614 key_code
= isChar ?
'=' : int(WXK_NUMPAD_EQUAL
);
617 case GDK_KP_Multiply
:
618 key_code
= isChar ?
'*' : int(WXK_NUMPAD_MULTIPLY
);
622 key_code
= isChar ?
'+' : int(WXK_NUMPAD_ADD
);
625 case GDK_KP_Separator
:
626 // FIXME: what is this?
627 key_code
= isChar ?
'.' : int(WXK_NUMPAD_SEPARATOR
);
630 case GDK_KP_Subtract
:
631 key_code
= isChar ?
'-' : int(WXK_NUMPAD_SUBTRACT
);
635 key_code
= isChar ?
'.' : int(WXK_NUMPAD_DECIMAL
);
639 key_code
= isChar ?
'/' : int(WXK_NUMPAD_DIVIDE
);
656 key_code
= WXK_F1
+ keysym
- GDK_F1
;
666 static inline bool wxIsAsciiKeysym(KeySym ks
)
671 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
673 GdkEventKey
*gdk_event
)
677 GdkModifierType state
;
678 if (gdk_event
->window
)
679 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
681 event
.SetTimestamp( gdk_event
->time
);
682 event
.SetId(win
->GetId());
683 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
684 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
685 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
686 event
.m_metaDown
= (gdk_event
->state
& GDK_META_MASK
) != 0;
687 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
688 event
.m_rawFlags
= 0;
690 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
691 if ( !event
.m_uniChar
&& event
.m_keyCode
<= WXK_DELETE
)
693 // Set Unicode key code to the ASCII equivalent for compatibility. E.g.
694 // let RETURN generate the key event with both key and Unicode key
696 event
.m_uniChar
= event
.m_keyCode
;
698 #endif // wxUSE_UNICODE
699 wxGetMousePosition( &x
, &y
);
700 win
->ScreenToClient( &x
, &y
);
703 event
.SetEventObject( win
);
708 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
710 GdkEventKey
*gdk_event
)
712 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
713 // but only event->keyval which is quite useless to us, so remember
714 // the last character from GDK_KEY_PRESS and reuse it as last resort
716 // NB: should be MT-safe as we're always called from the main thread only
721 } s_lastKeyPress
= { 0, 0 };
723 KeySym keysym
= gdk_event
->keyval
;
725 wxLogTrace(TRACE_KEYS
, wxT("Key %s event: keysym = %ld"),
726 event
.GetEventType() == wxEVT_KEY_UP ?
wxT("release")
730 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
734 // do we have the translation or is it a plain ASCII character?
735 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
737 // we should use keysym if it is ASCII as X does some translations
738 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
739 // which we don't want here (but which we do use for OnChar())
740 if ( !wxIsAsciiKeysym(keysym
) )
742 keysym
= (KeySym
)gdk_event
->string
[0];
745 // we want to always get the same key code when the same key is
746 // pressed regardless of the state of the modifiers, i.e. on a
747 // standard US keyboard pressing '5' or '%' ('5' key with
748 // Shift) should result in the same key code in OnKeyDown():
749 // '5' (although OnChar() will get either '5' or '%').
751 // to do it we first translate keysym to keycode (== scan code)
752 // and then back but always using the lower register
753 Display
*dpy
= (Display
*)wxGetDisplay();
754 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
756 wxLogTrace(TRACE_KEYS
, wxT("\t-> keycode %d"), keycode
);
758 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
760 // use the normalized, i.e. lower register, keysym if we've
762 key_code
= keysymNormalized ? keysymNormalized
: keysym
;
764 // as explained above, we want to have lower register key codes
765 // normally but for the letter keys we want to have the upper ones
767 // NB: don't use XConvertCase() here, we want to do it for letters
769 key_code
= toupper(key_code
);
771 else // non ASCII key, what to do?
773 // by default, ignore it
776 // but if we have cached information from the last KEY_PRESS
777 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
780 if ( keysym
== s_lastKeyPress
.keysym
)
782 key_code
= s_lastKeyPress
.keycode
;
787 if ( gdk_event
->type
== GDK_KEY_PRESS
)
789 // remember it to be reused for KEY_UP event later
790 s_lastKeyPress
.keysym
= keysym
;
791 s_lastKeyPress
.keycode
= key_code
;
795 wxLogTrace(TRACE_KEYS
, wxT("\t-> wxKeyCode %ld"), key_code
);
797 // sending unknown key events doesn't really make sense
801 event
.m_keyCode
= key_code
;
803 // now fill all the other fields
804 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
812 GtkIMContext
*context
;
813 GdkEventKey
*lastKeyEvent
;
817 context
= gtk_im_multicontext_new();
822 g_object_unref (context
);
829 // Send wxEVT_CHAR_HOOK event to the parent of the window and if it wasn't
830 // processed, send wxEVT_CHAR to the window itself. Return true if either of
833 SendCharHookAndCharEvents(const wxKeyEvent
& event
, wxWindow
*win
)
835 // wxEVT_CHAR_HOOK must be sent to the top level parent window to allow it
836 // to handle key events in all of its children.
837 wxWindow
* const parent
= wxGetTopLevelParent(win
);
840 // We need to make a copy of the event object because it is
841 // modified while it's handled, notably its WasProcessed() flag
842 // is set after it had been processed once.
843 wxKeyEvent
eventCharHook(event
);
844 eventCharHook
.SetEventType(wxEVT_CHAR_HOOK
);
845 if ( parent
->HandleWindowEvent(eventCharHook
) )
849 // As above, make a copy of the event first.
850 wxKeyEvent
eventChar(event
);
851 eventChar
.SetEventType(wxEVT_CHAR
);
852 return win
->HandleWindowEvent(eventChar
);
855 } // anonymous namespace
859 gtk_window_key_press_callback( GtkWidget
*WXUNUSED(widget
),
860 GdkEventKey
*gdk_event
,
865 if (g_blockEventsOnDrag
)
868 wxKeyEvent
event( wxEVT_KEY_DOWN
);
870 bool return_after_IM
= false;
872 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
874 // Emit KEY_DOWN event
875 ret
= win
->HandleWindowEvent( event
);
879 // Return after IM processing as we cannot do
880 // anything with it anyhow.
881 return_after_IM
= true;
884 if (!ret
&& win
->m_imData
)
886 win
->m_imData
->lastKeyEvent
= gdk_event
;
888 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
889 // docs, if IM filter returns true, no further processing should be done.
890 // we should send the key_down event anyway.
891 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
892 win
->m_imData
->lastKeyEvent
= NULL
;
893 if (intercepted_by_IM
)
895 wxLogTrace(TRACE_KEYS
, wxT("Key event intercepted by IM"));
906 wxWindowGTK
*ancestor
= win
;
909 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
912 wxCommandEvent
menu_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
913 ret
= ancestor
->HandleWindowEvent( menu_event
);
917 // if the accelerator wasn't handled as menu event, try
918 // it as button click (for compatibility with other
920 wxCommandEvent
button_event( wxEVT_COMMAND_BUTTON_CLICKED
, command
);
921 ret
= ancestor
->HandleWindowEvent( button_event
);
926 if (ancestor
->IsTopLevel())
928 ancestor
= ancestor
->GetParent();
931 #endif // wxUSE_ACCEL
933 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
934 // will only be sent if it is not in an accelerator table.
938 KeySym keysym
= gdk_event
->keyval
;
939 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
940 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
943 if ( wxIsAsciiKeysym(keysym
) )
946 key_code
= (unsigned char)keysym
;
948 // gdk_event->string is actually deprecated
949 else if ( gdk_event
->length
== 1 )
951 key_code
= (unsigned char)gdk_event
->string
[0];
957 wxLogTrace(TRACE_KEYS
, wxT("Char event: %ld"), key_code
);
959 event
.m_keyCode
= key_code
;
961 // To conform to the docs we need to translate Ctrl-alpha
962 // characters to values in the range 1-26.
963 if ( event
.ControlDown() &&
964 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
966 if ( wxIsLowerChar(key_code
) )
967 event
.m_keyCode
= key_code
- 'a' + 1;
968 if ( wxIsUpperChar(key_code
) )
969 event
.m_keyCode
= key_code
- 'A' + 1;
971 event
.m_uniChar
= event
.m_keyCode
;
975 ret
= SendCharHookAndCharEvents(event
, win
);
985 gtk_wxwindow_commit_cb (GtkIMContext
* WXUNUSED(context
),
989 wxKeyEvent
event( wxEVT_KEY_DOWN
);
991 // take modifiers, cursor position, timestamp etc. from the last
992 // key_press_event that was fed into Input Method:
993 if (window
->m_imData
->lastKeyEvent
)
995 wxFillOtherKeyEventFields(event
,
996 window
, window
->m_imData
->lastKeyEvent
);
1000 event
.SetEventObject( window
);
1003 const wxString
data(wxGTK_CONV_BACK_SYS(str
));
1007 for( wxString
::const_iterator pstr
= data
.begin(); pstr
!= data
.end(); ++pstr
)
1010 event
.m_uniChar
= *pstr
;
1011 // Backward compatible for ISO-8859-1
1012 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1013 wxLogTrace(TRACE_KEYS
, wxT("IM sent character '%c'"), event
.m_uniChar
);
1015 event
.m_keyCode
= (char)*pstr
;
1016 #endif // wxUSE_UNICODE
1018 // To conform to the docs we need to translate Ctrl-alpha
1019 // characters to values in the range 1-26.
1020 if ( event
.ControlDown() &&
1021 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
1023 if ( wxIsLowerChar(*pstr
) )
1024 event
.m_keyCode
= *pstr
- 'a' + 1;
1025 if ( wxIsUpperChar(*pstr
) )
1026 event
.m_keyCode
= *pstr
- 'A' + 1;
1028 event
.m_keyCode
= *pstr
- 'a' + 1;
1030 event
.m_uniChar
= event
.m_keyCode
;
1034 SendCharHookAndCharEvents(event
, window
);
1040 //-----------------------------------------------------------------------------
1041 // "key_release_event" from any window
1042 //-----------------------------------------------------------------------------
1046 gtk_window_key_release_callback( GtkWidget
* WXUNUSED(widget
),
1047 GdkEventKey
*gdk_event
,
1053 if (g_blockEventsOnDrag
)
1056 wxKeyEvent
event( wxEVT_KEY_UP
);
1057 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1059 // unknown key pressed, ignore (the event would be useless anyhow)
1063 return win
->GTKProcessEvent(event
);
1067 // ============================================================================
1069 // ============================================================================
1071 // ----------------------------------------------------------------------------
1072 // mouse event processing helpers
1073 // ----------------------------------------------------------------------------
1075 // init wxMouseEvent with the info from GdkEventXXX struct
1076 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1077 wxMouseEvent
& event
,
1080 event
.SetTimestamp( gdk_event
->time
);
1081 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1082 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1083 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1084 event
.m_metaDown
= (gdk_event
->state
& GDK_META_MASK
) != 0;
1085 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
) != 0;
1086 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
) != 0;
1087 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
) != 0;
1088 event
.m_aux1Down
= (gdk_event
->state
& GDK_BUTTON4_MASK
) != 0;
1089 event
.m_aux2Down
= (gdk_event
->state
& GDK_BUTTON5_MASK
) != 0;
1091 wxPoint pt
= win
->GetClientAreaOrigin();
1092 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1093 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1095 if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
))
1097 // origin in the upper right corner
1098 int window_width
= win
->m_wxwindow
->allocation
.width
;
1099 event
.m_x
= window_width
- event
.m_x
;
1102 event
.SetEventObject( win
);
1103 event
.SetId( win
->GetId() );
1104 event
.SetTimestamp( gdk_event
->time
);
1107 static void AdjustEventButtonState(wxMouseEvent
& event
)
1109 // GDK reports the old state of the button for a button press event, but
1110 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1111 // for a LEFT_DOWN event, not FALSE, so we will invert
1112 // left/right/middleDown for the corresponding click events
1114 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1115 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1116 (event
.GetEventType() == wxEVT_LEFT_UP
))
1118 event
.m_leftDown
= !event
.m_leftDown
;
1122 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1123 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1124 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1126 event
.m_middleDown
= !event
.m_middleDown
;
1130 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1131 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1132 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1134 event
.m_rightDown
= !event
.m_rightDown
;
1139 // find the window to send the mouse event too
1141 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1146 if (win
->m_wxwindow
)
1148 wxPizza
* pizza
= WX_PIZZA(win
->m_wxwindow
);
1149 xx
+= pizza
->m_scroll_x
;
1150 yy
+= pizza
->m_scroll_y
;
1153 wxWindowList
::compatibility_iterator node
= win
->GetChildren().GetFirst();
1156 wxWindowGTK
*child
= node
->GetData();
1158 node
= node
->GetNext();
1159 if (!child
->IsShown())
1162 if (child
->GTKIsTransparentForMouse())
1164 // wxStaticBox is transparent in the box itself
1165 int xx1
= child
->m_x
;
1166 int yy1
= child
->m_y
;
1167 int xx2
= child
->m_x
+ child
->m_width
;
1168 int yy2
= child
->m_y
+ child
->m_height
;
1171 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1173 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1175 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1177 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1188 if ((child
->m_wxwindow
== NULL
) &&
1189 (child
->m_x
<= xx
) &&
1190 (child
->m_y
<= yy
) &&
1191 (child
->m_x
+child
->m_width
>= xx
) &&
1192 (child
->m_y
+child
->m_height
>= yy
))
1205 // ----------------------------------------------------------------------------
1206 // common event handlers helpers
1207 // ----------------------------------------------------------------------------
1209 bool wxWindowGTK
::GTKProcessEvent(wxEvent
& event
) const
1211 // nothing special at this level
1212 return HandleWindowEvent(event
);
1215 bool wxWindowGTK
::GTKShouldIgnoreEvent() const
1217 return !m_hasVMT
|| g_blockEventsOnDrag
;
1220 int wxWindowGTK
::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1224 if (g_blockEventsOnDrag
)
1226 if (g_blockEventsOnScroll
)
1229 if (!GTKIsOwnWindow(event
->window
))
1235 // overloads for all GDK event types we use here: we need to have this as
1236 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1237 // derives from it in the sense that the structs have the same layout
1238 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1239 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1241 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1244 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1245 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1246 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1248 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1250 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1251 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1255 // all event handlers must have C linkage as they're called from GTK+ C code
1259 //-----------------------------------------------------------------------------
1260 // "button_press_event"
1261 //-----------------------------------------------------------------------------
1264 gtk_window_button_press_callback( GtkWidget
*widget
,
1265 GdkEventButton
*gdk_event
,
1268 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1270 g_lastButtonNumber
= gdk_event
->button
;
1272 // GDK sends surplus button down events
1273 // before a double click event. We
1274 // need to filter these out.
1275 if ((gdk_event
->type
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
))
1277 GdkEvent
*peek_event
= gdk_event_peek();
1280 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1281 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1283 gdk_event_free( peek_event
);
1288 gdk_event_free( peek_event
);
1293 wxEventType event_type
= wxEVT_NULL
;
1295 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1296 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1298 // Reset GDK internal timestamp variables in order to disable GDK
1299 // triple click events. GDK will then next time believe no button has
1300 // been clicked just before, and send a normal button click event.
1301 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1302 display
->button_click_time
[1] = 0;
1303 display
->button_click_time
[0] = 0;
1306 if (gdk_event
->button
== 1)
1308 // note that GDK generates triple click events which are not supported
1309 // by wxWidgets but still have to be passed to the app as otherwise
1310 // clicks would simply go missing
1311 switch (gdk_event
->type
)
1313 // we shouldn't get triple clicks at all for GTK2 because we
1314 // suppress them artificially using the code above but we still
1315 // should map them to something for GTK1 and not just ignore them
1316 // as this would lose clicks
1317 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1318 case GDK_BUTTON_PRESS
:
1319 event_type
= wxEVT_LEFT_DOWN
;
1322 case GDK_2BUTTON_PRESS
:
1323 event_type
= wxEVT_LEFT_DCLICK
;
1327 // just to silence gcc warnings
1331 else if (gdk_event
->button
== 2)
1333 switch (gdk_event
->type
)
1335 case GDK_3BUTTON_PRESS
:
1336 case GDK_BUTTON_PRESS
:
1337 event_type
= wxEVT_MIDDLE_DOWN
;
1340 case GDK_2BUTTON_PRESS
:
1341 event_type
= wxEVT_MIDDLE_DCLICK
;
1348 else if (gdk_event
->button
== 3)
1350 switch (gdk_event
->type
)
1352 case GDK_3BUTTON_PRESS
:
1353 case GDK_BUTTON_PRESS
:
1354 event_type
= wxEVT_RIGHT_DOWN
;
1357 case GDK_2BUTTON_PRESS
:
1358 event_type
= wxEVT_RIGHT_DCLICK
;
1366 if ( event_type
== wxEVT_NULL
)
1368 // unknown mouse button or click type
1372 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1374 wxMouseEvent
event( event_type
);
1375 InitMouseEvent( win
, event
, gdk_event
);
1377 AdjustEventButtonState(event
);
1379 // find the correct window to send the event to: it may be a different one
1380 // from the one which got it at GTK+ level because some controls don't have
1381 // their own X window and thus cannot get any events.
1382 if ( !g_captureWindow
)
1383 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1385 // reset the event object and id in case win changed.
1386 event
.SetEventObject( win
);
1387 event
.SetId( win
->GetId() );
1389 bool ret
= win
->GTKProcessEvent( event
);
1390 g_lastMouseEvent
= NULL
;
1394 if ((event_type
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&
1395 (gs_currentFocus
!= win
) /* && win->IsFocusable() */)
1400 if (event_type
== wxEVT_RIGHT_DOWN
)
1402 // generate a "context menu" event: this is similar to right mouse
1403 // click under many GUIs except that it is generated differently
1404 // (right up under MSW, ctrl-click under Mac, right down here) and
1406 // (a) it's a command event and so is propagated to the parent
1407 // (b) under some ports it can be generated from kbd too
1408 // (c) it uses screen coords (because of (a))
1409 wxContextMenuEvent
evtCtx(
1412 win
->ClientToScreen(event
.GetPosition()));
1413 evtCtx
.SetEventObject(win
);
1414 return win
->GTKProcessEvent(evtCtx
);
1420 //-----------------------------------------------------------------------------
1421 // "button_release_event"
1422 //-----------------------------------------------------------------------------
1425 gtk_window_button_release_callback( GtkWidget
*WXUNUSED(widget
),
1426 GdkEventButton
*gdk_event
,
1429 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1431 g_lastButtonNumber
= 0;
1433 wxEventType event_type
= wxEVT_NULL
;
1435 switch (gdk_event
->button
)
1438 event_type
= wxEVT_LEFT_UP
;
1442 event_type
= wxEVT_MIDDLE_UP
;
1446 event_type
= wxEVT_RIGHT_UP
;
1450 // unknown button, don't process
1454 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1456 wxMouseEvent
event( event_type
);
1457 InitMouseEvent( win
, event
, gdk_event
);
1459 AdjustEventButtonState(event
);
1461 if ( !g_captureWindow
)
1462 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1464 // reset the event object and id in case win changed.
1465 event
.SetEventObject( win
);
1466 event
.SetId( win
->GetId() );
1468 bool ret
= win
->GTKProcessEvent(event
);
1470 g_lastMouseEvent
= NULL
;
1475 //-----------------------------------------------------------------------------
1476 // "motion_notify_event"
1477 //-----------------------------------------------------------------------------
1480 gtk_window_motion_notify_callback( GtkWidget
* WXUNUSED(widget
),
1481 GdkEventMotion
*gdk_event
,
1484 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1486 if (gdk_event
->is_hint
)
1490 GdkModifierType state
;
1491 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1496 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1498 wxMouseEvent
event( wxEVT_MOTION
);
1499 InitMouseEvent(win
, event
, gdk_event
);
1501 if ( g_captureWindow
)
1503 // synthesise a mouse enter or leave event if needed
1504 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1505 // This seems to be necessary and actually been added to
1506 // GDK itself in version 2.0.X
1509 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1510 if ( hasMouse
!= g_captureWindowHasMouse
)
1512 // the mouse changed window
1513 g_captureWindowHasMouse
= hasMouse
;
1515 wxMouseEvent
eventM(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1516 : wxEVT_LEAVE_WINDOW
);
1517 InitMouseEvent(win
, eventM
, gdk_event
);
1518 eventM
.SetEventObject(win
);
1519 win
->GTKProcessEvent(eventM
);
1524 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1526 // reset the event object and id in case win changed.
1527 event
.SetEventObject( win
);
1528 event
.SetId( win
->GetId() );
1531 if ( !g_captureWindow
)
1533 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1534 if (win
->GTKProcessEvent( cevent
))
1536 win
->SetCursor( cevent
.GetCursor() );
1540 bool ret
= win
->GTKProcessEvent(event
);
1542 g_lastMouseEvent
= NULL
;
1547 //-----------------------------------------------------------------------------
1548 // "scroll_event" (mouse wheel event)
1549 //-----------------------------------------------------------------------------
1552 window_scroll_event_hscrollbar(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1554 if (gdk_event
->direction
!= GDK_SCROLL_LEFT
&&
1555 gdk_event
->direction
!= GDK_SCROLL_RIGHT
)
1560 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1561 InitMouseEvent(win
, event
, gdk_event
);
1563 GtkRange
*range
= win
->m_scrollBar
[wxWindow
::ScrollDir_Horz
];
1564 if (!range
) return FALSE
;
1566 if (range
&& GTK_WIDGET_VISIBLE (range
))
1568 GtkAdjustment
*adj
= range
->adjustment
;
1569 gdouble delta
= adj
->step_increment
* 3;
1570 if (gdk_event
->direction
== GDK_SCROLL_LEFT
)
1573 gdouble new_value
= CLAMP (adj
->value
+ delta
, adj
->lower
, adj
->upper
- adj
->page_size
);
1575 gtk_adjustment_set_value (adj
, new_value
);
1584 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1586 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1587 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1592 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1593 InitMouseEvent(win
, event
, gdk_event
);
1595 // FIXME: Get these values from GTK or GDK
1596 event
.m_linesPerAction
= 3;
1597 event
.m_wheelDelta
= 120;
1598 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1599 event
.m_wheelRotation
= 120;
1601 event
.m_wheelRotation
= -120;
1603 if (win
->GTKProcessEvent(event
))
1606 GtkRange
*range
= win
->m_scrollBar
[wxWindow
::ScrollDir_Vert
];
1607 if (!range
) return FALSE
;
1609 if (range
&& GTK_WIDGET_VISIBLE (range
))
1611 GtkAdjustment
*adj
= range
->adjustment
;
1612 gdouble delta
= adj
->step_increment
* 3;
1613 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1616 gdouble new_value
= CLAMP (adj
->value
+ delta
, adj
->lower
, adj
->upper
- adj
->page_size
);
1618 gtk_adjustment_set_value (adj
, new_value
);
1626 //-----------------------------------------------------------------------------
1628 //-----------------------------------------------------------------------------
1630 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1632 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1633 event
.SetEventObject(win
);
1634 return win
->GTKProcessEvent(event
);
1637 //-----------------------------------------------------------------------------
1639 //-----------------------------------------------------------------------------
1642 gtk_window_focus_in_callback( GtkWidget
* WXUNUSED(widget
),
1643 GdkEventFocus
*WXUNUSED(event
),
1646 return win
->GTKHandleFocusIn();
1649 //-----------------------------------------------------------------------------
1650 // "focus_out_event"
1651 //-----------------------------------------------------------------------------
1654 gtk_window_focus_out_callback( GtkWidget
* WXUNUSED(widget
),
1655 GdkEventFocus
* WXUNUSED(gdk_event
),
1658 return win
->GTKHandleFocusOut();
1661 //-----------------------------------------------------------------------------
1663 //-----------------------------------------------------------------------------
1666 wx_window_focus_callback(GtkWidget
*widget
,
1667 GtkDirectionType
WXUNUSED(direction
),
1670 // the default handler for focus signal in GtkScrolledWindow sets
1671 // focus to the window itself even if it doesn't accept focus, i.e. has no
1672 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1673 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1674 // any children which might accept focus (we know we don't accept the focus
1675 // ourselves as this signal is only connected in this case)
1676 if ( win
->GetChildren().empty() )
1677 g_signal_stop_emission_by_name(widget
, "focus");
1679 // we didn't change the focus
1683 //-----------------------------------------------------------------------------
1684 // "enter_notify_event"
1685 //-----------------------------------------------------------------------------
1688 gtk_window_enter_callback( GtkWidget
*widget
,
1689 GdkEventCrossing
*gdk_event
,
1692 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1694 // Event was emitted after a grab
1695 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1699 GdkModifierType state
= (GdkModifierType
)0;
1701 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1703 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1704 InitMouseEvent(win
, event
, gdk_event
);
1705 wxPoint pt
= win
->GetClientAreaOrigin();
1706 event
.m_x
= x
+ pt
.x
;
1707 event
.m_y
= y
+ pt
.y
;
1709 if ( !g_captureWindow
)
1711 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1712 if (win
->GTKProcessEvent( cevent
))
1714 win
->SetCursor( cevent
.GetCursor() );
1718 return win
->GTKProcessEvent(event
);
1721 //-----------------------------------------------------------------------------
1722 // "leave_notify_event"
1723 //-----------------------------------------------------------------------------
1726 gtk_window_leave_callback( GtkWidget
*widget
,
1727 GdkEventCrossing
*gdk_event
,
1730 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1732 // Event was emitted after an ungrab
1733 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1735 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1739 GdkModifierType state
= (GdkModifierType
)0;
1741 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1743 InitMouseEvent(win
, event
, gdk_event
);
1745 return win
->GTKProcessEvent(event
);
1748 //-----------------------------------------------------------------------------
1749 // "value_changed" from scrollbar
1750 //-----------------------------------------------------------------------------
1753 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
1755 wxEventType eventType
= win
->GTKGetScrollEventType(range
);
1756 if (eventType
!= wxEVT_NULL
)
1758 // Convert scroll event type to scrollwin event type
1759 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
1761 // find the scrollbar which generated the event
1762 wxWindowGTK
::ScrollDir dir
= win
->ScrollDirFromRange(range
);
1764 // generate the corresponding wx event
1765 const int orient
= wxWindow
::OrientFromScrollDir(dir
);
1766 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
1767 event
.SetEventObject(win
);
1769 win
->GTKProcessEvent(event
);
1773 //-----------------------------------------------------------------------------
1774 // "button_press_event" from scrollbar
1775 //-----------------------------------------------------------------------------
1778 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
1780 g_blockEventsOnScroll
= true;
1781 win
->m_mouseButtonDown
= true;
1786 //-----------------------------------------------------------------------------
1787 // "event_after" from scrollbar
1788 //-----------------------------------------------------------------------------
1791 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
1793 if (event
->type
== GDK_BUTTON_RELEASE
)
1795 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1797 const int orient
= wxWindow
::OrientFromScrollDir(
1798 win
->ScrollDirFromRange(range
));
1799 wxScrollWinEvent
evt(wxEVT_SCROLLWIN_THUMBRELEASE
,
1800 win
->GetScrollPos(orient
), orient
);
1801 evt
.SetEventObject(win
);
1802 win
->GTKProcessEvent(evt
);
1806 //-----------------------------------------------------------------------------
1807 // "button_release_event" from scrollbar
1808 //-----------------------------------------------------------------------------
1811 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
1813 g_blockEventsOnScroll
= false;
1814 win
->m_mouseButtonDown
= false;
1815 // If thumb tracking
1816 if (win
->m_isScrolling
)
1818 win
->m_isScrolling
= false;
1819 // Hook up handler to send thumb release event after this emission is finished.
1820 // To allow setting scroll position from event handler, sending event must
1821 // be deferred until after the GtkRange handler for this signal has run
1822 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1828 //-----------------------------------------------------------------------------
1829 // "realize" from m_widget
1830 //-----------------------------------------------------------------------------
1833 gtk_window_realized_callback(GtkWidget
* widget
, wxWindow
* win
)
1837 gtk_im_context_set_client_window( win
->m_imData
->context
,
1838 win
->m_wxwindow ? win
->GTKGetDrawingWindow() : widget
->window
);
1841 // We cannot set colours and fonts before the widget
1842 // been realized, so we do this directly after realization
1843 // or otherwise in idle time
1845 if (win
->m_needsStyleChange
)
1847 win
->SetBackgroundStyle(win
->GetBackgroundStyle());
1848 win
->m_needsStyleChange
= false;
1851 wxWindowCreateEvent
event( win
);
1852 event
.SetEventObject( win
);
1853 win
->GTKProcessEvent( event
);
1855 win
->GTKUpdateCursor(true, false);
1858 //-----------------------------------------------------------------------------
1859 // "size_allocate" from m_wxwindow or m_widget
1860 //-----------------------------------------------------------------------------
1863 size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxWindow
* win
)
1865 int w
= alloc
->width
;
1866 int h
= alloc
->height
;
1867 if (win
->m_wxwindow
)
1869 int border_x
, border_y
;
1870 WX_PIZZA(win
->m_wxwindow
)->get_border_widths(border_x
, border_y
);
1876 if (win
->m_oldClientWidth
!= w
|| win
->m_oldClientHeight
!= h
)
1878 win
->m_oldClientWidth
= w
;
1879 win
->m_oldClientHeight
= h
;
1880 // this callback can be connected to m_wxwindow,
1881 // so always get size from m_widget->allocation
1882 win
->m_width
= win
->m_widget
->allocation
.width
;
1883 win
->m_height
= win
->m_widget
->allocation
.height
;
1884 if (!win
->m_nativeSizeEvent
)
1886 wxSizeEvent
event(win
->GetSize(), win
->GetId());
1887 event
.SetEventObject(win
);
1888 win
->GTKProcessEvent(event
);
1893 //-----------------------------------------------------------------------------
1895 //-----------------------------------------------------------------------------
1897 #if GTK_CHECK_VERSION(2, 8, 0)
1899 gtk_window_grab_broken( GtkWidget
*,
1900 GdkEventGrabBroken
*event
,
1903 // Mouse capture has been lost involuntarily, notify the application
1904 if(!event
->keyboard
&& wxWindow
::GetCapture() == win
)
1906 wxMouseCaptureLostEvent
evt( win
->GetId() );
1907 evt
.SetEventObject( win
);
1908 win
->HandleWindowEvent( evt
);
1914 //-----------------------------------------------------------------------------
1916 //-----------------------------------------------------------------------------
1919 void gtk_window_style_set_callback( GtkWidget
*WXUNUSED(widget
),
1920 GtkStyle
*previous_style
,
1923 if (win
&& previous_style
)
1925 wxSysColourChangedEvent event
;
1926 event
.SetEventObject(win
);
1928 win
->GTKProcessEvent( event
);
1934 // ----------------------------------------------------------------------------
1935 // this wxWindowBase function is implemented here (in platform-specific file)
1936 // because it is static and so couldn't be made virtual
1937 // ----------------------------------------------------------------------------
1939 wxWindow
*wxWindowBase
::DoFindFocus()
1941 wxWindowGTK
*focus
= gs_pendingFocus ? gs_pendingFocus
: gs_currentFocus
;
1942 // the cast is necessary when we compile in wxUniversal mode
1943 return static_cast<wxWindow
*>(focus
);
1946 void wxWindowGTK
::AddChildGTK(wxWindowGTK
* child
)
1948 wxASSERT_MSG(m_wxwindow
, "Cannot add a child to a window without a client area");
1950 // the window might have been scrolled already, we
1951 // have to adapt the position
1952 wxPizza
* pizza
= WX_PIZZA(m_wxwindow
);
1953 child
->m_x
+= pizza
->m_scroll_x
;
1954 child
->m_y
+= pizza
->m_scroll_y
;
1956 gtk_widget_set_size_request(
1957 child
->m_widget
, child
->m_width
, child
->m_height
);
1958 pizza
->put(child
->m_widget
, child
->m_x
, child
->m_y
);
1961 //-----------------------------------------------------------------------------
1963 //-----------------------------------------------------------------------------
1965 wxWindow
*wxGetActiveWindow()
1967 return wxWindow
::FindFocus();
1971 wxMouseState
wxGetMouseState()
1977 GdkModifierType mask
;
1979 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
1983 ms
.SetLeftDown((mask
& GDK_BUTTON1_MASK
) != 0);
1984 ms
.SetMiddleDown((mask
& GDK_BUTTON2_MASK
) != 0);
1985 ms
.SetRightDown((mask
& GDK_BUTTON3_MASK
) != 0);
1986 ms
.SetAux1Down((mask
& GDK_BUTTON4_MASK
) != 0);
1987 ms
.SetAux2Down((mask
& GDK_BUTTON5_MASK
) != 0);
1989 ms
.SetControlDown((mask
& GDK_CONTROL_MASK
) != 0);
1990 ms
.SetShiftDown((mask
& GDK_SHIFT_MASK
) != 0);
1991 ms
.SetAltDown((mask
& GDK_MOD1_MASK
) != 0);
1992 ms
.SetMetaDown((mask
& GDK_META_MASK
) != 0);
1997 //-----------------------------------------------------------------------------
1999 //-----------------------------------------------------------------------------
2001 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2003 #ifdef __WXUNIVERSAL__
2004 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2006 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2007 #endif // __WXUNIVERSAL__/__WXGTK__
2009 void wxWindowGTK
::Init()
2014 m_focusWidget
= NULL
;
2024 m_showOnIdle
= false;
2027 m_nativeSizeEvent
= false;
2029 m_isScrolling
= false;
2030 m_mouseButtonDown
= false;
2032 // initialize scrolling stuff
2033 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2035 m_scrollBar
[dir
] = NULL
;
2036 m_scrollPos
[dir
] = 0;
2040 m_oldClientHeight
= 0;
2042 m_clipPaintRegion
= false;
2044 m_needsStyleChange
= false;
2046 m_cursor
= *wxSTANDARD_CURSOR
;
2049 m_dirtyTabOrder
= false;
2052 wxWindowGTK
::wxWindowGTK()
2057 wxWindowGTK
::wxWindowGTK( wxWindow
*parent
,
2062 const wxString
&name
)
2066 Create( parent
, id
, pos
, size
, style
, name
);
2069 bool wxWindowGTK
::Create( wxWindow
*parent
,
2074 const wxString
&name
)
2076 // Get default border
2077 wxBorder border
= GetBorder(style
);
2079 style
&= ~wxBORDER_MASK
;
2082 if (!PreCreation( parent
, pos
, size
) ||
2083 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2085 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2089 // We should accept the native look
2091 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2092 scroll_class
->scrollbar_spacing
= 0;
2096 m_wxwindow
= wxPizza
::New(m_windowStyle
);
2097 #ifndef __WXUNIVERSAL__
2098 if (HasFlag(wxPizza
::BORDER_STYLES
))
2100 g_signal_connect(m_wxwindow
, "parent_set",
2101 G_CALLBACK(parent_set
), this);
2104 if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
))
2105 m_widget
= m_wxwindow
;
2108 m_widget
= gtk_scrolled_window_new( NULL
, NULL
);
2110 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2112 // There is a conflict with default bindings at GTK+
2113 // level between scrolled windows and notebooks both of which want to use
2114 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2115 // direction and notebooks for changing pages -- we decide that if we don't
2116 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2117 // means we can get working keyboard navigation in notebooks
2118 if ( !HasFlag(wxHSCROLL
) )
2121 bindings
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
));
2124 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
);
2125 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
);
2129 if (HasFlag(wxALWAYS_SHOW_SB
))
2131 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
2133 scrolledWindow
->hscrollbar_visible
= TRUE
;
2134 scrolledWindow
->vscrollbar_visible
= TRUE
;
2138 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2141 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2142 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2143 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2144 gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE
);
2146 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2148 // connect various scroll-related events
2149 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2151 // these handlers block mouse events to any window during scrolling
2152 // such as motion events and prevent GTK and wxWidgets from fighting
2153 // over where the slider should be
2154 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2155 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2156 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2157 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2159 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2160 G_CALLBACK(gtk_scrollbar_event_after
), this);
2161 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2163 // these handlers get notified when scrollbar slider moves
2164 g_signal_connect_after(m_scrollBar
[dir
], "value_changed",
2165 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2168 gtk_widget_show( m_wxwindow
);
2170 g_object_ref(m_widget
);
2173 m_parent
->DoAddChild( this );
2175 m_focusWidget
= m_wxwindow
;
2177 SetCanFocus(AcceptsFocus());
2184 wxWindowGTK
::~wxWindowGTK()
2188 if (gs_currentFocus
== this)
2189 gs_currentFocus
= NULL
;
2190 if (gs_pendingFocus
== this)
2191 gs_pendingFocus
= NULL
;
2193 if ( gs_deferredFocusOut
== this )
2194 gs_deferredFocusOut
= NULL
;
2198 // destroy children before destroying this window itself
2201 // unhook focus handlers to prevent stray events being
2202 // propagated to this (soon to be) dead object
2203 if (m_focusWidget
!= NULL
)
2205 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2206 (gpointer
) gtk_window_focus_in_callback
,
2208 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2209 (gpointer
) gtk_window_focus_out_callback
,
2216 // delete before the widgets to avoid a crash on solaris
2219 // avoid problem with GTK+ 2.18 where a frozen window causes the whole
2220 // TLW to be frozen, and if the window is then destroyed, nothing ever
2221 // gets painted again
2227 // Note that gtk_widget_destroy() does not destroy the widget, it just
2228 // emits the "destroy" signal. The widget is not actually destroyed
2229 // until its reference count drops to zero.
2230 gtk_widget_destroy(m_widget
);
2231 // Release our reference, should be the last one
2232 g_object_unref(m_widget
);
2238 bool wxWindowGTK
::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2240 if ( GTKNeedsParent() )
2242 wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") );
2245 // Use either the given size, or the default if -1 is given.
2246 // See wxWindowBase for these functions.
2247 m_width
= WidthDefault(size
.x
) ;
2248 m_height
= HeightDefault(size
.y
);
2256 void wxWindowGTK
::PostCreation()
2258 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2264 // these get reported to wxWidgets -> wxPaintEvent
2266 g_signal_connect (m_wxwindow
, "expose_event",
2267 G_CALLBACK (gtk_window_expose_callback
), this);
2269 if (GetLayoutDirection() == wxLayout_LeftToRight
)
2270 gtk_widget_set_redraw_on_allocate(m_wxwindow
, HasFlag(wxFULL_REPAINT_ON_RESIZE
));
2273 // Create input method handler
2274 m_imData
= new wxGtkIMData
;
2276 // Cannot handle drawing preedited text yet
2277 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2279 g_signal_connect (m_imData
->context
, "commit",
2280 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2285 if (!GTK_IS_WINDOW(m_widget
))
2287 if (m_focusWidget
== NULL
)
2288 m_focusWidget
= m_widget
;
2292 g_signal_connect (m_focusWidget
, "focus_in_event",
2293 G_CALLBACK (gtk_window_focus_in_callback
), this);
2294 g_signal_connect (m_focusWidget
, "focus_out_event",
2295 G_CALLBACK (gtk_window_focus_out_callback
), this);
2299 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2300 G_CALLBACK (gtk_window_focus_in_callback
), this);
2301 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2302 G_CALLBACK (gtk_window_focus_out_callback
), this);
2306 if ( !AcceptsFocusFromKeyboard() )
2310 g_signal_connect(m_widget
, "focus",
2311 G_CALLBACK(wx_window_focus_callback
), this);
2314 // connect to the various key and mouse handlers
2316 GtkWidget
*connect_widget
= GetConnectWidget();
2318 ConnectWidget( connect_widget
);
2320 /* We cannot set colours, fonts and cursors before the widget has
2321 been realized, so we do this directly after realization */
2322 g_signal_connect (connect_widget
, "realize",
2323 G_CALLBACK (gtk_window_realized_callback
), this);
2327 g_signal_connect(m_wxwindow ? m_wxwindow
: m_widget
, "size_allocate",
2328 G_CALLBACK(size_allocate
), this);
2331 #if GTK_CHECK_VERSION(2, 8, 0)
2332 if ( gtk_check_version(2,8,0) == NULL
)
2334 // Make sure we can notify the app when mouse capture is lost
2337 g_signal_connect (m_wxwindow
, "grab_broken_event",
2338 G_CALLBACK (gtk_window_grab_broken
), this);
2341 if ( connect_widget
!= m_wxwindow
)
2343 g_signal_connect (connect_widget
, "grab_broken_event",
2344 G_CALLBACK (gtk_window_grab_broken
), this);
2347 #endif // GTK+ >= 2.8
2349 if ( GTKShouldConnectSizeRequest() )
2351 // This is needed if we want to add our windows into native
2352 // GTK controls, such as the toolbar. With this callback, the
2353 // toolbar gets to know the correct size (the one set by the
2354 // programmer). Sadly, it misbehaves for wxComboBox.
2355 g_signal_connect (m_widget
, "size_request",
2356 G_CALLBACK (wxgtk_window_size_request_callback
),
2360 InheritAttributes();
2364 SetLayoutDirection(wxLayout_Default
);
2366 // unless the window was created initially hidden (i.e. Hide() had been
2367 // called before Create()), we should show it at GTK+ level as well
2369 gtk_widget_show( m_widget
);
2372 gulong wxWindowGTK
::GTKConnectWidget(const char *signal
, void (*callback
)())
2374 return g_signal_connect(m_widget
, signal
, callback
, this);
2377 void wxWindowGTK
::ConnectWidget( GtkWidget
*widget
)
2379 g_signal_connect (widget
, "key_press_event",
2380 G_CALLBACK (gtk_window_key_press_callback
), this);
2381 g_signal_connect (widget
, "key_release_event",
2382 G_CALLBACK (gtk_window_key_release_callback
), this);
2383 g_signal_connect (widget
, "button_press_event",
2384 G_CALLBACK (gtk_window_button_press_callback
), this);
2385 g_signal_connect (widget
, "button_release_event",
2386 G_CALLBACK (gtk_window_button_release_callback
), this);
2387 g_signal_connect (widget
, "motion_notify_event",
2388 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2390 g_signal_connect (widget
, "scroll_event",
2391 G_CALLBACK (window_scroll_event
), this);
2392 if (m_scrollBar
[ScrollDir_Horz
])
2393 g_signal_connect (m_scrollBar
[ScrollDir_Horz
], "scroll_event",
2394 G_CALLBACK (window_scroll_event_hscrollbar
), this);
2395 if (m_scrollBar
[ScrollDir_Vert
])
2396 g_signal_connect (m_scrollBar
[ScrollDir_Vert
], "scroll_event",
2397 G_CALLBACK (window_scroll_event
), this);
2399 g_signal_connect (widget
, "popup_menu",
2400 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2401 g_signal_connect (widget
, "enter_notify_event",
2402 G_CALLBACK (gtk_window_enter_callback
), this);
2403 g_signal_connect (widget
, "leave_notify_event",
2404 G_CALLBACK (gtk_window_leave_callback
), this);
2406 if (IsTopLevel() && m_wxwindow
)
2407 g_signal_connect (m_wxwindow
, "style_set",
2408 G_CALLBACK (gtk_window_style_set_callback
), this);
2411 bool wxWindowGTK
::Destroy()
2413 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2417 return wxWindowBase
::Destroy();
2420 void wxWindowGTK
::DoMoveWindow(int x
, int y
, int width
, int height
)
2422 gtk_widget_set_size_request(m_widget
, width
, height
);
2424 // inform the parent to perform the move
2425 wxASSERT_MSG(m_parent
&& m_parent
->m_wxwindow
,
2426 "the parent window has no client area?");
2427 WX_PIZZA(m_parent
->m_wxwindow
)->move(m_widget
, x
, y
);
2430 void wxWindowGTK
::ConstrainSize()
2433 // GPE's window manager doesn't like size hints at all, esp. when the user
2434 // has to use the virtual keyboard, so don't constrain size there
2438 const wxSize minSize
= GetMinSize();
2439 const wxSize maxSize
= GetMaxSize();
2440 if (minSize
.x
> 0 && m_width
< minSize
.x
) m_width
= minSize
.x
;
2441 if (minSize
.y
> 0 && m_height
< minSize
.y
) m_height
= minSize
.y
;
2442 if (maxSize
.x
> 0 && m_width
> maxSize
.x
) m_width
= maxSize
.x
;
2443 if (maxSize
.y
> 0 && m_height
> maxSize
.y
) m_height
= maxSize
.y
;
2447 void wxWindowGTK
::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2449 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2450 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2452 int currentX
, currentY
;
2453 GetPosition(¤tX
, ¤tY
);
2454 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2456 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2458 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2460 // calculate the best size if we should auto size the window
2461 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2462 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2464 const wxSize sizeBest
= GetBestSize();
2465 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2467 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2468 height
= sizeBest
.y
;
2471 const wxSize
oldSize(m_width
, m_height
);
2477 if (m_parent
->m_wxwindow
)
2479 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2480 m_x
= x
+ pizza
->m_scroll_x
;
2481 m_y
= y
+ pizza
->m_scroll_y
;
2483 int left_border
= 0;
2484 int right_border
= 0;
2486 int bottom_border
= 0;
2488 /* the default button has a border around it */
2489 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2491 GtkBorder
*default_border
= NULL
;
2492 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2495 left_border
+= default_border
->left
;
2496 right_border
+= default_border
->right
;
2497 top_border
+= default_border
->top
;
2498 bottom_border
+= default_border
->bottom
;
2499 gtk_border_free( default_border
);
2503 DoMoveWindow( m_x
- left_border
,
2505 m_width
+left_border
+right_border
,
2506 m_height
+top_border
+bottom_border
);
2509 if (m_width
!= oldSize
.x
|| m_height
!= oldSize
.y
)
2511 // update these variables to keep size_allocate handler
2512 // from sending another size event for this change
2513 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2515 gtk_widget_queue_resize(m_widget
);
2516 if (!m_nativeSizeEvent
)
2518 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2519 event
.SetEventObject( this );
2520 HandleWindowEvent( event
);
2523 if (sizeFlags
& wxSIZE_FORCE_EVENT
)
2525 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2526 event
.SetEventObject( this );
2527 HandleWindowEvent( event
);
2531 bool wxWindowGTK
::GTKShowFromOnIdle()
2533 if (IsShown() && m_showOnIdle
&& !GTK_WIDGET_VISIBLE (m_widget
))
2535 GtkAllocation alloc
;
2538 alloc
.width
= m_width
;
2539 alloc
.height
= m_height
;
2540 gtk_widget_size_allocate( m_widget
, &alloc
);
2541 gtk_widget_show( m_widget
);
2542 wxShowEvent
eventShow(GetId(), true);
2543 eventShow
.SetEventObject(this);
2544 HandleWindowEvent(eventShow
);
2545 m_showOnIdle
= false;
2552 void wxWindowGTK
::OnInternalIdle()
2554 if ( gs_deferredFocusOut
)
2555 GTKHandleDeferredFocusOut();
2557 // Check if we have to show window now
2558 if (GTKShowFromOnIdle()) return;
2560 if ( m_dirtyTabOrder
)
2562 m_dirtyTabOrder
= false;
2566 // Update style if the window was not yet realized when
2567 // SetBackgroundStyle() was called
2568 if (m_needsStyleChange
)
2570 SetBackgroundStyle(GetBackgroundStyle());
2571 m_needsStyleChange
= false;
2574 if (wxUpdateUIEvent
::CanUpdate(this) && IsShownOnScreen())
2575 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2578 void wxWindowGTK
::DoGetSize( int *width
, int *height
) const
2580 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2582 if (width
) (*width
) = m_width
;
2583 if (height
) (*height
) = m_height
;
2586 void wxWindowGTK
::DoSetClientSize( int width
, int height
)
2588 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2590 const wxSize size
= GetSize();
2591 const wxSize clientSize
= GetClientSize();
2592 SetSize(width
+ (size
.x
- clientSize
.x
), height
+ (size
.y
- clientSize
.y
));
2595 void wxWindowGTK
::DoGetClientSize( int *width
, int *height
) const
2597 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2604 // if window is scrollable, account for scrollbars
2605 if ( GTK_IS_SCROLLED_WINDOW(m_widget
) )
2607 GtkPolicyType policy
[ScrollDir_Max
];
2608 gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(m_widget
),
2609 &policy
[ScrollDir_Horz
],
2610 &policy
[ScrollDir_Vert
]);
2612 for ( int i
= 0; i
< ScrollDir_Max
; i
++ )
2614 // don't account for the scrollbars we don't have
2615 GtkRange
* const range
= m_scrollBar
[i
];
2619 // nor for the ones we have but don't current show
2620 switch ( policy
[i
] )
2622 case GTK_POLICY_NEVER
:
2623 // never shown so doesn't take any place
2626 case GTK_POLICY_ALWAYS
:
2627 // no checks necessary
2630 case GTK_POLICY_AUTOMATIC
:
2631 // may be shown or not, check
2632 GtkAdjustment
*adj
= gtk_range_get_adjustment(range
);
2633 if ( adj
->upper
<= adj
->page_size
)
2637 GtkScrolledWindowClass
*scroll_class
=
2638 GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2641 gtk_widget_size_request(GTK_WIDGET(range
), &req
);
2642 if (i
== ScrollDir_Horz
)
2643 h
-= req
.height
+ scroll_class
->scrollbar_spacing
;
2645 w
-= req
.width
+ scroll_class
->scrollbar_spacing
;
2649 const wxSize sizeBorders
= DoGetBorderSize();
2659 if (width
) *width
= w
;
2660 if (height
) *height
= h
;
2663 wxSize wxWindowGTK
::DoGetBorderSize() const
2666 return wxWindowBase
::DoGetBorderSize();
2669 WX_PIZZA(m_wxwindow
)->get_border_widths(x
, y
);
2671 return 2*wxSize(x
, y
);
2674 void wxWindowGTK
::DoGetPosition( int *x
, int *y
) const
2676 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2680 if (!IsTopLevel() && m_parent
&& m_parent
->m_wxwindow
)
2682 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2683 dx
= pizza
->m_scroll_x
;
2684 dy
= pizza
->m_scroll_y
;
2687 if (m_x
== -1 && m_y
== -1)
2689 GdkWindow
*source
= NULL
;
2691 source
= m_wxwindow
->window
;
2693 source
= m_widget
->window
;
2699 gdk_window_get_origin( source
, &org_x
, &org_y
);
2702 m_parent
->ScreenToClient(&org_x
, &org_y
);
2704 const_cast<wxWindowGTK
*>(this)->m_x
= org_x
;
2705 const_cast<wxWindowGTK
*>(this)->m_y
= org_y
;
2709 if (x
) (*x
) = m_x
- dx
;
2710 if (y
) (*y
) = m_y
- dy
;
2713 void wxWindowGTK
::DoClientToScreen( int *x
, int *y
) const
2715 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2717 if (!m_widget
->window
) return;
2719 GdkWindow
*source
= NULL
;
2721 source
= m_wxwindow
->window
;
2723 source
= m_widget
->window
;
2727 gdk_window_get_origin( source
, &org_x
, &org_y
);
2731 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2733 org_x
+= m_widget
->allocation
.x
;
2734 org_y
+= m_widget
->allocation
.y
;
2741 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2742 *x
= (GetClientSize().x
- *x
) + org_x
;
2750 void wxWindowGTK
::DoScreenToClient( int *x
, int *y
) const
2752 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2754 if (!m_widget
->window
) return;
2756 GdkWindow
*source
= NULL
;
2758 source
= m_wxwindow
->window
;
2760 source
= m_widget
->window
;
2764 gdk_window_get_origin( source
, &org_x
, &org_y
);
2768 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2770 org_x
+= m_widget
->allocation
.x
;
2771 org_y
+= m_widget
->allocation
.y
;
2777 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2778 *x
= (GetClientSize().x
- *x
) - org_x
;
2785 bool wxWindowGTK
::Show( bool show
)
2787 if ( !wxWindowBase
::Show(show
) )
2793 // notice that we may call Hide() before the window is created and this is
2794 // actually useful to create it hidden initially -- but we can't call
2795 // Show() before it is created
2798 wxASSERT_MSG( !show
, "can't show invalid window" );
2806 // defer until later
2810 gtk_widget_show(m_widget
);
2814 gtk_widget_hide(m_widget
);
2817 wxShowEvent
eventShow(GetId(), show
);
2818 eventShow
.SetEventObject(this);
2819 HandleWindowEvent(eventShow
);
2824 void wxWindowGTK
::DoEnable( bool enable
)
2826 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2828 gtk_widget_set_sensitive( m_widget
, enable
);
2829 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2830 gtk_widget_set_sensitive( m_wxwindow
, enable
);
2833 int wxWindowGTK
::GetCharHeight() const
2835 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
2837 wxFont font
= GetFont();
2838 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
2840 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2845 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2846 PangoLayout
*layout
= pango_layout_new(context
);
2847 pango_layout_set_font_description(layout
, desc
);
2848 pango_layout_set_text(layout
, "H", 1);
2849 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2851 PangoRectangle rect
;
2852 pango_layout_line_get_extents(line
, NULL
, &rect
);
2854 g_object_unref (layout
);
2856 return (int) PANGO_PIXELS(rect
.height
);
2859 int wxWindowGTK
::GetCharWidth() const
2861 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
2863 wxFont font
= GetFont();
2864 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
2866 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2871 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2872 PangoLayout
*layout
= pango_layout_new(context
);
2873 pango_layout_set_font_description(layout
, desc
);
2874 pango_layout_set_text(layout
, "g", 1);
2875 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2877 PangoRectangle rect
;
2878 pango_layout_line_get_extents(line
, NULL
, &rect
);
2880 g_object_unref (layout
);
2882 return (int) PANGO_PIXELS(rect
.width
);
2885 void wxWindowGTK
::DoGetTextExtent( const wxString
& string
,
2889 int *externalLeading
,
2890 const wxFont
*theFont
) const
2892 wxFont fontToUse
= theFont ?
*theFont
: GetFont();
2894 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
2903 PangoContext
*context
= NULL
;
2905 context
= gtk_widget_get_pango_context( m_widget
);
2914 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
2915 PangoLayout
*layout
= pango_layout_new(context
);
2916 pango_layout_set_font_description(layout
, desc
);
2918 const wxCharBuffer data
= wxGTK_CONV( string
);
2920 pango_layout_set_text(layout
, data
, strlen(data
));
2923 PangoRectangle rect
;
2924 pango_layout_get_extents(layout
, NULL
, &rect
);
2926 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
2927 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
2930 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
2931 int baseline
= pango_layout_iter_get_baseline(iter
);
2932 pango_layout_iter_free(iter
);
2933 *descent
= *y
- PANGO_PIXELS(baseline
);
2935 if (externalLeading
) (*externalLeading
) = 0; // ??
2937 g_object_unref (layout
);
2940 void wxWindowGTK
::GTKDisableFocusOutEvent()
2942 g_signal_handlers_block_by_func( m_focusWidget
,
2943 (gpointer
) gtk_window_focus_out_callback
, this);
2946 void wxWindowGTK
::GTKEnableFocusOutEvent()
2948 g_signal_handlers_unblock_by_func( m_focusWidget
,
2949 (gpointer
) gtk_window_focus_out_callback
, this);
2952 bool wxWindowGTK
::GTKHandleFocusIn()
2954 // Disable default focus handling for custom windows since the default GTK+
2955 // handler issues a repaint
2956 const bool retval
= m_wxwindow ?
true : false;
2959 // NB: if there's still unprocessed deferred focus-out event (see
2960 // GTKHandleFocusOut() for explanation), we need to process it first so
2961 // that the order of focus events -- focus-out first, then focus-in
2962 // elsewhere -- is preserved
2963 if ( gs_deferredFocusOut
)
2965 if ( GTKNeedsToFilterSameWindowFocus() &&
2966 gs_deferredFocusOut
== this )
2968 // GTK+ focus changed from this wxWindow back to itself, so don't
2969 // emit any events at all
2970 wxLogTrace(TRACE_FOCUS
,
2971 "filtered out spurious focus change within %s(%p, %s)",
2972 GetClassInfo()->GetClassName(), this, GetLabel());
2973 gs_deferredFocusOut
= NULL
;
2977 // otherwise we need to send focus-out first
2978 wxASSERT_MSG ( gs_deferredFocusOut
!= this,
2979 "GTKHandleFocusIn(GTKFocus_Normal) called even though focus changed back to itself - derived class should handle this" );
2980 GTKHandleDeferredFocusOut();
2984 wxLogTrace(TRACE_FOCUS
,
2985 "handling focus_in event for %s(%p, %s)",
2986 GetClassInfo()->GetClassName(), this, GetLabel());
2989 gtk_im_context_focus_in(m_imData
->context
);
2991 gs_currentFocus
= this;
2992 gs_pendingFocus
= NULL
;
2995 // caret needs to be informed about focus change
2996 wxCaret
*caret
= GetCaret();
2999 caret
->OnSetFocus();
3001 #endif // wxUSE_CARET
3003 // Notify the parent keeping track of focus for the kbd navigation
3004 // purposes that we got it.
3005 wxChildFocusEvent
eventChildFocus(static_cast<wxWindow
*>(this));
3006 GTKProcessEvent(eventChildFocus
);
3008 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, GetId());
3009 eventFocus
.SetEventObject(this);
3010 GTKProcessEvent(eventFocus
);
3015 bool wxWindowGTK
::GTKHandleFocusOut()
3017 // Disable default focus handling for custom windows since the default GTK+
3018 // handler issues a repaint
3019 const bool retval
= m_wxwindow ?
true : false;
3022 // NB: If a control is composed of several GtkWidgets and when focus
3023 // changes from one of them to another within the same wxWindow, we get
3024 // a focus-out event followed by focus-in for another GtkWidget owned
3025 // by the same wx control. We don't want to generate two spurious
3026 // wxEVT_SET_FOCUS events in this case, so we defer sending wx events
3027 // from GTKHandleFocusOut() until we know for sure it's not coming back
3028 // (i.e. in GTKHandleFocusIn() or at idle time).
3029 if ( GTKNeedsToFilterSameWindowFocus() )
3031 wxASSERT_MSG( gs_deferredFocusOut
== NULL
,
3032 "deferred focus out event already pending" );
3033 wxLogTrace(TRACE_FOCUS
,
3034 "deferring focus_out event for %s(%p, %s)",
3035 GetClassInfo()->GetClassName(), this, GetLabel());
3036 gs_deferredFocusOut
= this;
3040 GTKHandleFocusOutNoDeferring();
3045 void wxWindowGTK
::GTKHandleFocusOutNoDeferring()
3047 wxLogTrace(TRACE_FOCUS
,
3048 "handling focus_out event for %s(%p, %s)",
3049 GetClassInfo()->GetClassName(), this, GetLabel());
3052 gtk_im_context_focus_out(m_imData
->context
);
3054 if ( gs_currentFocus
!= this )
3056 // Something is terribly wrong, gs_currentFocus is out of sync with the
3057 // real focus. We will reset it to NULL anyway, because after this
3058 // focus-out event is handled, one of the following with happen:
3060 // * either focus will go out of the app altogether, in which case
3061 // gs_currentFocus _should_ be NULL
3063 // * or it goes to another control, in which case focus-in event will
3064 // follow immediately and it will set gs_currentFocus to the right
3066 wxLogDebug("window %s(%p, %s) lost focus even though it didn't have it",
3067 GetClassInfo()->GetClassName(), this, GetLabel());
3069 gs_currentFocus
= NULL
;
3072 // caret needs to be informed about focus change
3073 wxCaret
*caret
= GetCaret();
3076 caret
->OnKillFocus();
3078 #endif // wxUSE_CARET
3080 wxFocusEvent
event( wxEVT_KILL_FOCUS
, GetId() );
3081 event
.SetEventObject( this );
3082 GTKProcessEvent( event
);
3086 void wxWindowGTK
::GTKHandleDeferredFocusOut()
3088 // NB: See GTKHandleFocusOut() for explanation. This function is called
3089 // from either GTKHandleFocusIn() or OnInternalIdle() to process
3091 if ( gs_deferredFocusOut
)
3093 wxWindowGTK
*win
= gs_deferredFocusOut
;
3094 gs_deferredFocusOut
= NULL
;
3096 wxLogTrace(TRACE_FOCUS
,
3097 "processing deferred focus_out event for %s(%p, %s)",
3098 win
->GetClassInfo()->GetClassName(), win
, win
->GetLabel());
3100 win
->GTKHandleFocusOutNoDeferring();
3104 void wxWindowGTK
::SetFocus()
3106 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3108 // Setting "physical" focus is not immediate in GTK+ and while
3109 // gtk_widget_is_focus ("determines if the widget is the focus widget
3110 // within its toplevel", i.e. returns true for one widget per TLW, not
3111 // globally) returns true immediately after grabbing focus,
3112 // GTK_WIDGET_HAS_FOCUS (which returns true only for the one widget that
3113 // has focus at the moment) takes affect only after the window is shown
3114 // (if it was hidden at the moment of the call) or at the next event loop
3117 // Because we want to FindFocus() call immediately following
3118 // foo->SetFocus() to return foo, we have to keep track of "pending" focus
3120 gs_pendingFocus
= this;
3122 GtkWidget
*widget
= m_wxwindow ? m_wxwindow
: m_focusWidget
;
3124 if ( GTK_IS_CONTAINER(widget
) &&
3125 !GTK_WIDGET_CAN_FOCUS(widget
) )
3127 wxLogTrace(TRACE_FOCUS
,
3128 wxT("Setting focus to a child of %s(%p, %s)"),
3129 GetClassInfo()->GetClassName(), this, GetLabel().c_str());
3130 gtk_widget_child_focus(widget
, GTK_DIR_TAB_FORWARD
);
3134 wxLogTrace(TRACE_FOCUS
,
3135 wxT("Setting focus to %s(%p, %s)"),
3136 GetClassInfo()->GetClassName(), this, GetLabel().c_str());
3137 gtk_widget_grab_focus(widget
);
3141 void wxWindowGTK
::SetCanFocus(bool canFocus
)
3144 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3146 GTK_WIDGET_UNSET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3148 if ( m_wxwindow
&& (m_widget
!= m_wxwindow
) )
3151 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3153 GTK_WIDGET_UNSET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3157 bool wxWindowGTK
::Reparent( wxWindowBase
*newParentBase
)
3159 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3161 wxWindowGTK
*oldParent
= m_parent
,
3162 *newParent
= (wxWindowGTK
*)newParentBase
;
3164 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3166 if ( !wxWindowBase
::Reparent(newParent
) )
3169 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3172 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3174 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3178 if (GTK_WIDGET_VISIBLE (newParent
->m_widget
))
3180 m_showOnIdle
= true;
3181 gtk_widget_hide( m_widget
);
3183 /* insert GTK representation */
3184 newParent
->AddChildGTK(this);
3187 SetLayoutDirection(wxLayout_Default
);
3192 void wxWindowGTK
::DoAddChild(wxWindowGTK
*child
)
3194 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3195 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3200 /* insert GTK representation */
3204 void wxWindowGTK
::AddChild(wxWindowBase
*child
)
3206 wxWindowBase
::AddChild(child
);
3207 m_dirtyTabOrder
= true;
3208 wxTheApp
->WakeUpIdle();
3211 void wxWindowGTK
::RemoveChild(wxWindowBase
*child
)
3213 wxWindowBase
::RemoveChild(child
);
3214 m_dirtyTabOrder
= true;
3215 wxTheApp
->WakeUpIdle();
3219 wxLayoutDirection wxWindowGTK
::GTKGetLayout(GtkWidget
*widget
)
3221 return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
3222 ? wxLayout_RightToLeft
3223 : wxLayout_LeftToRight
;
3227 void wxWindowGTK
::GTKSetLayout(GtkWidget
*widget
, wxLayoutDirection dir
)
3229 wxASSERT_MSG( dir
!= wxLayout_Default
, wxT("invalid layout direction") );
3231 gtk_widget_set_direction(widget
,
3232 dir
== wxLayout_RightToLeft ? GTK_TEXT_DIR_RTL
3233 : GTK_TEXT_DIR_LTR
);
3236 wxLayoutDirection wxWindowGTK
::GetLayoutDirection() const
3238 return GTKGetLayout(m_widget
);
3241 void wxWindowGTK
::SetLayoutDirection(wxLayoutDirection dir
)
3243 if ( dir
== wxLayout_Default
)
3245 const wxWindow
*const parent
= GetParent();
3248 // inherit layout from parent.
3249 dir
= parent
->GetLayoutDirection();
3251 else // no parent, use global default layout
3253 dir
= wxTheApp
->GetLayoutDirection();
3257 if ( dir
== wxLayout_Default
)
3260 GTKSetLayout(m_widget
, dir
);
3262 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3263 GTKSetLayout(m_wxwindow
, dir
);
3267 wxWindowGTK
::AdjustForLayoutDirection(wxCoord x
,
3268 wxCoord
WXUNUSED(width
),
3269 wxCoord
WXUNUSED(widthTotal
)) const
3271 // We now mirror the coordinates of RTL windows in wxPizza
3275 void wxWindowGTK
::DoMoveInTabOrder(wxWindow
*win
, WindowOrder move
)
3277 wxWindowBase
::DoMoveInTabOrder(win
, move
);
3278 m_dirtyTabOrder
= true;
3279 wxTheApp
->WakeUpIdle();
3282 bool wxWindowGTK
::DoNavigateIn(int flags
)
3284 if ( flags
& wxNavigationKeyEvent
::WinChange
)
3286 wxFAIL_MSG( wxT("not implemented") );
3290 else // navigate inside the container
3292 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3293 wxCHECK_MSG( parent
, false, wxT("every window must have a TLW parent") );
3295 GtkDirectionType dir
;
3296 dir
= flags
& wxNavigationKeyEvent
::IsForward ? GTK_DIR_TAB_FORWARD
3297 : GTK_DIR_TAB_BACKWARD
;
3300 g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
);
3306 bool wxWindowGTK
::GTKWidgetNeedsMnemonic() const
3308 // none needed by default
3312 void wxWindowGTK
::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3314 // nothing to do by default since none is needed
3317 void wxWindowGTK
::RealizeTabOrder()
3321 if ( !m_children
.empty() )
3323 // we don't only construct the correct focus chain but also use
3324 // this opportunity to update the mnemonic widgets for the widgets
3327 GList
*chain
= NULL
;
3328 wxWindowGTK
* mnemonicWindow
= NULL
;
3330 for ( wxWindowList
::const_iterator i
= m_children
.begin();
3331 i
!= m_children
.end();
3334 wxWindowGTK
*win
= *i
;
3336 if ( mnemonicWindow
)
3338 if ( win
->AcceptsFocusFromKeyboard() )
3340 // wxComboBox et al. needs to focus on on a different
3341 // widget than m_widget, so if the main widget isn't
3342 // focusable try the connect widget
3343 GtkWidget
* w
= win
->m_widget
;
3344 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3346 w
= win
->GetConnectWidget();
3347 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3353 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3354 mnemonicWindow
= NULL
;
3358 else if ( win
->GTKWidgetNeedsMnemonic() )
3360 mnemonicWindow
= win
;
3363 chain
= g_list_prepend(chain
, win
->m_widget
);
3366 chain
= g_list_reverse(chain
);
3368 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3373 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3378 void wxWindowGTK
::Raise()
3380 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3382 if (m_wxwindow
&& m_wxwindow
->window
)
3384 gdk_window_raise( m_wxwindow
->window
);
3386 else if (m_widget
->window
)
3388 gdk_window_raise( m_widget
->window
);
3392 void wxWindowGTK
::Lower()
3394 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3396 if (m_wxwindow
&& m_wxwindow
->window
)
3398 gdk_window_lower( m_wxwindow
->window
);
3400 else if (m_widget
->window
)
3402 gdk_window_lower( m_widget
->window
);
3406 bool wxWindowGTK
::SetCursor( const wxCursor
&cursor
)
3408 if ( !wxWindowBase
::SetCursor(cursor
.Ok() ? cursor
: *wxSTANDARD_CURSOR
) )
3416 void wxWindowGTK
::GTKUpdateCursor(bool update_self
/*=true*/, bool recurse
/*=true*/)
3420 wxCursor
cursor(g_globalCursor
.Ok() ? g_globalCursor
: GetCursor());
3423 wxArrayGdkWindows windowsThis
;
3424 GdkWindow
* window
= GTKGetWindow(windowsThis
);
3426 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3429 const size_t count
= windowsThis
.size();
3430 for ( size_t n
= 0; n
< count
; n
++ )
3432 GdkWindow
*win
= windowsThis
[n
];
3433 // It can be zero if the window has not been realized yet.
3436 gdk_window_set_cursor(win
, cursor
.GetCursor());
3445 for (wxWindowList
::iterator it
= GetChildren().begin(); it
!= GetChildren().end(); ++it
)
3447 (*it
)->GTKUpdateCursor( true );
3452 void wxWindowGTK
::WarpPointer( int x
, int y
)
3454 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3456 // We provide this function ourselves as it is
3457 // missing in GDK (top of this file).
3459 GdkWindow
*window
= NULL
;
3461 window
= m_wxwindow
->window
;
3463 window
= GetConnectWidget()->window
;
3466 gdk_window_warp_pointer( window
, x
, y
);
3469 wxWindowGTK
::ScrollDir wxWindowGTK
::ScrollDirFromRange(GtkRange
*range
) const
3471 // find the scrollbar which generated the event
3472 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3474 if ( range
== m_scrollBar
[dir
] )
3475 return (ScrollDir
)dir
;
3478 wxFAIL_MSG( wxT("event from unknown scrollbar received") );
3480 return ScrollDir_Max
;
3483 bool wxWindowGTK
::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3485 bool changed
= false;
3486 GtkRange
* range
= m_scrollBar
[dir
];
3487 if ( range
&& units
)
3489 GtkAdjustment
* adj
= range
->adjustment
;
3490 gdouble inc
= unit
== ScrollUnit_Line ? adj
->step_increment
3491 : adj
->page_increment
;
3493 const int posOld
= int(adj
->value
+ 0.5);
3494 gtk_range_set_value(range
, posOld
+ units
*inc
);
3496 changed
= int(adj
->value
+ 0.5) != posOld
;
3502 bool wxWindowGTK
::ScrollLines(int lines
)
3504 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3507 bool wxWindowGTK
::ScrollPages(int pages
)
3509 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3512 void wxWindowGTK
::Refresh(bool WXUNUSED(eraseBackground
),
3517 // it is valid to call Refresh() for a window which hasn't been created
3518 // yet, it simply doesn't do anything in this case
3525 gtk_widget_queue_draw_area( m_widget
, rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3527 gtk_widget_queue_draw( m_widget
);
3531 // Just return if the widget or one of its ancestors isn't mapped
3533 for (w
= m_wxwindow
; w
!= NULL
; w
= w
->parent
)
3534 if (!GTK_WIDGET_MAPPED (w
))
3537 GdkWindow
* window
= GTKGetDrawingWindow();
3541 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3542 x
= GetClientSize().x
- x
- rect
->width
;
3546 r
.width
= rect
->width
;
3547 r
.height
= rect
->height
;
3548 gdk_window_invalidate_rect(window
, &r
, true);
3551 gdk_window_invalidate_rect(window
, NULL
, true);
3555 void wxWindowGTK
::Update()
3557 if (m_widget
&& GTK_WIDGET_MAPPED(m_widget
))
3559 GdkDisplay
* display
= gtk_widget_get_display(m_widget
);
3560 // Flush everything out to the server, and wait for it to finish.
3561 // This ensures nothing will overwrite the drawing we are about to do.
3562 gdk_display_sync(display
);
3564 GdkWindow
* window
= GTKGetDrawingWindow();
3566 window
= m_widget
->window
;
3567 gdk_window_process_updates(window
, true);
3569 // Flush again, but no need to wait for it to finish
3570 gdk_display_flush(display
);
3574 bool wxWindowGTK
::DoIsExposed( int x
, int y
) const
3576 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
3579 bool wxWindowGTK
::DoIsExposed( int x
, int y
, int w
, int h
) const
3581 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3582 return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
;
3584 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
3587 void wxWindowGTK
::GtkSendPaintEvents()
3591 m_updateRegion
.Clear();
3595 // Clip to paint region in wxClientDC
3596 m_clipPaintRegion
= true;
3598 m_nativeUpdateRegion
= m_updateRegion
;
3600 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3602 // Transform m_updateRegion under RTL
3603 m_updateRegion
.Clear();
3606 gdk_drawable_get_size(m_wxwindow
->window
, &width
, NULL
);
3608 wxRegionIterator
upd( m_nativeUpdateRegion
);
3612 rect
.x
= upd
.GetX();
3613 rect
.y
= upd
.GetY();
3614 rect
.width
= upd
.GetWidth();
3615 rect
.height
= upd
.GetHeight();
3617 rect
.x
= width
- rect
.x
- rect
.width
;
3618 m_updateRegion
.Union( rect
);
3624 switch ( GetBackgroundStyle() )
3626 case wxBG_STYLE_ERASE
:
3628 wxWindowDC
dc( (wxWindow
*)this );
3629 dc
.SetDeviceClippingRegion( m_updateRegion
);
3631 // Work around gtk-qt <= 0.60 bug whereby the window colour
3635 GetOptionInt("gtk.window.force-background-colour") )
3637 dc
.SetBackground(GetBackgroundColour());
3641 wxEraseEvent
erase_event( GetId(), &dc
);
3642 erase_event
.SetEventObject( this );
3644 if ( HandleWindowEvent(erase_event
) )
3646 // background erased, don't do it again
3652 case wxBG_STYLE_SYSTEM
:
3653 if ( GetThemeEnabled() )
3655 // find ancestor from which to steal background
3656 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3658 parent
= (wxWindow
*)this;
3660 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3662 wxRegionIterator
upd( m_nativeUpdateRegion
);
3666 rect
.x
= upd
.GetX();
3667 rect
.y
= upd
.GetY();
3668 rect
.width
= upd
.GetWidth();
3669 rect
.height
= upd
.GetHeight();
3671 gtk_paint_flat_box( parent
->m_widget
->style
,
3672 GTKGetDrawingWindow(),
3673 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3686 case wxBG_STYLE_PAINT
:
3687 // nothing to do: window will be painted over in EVT_PAINT
3691 wxFAIL_MSG( "unsupported background style" );
3694 wxNcPaintEvent
nc_paint_event( GetId() );
3695 nc_paint_event
.SetEventObject( this );
3696 HandleWindowEvent( nc_paint_event
);
3698 wxPaintEvent
paint_event( GetId() );
3699 paint_event
.SetEventObject( this );
3700 HandleWindowEvent( paint_event
);
3702 m_clipPaintRegion
= false;
3704 m_updateRegion
.Clear();
3705 m_nativeUpdateRegion
.Clear();
3708 void wxWindowGTK
::SetDoubleBuffered( bool on
)
3710 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3713 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3716 bool wxWindowGTK
::IsDoubleBuffered() const
3718 return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow
);
3721 void wxWindowGTK
::ClearBackground()
3723 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3727 void wxWindowGTK
::DoSetToolTip( wxToolTip
*tip
)
3729 wxWindowBase
::DoSetToolTip(tip
);
3733 m_tooltip
->GTKApply( (wxWindow
*)this );
3737 GtkWidget
*w
= GetConnectWidget();
3738 wxToolTip
::GTKApply(w
, NULL
);
3739 #if GTK_CHECK_VERSION(2, 12, 0)
3740 // Just applying NULL doesn't work on 2.12.0, so also use
3741 // gtk_widget_set_has_tooltip. It is part of the new GtkTooltip API
3742 // but seems also to work with the old GtkTooltips.
3743 if (gtk_check_version(2, 12, 0) == NULL
)
3744 gtk_widget_set_has_tooltip(w
, FALSE
);
3749 void wxWindowGTK
::GTKApplyToolTip( GtkTooltips
*tips
, const gchar
*tip
)
3751 gtk_tooltips_set_tip(tips
, GetConnectWidget(), tip
, NULL
);
3753 #endif // wxUSE_TOOLTIPS
3755 bool wxWindowGTK
::SetBackgroundColour( const wxColour
&colour
)
3757 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3759 if (!wxWindowBase
::SetBackgroundColour(colour
))
3764 // We need the pixel value e.g. for background clearing.
3765 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3768 // apply style change (forceStyle=true so that new style is applied
3769 // even if the bg colour changed from valid to wxNullColour)
3770 GTKApplyWidgetStyle(true);
3775 bool wxWindowGTK
::SetForegroundColour( const wxColour
&colour
)
3777 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3779 if (!wxWindowBase
::SetForegroundColour(colour
))
3786 // We need the pixel value e.g. for background clearing.
3787 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3790 // apply style change (forceStyle=true so that new style is applied
3791 // even if the bg colour changed from valid to wxNullColour):
3792 GTKApplyWidgetStyle(true);
3797 PangoContext
*wxWindowGTK
::GTKGetPangoDefaultContext()
3799 return gtk_widget_get_pango_context( m_widget
);
3802 GtkRcStyle
*wxWindowGTK
::GTKCreateWidgetStyle(bool forceStyle
)
3804 // do we need to apply any changes at all?
3807 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3812 GtkRcStyle
*style
= gtk_rc_style_new();
3817 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3820 int flagsNormal
= 0,
3823 flagsInsensitive
= 0;
3825 if ( m_foregroundColour
.Ok() )
3827 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3829 style
->fg
[GTK_STATE_NORMAL
] =
3830 style
->text
[GTK_STATE_NORMAL
] = *fg
;
3831 flagsNormal
|= GTK_RC_FG
| GTK_RC_TEXT
;
3833 style
->fg
[GTK_STATE_PRELIGHT
] =
3834 style
->text
[GTK_STATE_PRELIGHT
] = *fg
;
3835 flagsPrelight
|= GTK_RC_FG
| GTK_RC_TEXT
;
3837 style
->fg
[GTK_STATE_ACTIVE
] =
3838 style
->text
[GTK_STATE_ACTIVE
] = *fg
;
3839 flagsActive
|= GTK_RC_FG
| GTK_RC_TEXT
;
3842 if ( m_backgroundColour
.Ok() )
3844 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3846 style
->bg
[GTK_STATE_NORMAL
] =
3847 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3848 flagsNormal
|= GTK_RC_BG
| GTK_RC_BASE
;
3850 style
->bg
[GTK_STATE_PRELIGHT
] =
3851 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3852 flagsPrelight
|= GTK_RC_BG
| GTK_RC_BASE
;
3854 style
->bg
[GTK_STATE_ACTIVE
] =
3855 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3856 flagsActive
|= GTK_RC_BG
| GTK_RC_BASE
;
3858 style
->bg
[GTK_STATE_INSENSITIVE
] =
3859 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3860 flagsInsensitive
|= GTK_RC_BG
| GTK_RC_BASE
;
3863 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
;
3864 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
;
3865 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
;
3866 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
;
3871 void wxWindowGTK
::GTKApplyWidgetStyle(bool forceStyle
)
3873 GtkRcStyle
*style
= GTKCreateWidgetStyle(forceStyle
);
3876 DoApplyWidgetStyle(style
);
3877 gtk_rc_style_unref(style
);
3880 // Style change may affect GTK+'s size calculation:
3881 InvalidateBestSize();
3884 void wxWindowGTK
::DoApplyWidgetStyle(GtkRcStyle
*style
)
3888 // block the signal temporarily to avoid sending
3889 // wxSysColourChangedEvents when we change the colours ourselves
3890 bool unblock
= false;
3894 g_signal_handlers_block_by_func(
3895 m_wxwindow
, (void *)gtk_window_style_set_callback
, this);
3898 gtk_widget_modify_style(m_wxwindow
, style
);
3902 g_signal_handlers_unblock_by_func(
3903 m_wxwindow
, (void *)gtk_window_style_set_callback
, this);
3908 gtk_widget_modify_style(m_widget
, style
);
3912 bool wxWindowGTK
::SetBackgroundStyle(wxBackgroundStyle style
)
3914 wxWindowBase
::SetBackgroundStyle(style
);
3916 if ( style
== wxBG_STYLE_PAINT
)
3921 window
= GTKGetDrawingWindow();
3925 GtkWidget
* const w
= GetConnectWidget();
3926 window
= w ? w
->window
: NULL
;
3931 // Make sure GDK/X11 doesn't refresh the window
3933 gdk_window_set_back_pixmap( window
, None
, False
);
3935 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3938 m_needsStyleChange
= false;
3940 else // window not realized yet
3942 // Do in OnIdle, because the window is not yet available
3943 m_needsStyleChange
= true;
3946 // Don't apply widget style, or we get a grey background
3950 // apply style change (forceStyle=true so that new style is applied
3951 // even if the bg colour changed from valid to wxNullColour):
3952 GTKApplyWidgetStyle(true);
3958 // ----------------------------------------------------------------------------
3959 // Pop-up menu stuff
3960 // ----------------------------------------------------------------------------
3962 #if wxUSE_MENUS_NATIVE
3966 void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3968 gboolean
* WXUNUSED(whatever
),
3969 gpointer user_data
)
3971 // ensure that the menu appears entirely on screen
3973 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3975 wxSize sizeScreen
= wxGetDisplaySize();
3976 wxPoint
*pos
= (wxPoint
*)user_data
;
3978 gint xmax
= sizeScreen
.x
- req
.width
,
3979 ymax
= sizeScreen
.y
- req
.height
;
3981 *x
= pos
->x
< xmax ? pos
->x
: xmax
;
3982 *y
= pos
->y
< ymax ? pos
->y
: ymax
;
3986 bool wxWindowGTK
::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3988 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3994 GtkMenuPositionFunc posfunc
;
3995 if ( x
== -1 && y
== -1 )
3997 // use GTK's default positioning algorithm
4003 pos
= ClientToScreen(wxPoint(x
, y
));
4005 posfunc
= wxPopupMenuPositionCallback
;
4008 menu
->m_popupShown
= true;
4010 GTK_MENU(menu
->m_menu
),
4011 NULL
, // parent menu shell
4012 NULL
, // parent menu item
4013 posfunc
, // function to position it
4014 userdata
, // client data
4015 0, // button used to activate it
4016 gtk_get_current_event_time()
4019 while (menu
->m_popupShown
)
4021 gtk_main_iteration();
4027 #endif // wxUSE_MENUS_NATIVE
4029 #if wxUSE_DRAG_AND_DROP
4031 void wxWindowGTK
::SetDropTarget( wxDropTarget
*dropTarget
)
4033 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4035 GtkWidget
*dnd_widget
= GetConnectWidget();
4037 if (m_dropTarget
) m_dropTarget
->GtkUnregisterWidget( dnd_widget
);
4039 if (m_dropTarget
) delete m_dropTarget
;
4040 m_dropTarget
= dropTarget
;
4042 if (m_dropTarget
) m_dropTarget
->GtkRegisterWidget( dnd_widget
);
4045 #endif // wxUSE_DRAG_AND_DROP
4047 GtkWidget
* wxWindowGTK
::GetConnectWidget()
4049 GtkWidget
*connect_widget
= m_widget
;
4050 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4052 return connect_widget
;
4055 bool wxWindowGTK
::GTKIsOwnWindow(GdkWindow
*window
) const
4057 wxArrayGdkWindows windowsThis
;
4058 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
4060 return winThis ? window
== winThis
4061 : windowsThis
.Index(window
) != wxNOT_FOUND
;
4064 GdkWindow
*wxWindowGTK
::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
4066 return m_wxwindow ?
GTKGetDrawingWindow() : m_widget
->window
;
4069 bool wxWindowGTK
::SetFont( const wxFont
&font
)
4071 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4073 if (!wxWindowBase
::SetFont(font
))
4076 // apply style change (forceStyle=true so that new style is applied
4077 // even if the font changed from valid to wxNullFont):
4078 GTKApplyWidgetStyle(true);
4083 void wxWindowGTK
::DoCaptureMouse()
4085 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4087 GdkWindow
*window
= NULL
;
4089 window
= GTKGetDrawingWindow();
4091 window
= GetConnectWidget()->window
;
4093 wxCHECK_RET( window
, wxT("CaptureMouse() failed") );
4095 const wxCursor
* cursor
= &m_cursor
;
4097 cursor
= wxSTANDARD_CURSOR
;
4099 gdk_pointer_grab( window
, FALSE
,
4101 (GDK_BUTTON_PRESS_MASK
|
4102 GDK_BUTTON_RELEASE_MASK
|
4103 GDK_POINTER_MOTION_HINT_MASK
|
4104 GDK_POINTER_MOTION_MASK
),
4106 cursor
->GetCursor(),
4107 (guint32
)GDK_CURRENT_TIME
);
4108 g_captureWindow
= this;
4109 g_captureWindowHasMouse
= true;
4112 void wxWindowGTK
::DoReleaseMouse()
4114 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4116 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4118 g_captureWindow
= NULL
;
4120 GdkWindow
*window
= NULL
;
4122 window
= GTKGetDrawingWindow();
4124 window
= GetConnectWidget()->window
;
4129 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4132 void wxWindowGTK
::GTKReleaseMouseAndNotify()
4135 wxMouseCaptureLostEvent
evt(GetId());
4136 evt
.SetEventObject( this );
4137 HandleWindowEvent( evt
);
4141 wxWindow
*wxWindowBase
::GetCapture()
4143 return (wxWindow
*)g_captureWindow
;
4146 bool wxWindowGTK
::IsRetained() const
4151 void wxWindowGTK
::SetScrollbar(int orient
,
4155 bool WXUNUSED(update
))
4157 const int dir
= ScrollDirFromOrient(orient
);
4158 GtkRange
* const sb
= m_scrollBar
[dir
];
4159 wxCHECK_RET( sb
, wxT("this window is not scrollable") );
4163 // GtkRange requires upper > lower
4168 GtkAdjustment
* const adj
= sb
->adjustment
;
4169 adj
->step_increment
= 1;
4170 adj
->page_increment
=
4171 adj
->page_size
= thumbVisible
;
4174 g_signal_handlers_block_by_func(
4175 sb
, (void*)gtk_scrollbar_value_changed
, this);
4177 gtk_range_set_range(sb
, 0, range
);
4178 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4180 g_signal_handlers_unblock_by_func(
4181 sb
, (void*)gtk_scrollbar_value_changed
, this);
4184 void wxWindowGTK
::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4186 const int dir
= ScrollDirFromOrient(orient
);
4187 GtkRange
* const sb
= m_scrollBar
[dir
];
4188 wxCHECK_RET( sb
, wxT("this window is not scrollable") );
4190 // This check is more than an optimization. Without it, the slider
4191 // will not move smoothly while tracking when using wxScrollHelper.
4192 if (GetScrollPos(orient
) != pos
)
4194 g_signal_handlers_block_by_func(
4195 sb
, (void*)gtk_scrollbar_value_changed
, this);
4197 gtk_range_set_value(sb
, pos
);
4198 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4200 g_signal_handlers_unblock_by_func(
4201 sb
, (void*)gtk_scrollbar_value_changed
, this);
4205 int wxWindowGTK
::GetScrollThumb(int orient
) const
4207 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4208 wxCHECK_MSG( sb
, 0, wxT("this window is not scrollable") );
4210 return wxRound(sb
->adjustment
->page_size
);
4213 int wxWindowGTK
::GetScrollPos( int orient
) const
4215 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4216 wxCHECK_MSG( sb
, 0, wxT("this window is not scrollable") );
4218 return wxRound(sb
->adjustment
->value
);
4221 int wxWindowGTK
::GetScrollRange( int orient
) const
4223 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4224 wxCHECK_MSG( sb
, 0, wxT("this window is not scrollable") );
4226 return wxRound(sb
->adjustment
->upper
);
4229 // Determine if increment is the same as +/-x, allowing for some small
4230 // difference due to possible inexactness in floating point arithmetic
4231 static inline bool IsScrollIncrement(double increment
, double x
)
4233 wxASSERT(increment
> 0);
4234 const double tolerance
= 1.0 / 1024;
4235 return fabs(increment
- fabs(x
)) < tolerance
;
4238 wxEventType wxWindowGTK
::GTKGetScrollEventType(GtkRange
* range
)
4240 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4242 const int barIndex
= range
== m_scrollBar
[1];
4243 GtkAdjustment
* adj
= range
->adjustment
;
4245 const int value
= wxRound(adj
->value
);
4247 // save previous position
4248 const double oldPos
= m_scrollPos
[barIndex
];
4249 // update current position
4250 m_scrollPos
[barIndex
] = adj
->value
;
4251 // If event should be ignored, or integral position has not changed
4252 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== wxRound(oldPos
))
4257 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4260 // Difference from last change event
4261 const double diff
= adj
->value
- oldPos
;
4262 const bool isDown
= diff
> 0;
4264 if (IsScrollIncrement(adj
->step_increment
, diff
))
4266 eventType
= isDown ? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4268 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4270 eventType
= isDown ? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4272 else if (m_mouseButtonDown
)
4274 // Assume track event
4275 m_isScrolling
= true;
4281 void wxWindowGTK
::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4283 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4285 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4287 // No scrolling requested.
4288 if ((dx
== 0) && (dy
== 0)) return;
4290 m_clipPaintRegion
= true;
4292 WX_PIZZA(m_wxwindow
)->scroll(dx
, dy
);
4294 m_clipPaintRegion
= false;
4297 bool restoreCaret
= (GetCaret() != NULL
&& GetCaret()->IsVisible());
4300 wxRect
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4302 caretRect
.width
+= dx
;
4305 caretRect
.x
+= dx
; caretRect
.width
-= dx
;
4308 caretRect
.height
+= dy
;
4311 caretRect
.y
+= dy
; caretRect
.height
-= dy
;
4314 RefreshRect(caretRect
);
4316 #endif // wxUSE_CARET
4319 void wxWindowGTK
::GTKScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4321 //RN: Note that static controls usually have no border on gtk, so maybe
4322 //it makes sense to treat that as simply no border at the wx level
4324 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4326 GtkShadowType gtkstyle
;
4328 if(wxstyle
& wxBORDER_RAISED
)
4329 gtkstyle
= GTK_SHADOW_OUT
;
4330 else if ((wxstyle
& wxBORDER_SUNKEN
) || (wxstyle
& wxBORDER_THEME
))
4331 gtkstyle
= GTK_SHADOW_IN
;
4334 else if (wxstyle
& wxBORDER_DOUBLE
)
4335 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4338 gtkstyle
= GTK_SHADOW_IN
;
4340 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4345 void wxWindowGTK
::SetWindowStyleFlag( long style
)
4347 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4348 wxWindowBase
::SetWindowStyleFlag(style
);
4351 // Find the wxWindow at the current mouse position, also returning the mouse
4353 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4355 pt
= wxGetMousePosition();
4356 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4360 // Get the current mouse position.
4361 wxPoint
wxGetMousePosition()
4363 /* This crashes when used within wxHelpContext,
4364 so we have to use the X-specific implementation below.
4366 GdkModifierType *mask;
4367 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4369 return wxPoint(x, y);
4373 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4375 Display
*display
= windowAtPtr ?
GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4376 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4377 Window rootReturn
, childReturn
;
4378 int rootX
, rootY
, winX
, winY
;
4379 unsigned int maskReturn
;
4381 XQueryPointer (display
,
4385 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4386 return wxPoint(rootX
, rootY
);
4390 GdkWindow
* wxWindowGTK
::GTKGetDrawingWindow() const
4392 GdkWindow
* window
= NULL
;
4394 window
= m_wxwindow
->window
;
4398 // ----------------------------------------------------------------------------
4400 // ----------------------------------------------------------------------------
4405 // this is called if we attempted to freeze unrealized widget when it finally
4406 // is realized (and so can be frozen):
4407 static void wx_frozen_widget_realize(GtkWidget
* w
, wxWindowGTK
* win
)
4409 wxASSERT( w
&& !GTK_WIDGET_NO_WINDOW(w
) );
4410 wxASSERT( GTK_WIDGET_REALIZED(w
) );
4412 g_signal_handlers_disconnect_by_func
4415 (void*)wx_frozen_widget_realize
,
4419 GdkWindow
* window
= w
->window
;
4420 if (w
== win
->m_wxwindow
)
4421 window
= win
->GTKGetDrawingWindow();
4422 gdk_window_freeze_updates(window
);
4427 void wxWindowGTK
::GTKFreezeWidget(GtkWidget
*w
)
4429 if ( !w
|| GTK_WIDGET_NO_WINDOW(w
) )
4430 return; // window-less widget, cannot be frozen
4432 if ( !GTK_WIDGET_REALIZED(w
) )
4434 // we can't thaw unrealized widgets because they don't have GdkWindow,
4435 // so set it up to be done immediately after realization:
4436 g_signal_connect_after
4440 G_CALLBACK(wx_frozen_widget_realize
),
4446 GdkWindow
* window
= w
->window
;
4447 if (w
== m_wxwindow
)
4448 window
= GTKGetDrawingWindow();
4449 gdk_window_freeze_updates(window
);
4452 void wxWindowGTK
::GTKThawWidget(GtkWidget
*w
)
4454 if ( !w
|| GTK_WIDGET_NO_WINDOW(w
) )
4455 return; // window-less widget, cannot be frozen
4457 if ( !GTK_WIDGET_REALIZED(w
) )
4459 // the widget wasn't realized yet, no need to thaw
4460 g_signal_handlers_disconnect_by_func
4463 (void*)wx_frozen_widget_realize
,
4469 GdkWindow
* window
= w
->window
;
4470 if (w
== m_wxwindow
)
4471 window
= GTKGetDrawingWindow();
4472 gdk_window_thaw_updates(window
);
4475 void wxWindowGTK
::DoFreeze()
4477 GTKFreezeWidget(m_widget
);
4478 if ( m_wxwindow
&& m_widget
!= m_wxwindow
)
4479 GTKFreezeWidget(m_wxwindow
);
4482 void wxWindowGTK
::DoThaw()
4484 GTKThawWidget(m_widget
);
4485 if ( m_wxwindow
&& m_widget
!= m_wxwindow
)
4486 GTKThawWidget(m_wxwindow
);