1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
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 //-----------------------------------------------------------------------------
44 // documentation on internals
45 //-----------------------------------------------------------------------------
48 I have been asked several times about writing some documentation about
49 the GTK port of wxWidgets, especially its internal structures. Obviously,
50 you cannot understand wxGTK without knowing a little about the GTK, but
51 some more information about what the wxWindow, which is the base class
52 for all other window classes, does seems required as well.
56 What does wxWindow do? It contains the common interface for the following
57 jobs of its descendants:
59 1) Define the rudimentary behaviour common to all window classes, such as
60 resizing, intercepting user input (so as to make it possible to use these
61 events for special purposes in a derived class), window names etc.
63 2) Provide the possibility to contain and manage children, if the derived
64 class is allowed to contain children, which holds true for those window
65 classes which do not display a native GTK widget. To name them, these
66 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
67 work classes are a special case and are handled a bit differently from
68 the rest. The same holds true for the wxNotebook class.
70 3) Provide the possibility to draw into a client area of a window. This,
71 too, only holds true for classes that do not display a native GTK widget
74 4) Provide the entire mechanism for scrolling widgets. This actual inter-
75 face for this is usually in wxScrolledWindow, but the GTK implementation
78 5) A multitude of helper or extra methods for special purposes, such as
79 Drag'n'Drop, managing validators etc.
81 6) Display a border (sunken, raised, simple or none).
83 Normally one might expect, that one wxWidgets window would always correspond
84 to one GTK widget. Under GTK, there is no such all-round widget that has all
85 the functionality. Moreover, the GTK defines a client area as a different
86 widget from the actual widget you are handling. Last but not least some
87 special classes (e.g. wxFrame) handle different categories of widgets and
88 still have the possibility to draw something in the client area.
89 It was therefore required to write a special purpose GTK widget, that would
90 represent a client area in the sense of wxWidgets capable to do the jobs
91 2), 3) and 4). I have written this class and it resides in win_gtk.c of
94 All windows must have a widget, with which they interact with other under-
95 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
96 the wxWindow class has a member variable called m_widget which holds a
97 pointer to this widget. When the window class represents a GTK native widget,
98 this is (in most cases) the only GTK widget the class manages. E.g. the
99 wxStaticText class handles only a GtkLabel widget a pointer to which you
100 can find in m_widget (defined in wxWindow)
102 When the class has a client area for drawing into and for containing children
103 it has to handle the client area widget (of the type wxPizza, defined in
104 win_gtk.cpp), but there could be any number of widgets, handled by a class.
105 The common rule for all windows is only, that the widget that interacts with
106 the rest of GTK must be referenced in m_widget and all other widgets must be
107 children of this widget on the GTK level. The top-most widget, which also
108 represents the client area, must be in the m_wxwindow field and must be of
111 As I said, the window classes that display a GTK native widget only have
112 one widget, so in the case of e.g. the wxButton class m_widget holds a
113 pointer to a GtkButton widget. But windows with client areas (for drawing
114 and children) have a m_widget field that is a pointer to a GtkScrolled-
115 Window and a m_wxwindow field that is pointer to a wxPizza and this
116 one is (in the GTK sense) a child of the GtkScrolledWindow.
118 If the m_wxwindow field is set, then all input to this widget is inter-
119 cepted and sent to the wxWidgets class. If not, all input to the widget
120 that gets pointed to by m_widget gets intercepted and sent to the class.
124 The design of scrolling in wxWidgets is markedly different from that offered
125 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
126 clicking on a scrollbar belonging to scrolled window will inevitably move
127 the window. In wxWidgets, the scrollbar will only emit an event, send this
128 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
129 which actually moves the window and its sub-windows. Note that wxPizza
130 memorizes how much it has been scrolled but that wxWidgets forgets this
131 so that the two coordinates systems have to be kept in synch. This is done
132 in various places using the pizza->m_scroll_x and pizza->m_scroll_y values.
136 Singularly the most broken code in GTK is the code that is supposed to
137 inform subwindows (child windows) about new positions. Very often, duplicate
138 events are sent without changes in size or position, equally often no
139 events are sent at all (All this is due to a bug in the GtkContainer code
140 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
141 GTK's own system and it simply waits for size events for toplevel windows
142 and then iterates down the respective size events to all window. This has
143 the disadvantage that windows might get size events before the GTK widget
144 actually has the reported size. This doesn't normally pose any problem, but
145 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
146 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
147 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
148 window that is used for OpenGL output really has that size (as reported by
153 If someone at some point of time feels the immense desire to have a look at,
154 change or attempt to optimise the Refresh() logic, this person will need an
155 intimate understanding of what "draw" and "expose" events are and what
156 they are used for, in particular when used in connection with GTK's
157 own windowless widgets. Beware.
161 Cursors, too, have been a constant source of pleasure. The main difficulty
162 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
163 for the parent. To prevent this from doing too much harm, I use idle time
164 to set the cursor over and over again, starting from the toplevel windows
165 and ending with the youngest generation (speaking of parent and child windows).
166 Also don't forget that cursors (like much else) are connected to GdkWindows,
167 not GtkWidgets and that the "window" field of a GtkWidget might very well
168 point to the GdkWindow of the parent widget (-> "window-less widget") and
169 that the two obviously have very different meanings.
173 //-----------------------------------------------------------------------------
175 //-----------------------------------------------------------------------------
177 // Don't allow event propagation during drag
178 bool g_blockEventsOnDrag
;
179 // Don't allow mouse event propagation during scroll
180 bool g_blockEventsOnScroll
;
181 extern wxCursor g_globalCursor
;
183 // mouse capture state: the window which has it and if the mouse is currently
185 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
186 static bool g_captureWindowHasMouse
= false;
188 // The window that currently has focus:
189 static wxWindowGTK
*gs_currentFocus
= NULL
;
190 // The window that is scheduled to get focus in the next event loop iteration
191 // or NULL if there's no pending focus change:
192 static wxWindowGTK
*gs_pendingFocus
= NULL
;
194 // the window that has deferred focus-out event pending, if any (see
195 // GTKAddDeferredFocusOut() for details)
196 static wxWindowGTK
*gs_deferredFocusOut
= NULL
;
198 // global variables because GTK+ DnD want to have the
199 // mouse event that caused it
200 GdkEvent
*g_lastMouseEvent
= (GdkEvent
*) NULL
;
201 int g_lastButtonNumber
= 0;
203 //-----------------------------------------------------------------------------
205 //-----------------------------------------------------------------------------
207 // the trace mask used for the focus debugging messages
208 #define TRACE_FOCUS _T("focus")
210 //-----------------------------------------------------------------------------
211 // missing gdk functions
212 //-----------------------------------------------------------------------------
215 gdk_window_warp_pointer (GdkWindow
*window
,
220 window
= gdk_get_default_root_window();
222 if (!GDK_WINDOW_DESTROYED(window
))
224 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
225 None
, /* not source window -> move from anywhere */
226 GDK_WINDOW_XID(window
), /* dest window */
227 0, 0, 0, 0, /* not source window -> move from anywhere */
233 //-----------------------------------------------------------------------------
234 // "size_request" of m_widget
235 //-----------------------------------------------------------------------------
237 // make it extern because wxStaticText needs to disconnect this one
239 void wxgtk_window_size_request_callback(GtkWidget
* WXUNUSED(widget
),
240 GtkRequisition
*requisition
,
244 win
->GetSize( &w
, &h
);
250 requisition
->height
= h
;
251 requisition
->width
= w
;
255 //-----------------------------------------------------------------------------
256 // "expose_event" of m_wxwindow
257 //-----------------------------------------------------------------------------
261 gtk_window_expose_callback( GtkWidget
* widget
,
262 GdkEventExpose
*gdk_event
,
265 if (gdk_event
->window
== widget
->window
)
267 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
268 win
->GtkSendPaintEvents();
270 // Let parent window draw window-less widgets
275 //-----------------------------------------------------------------------------
276 // "expose_event" from m_widget, for drawing border
277 //-----------------------------------------------------------------------------
279 #ifndef __WXUNIVERSAL__
281 GtkWidget
* GetEntryWidget();
285 expose_event_border(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxWindow
* win
)
287 // if this event is not for the GdkWindow the border is drawn on
288 if (win
->m_wxwindow
== win
->m_widget
&& gdk_event
->window
== widget
->window
)
293 // GtkScrolledWindow is GTK_NO_WINDOW
294 if (GTK_WIDGET_NO_WINDOW(widget
))
296 x
= widget
->allocation
.x
;
297 y
= widget
->allocation
.y
;
299 int w
= win
->m_wxwindow
->allocation
.width
;
300 int h
= win
->m_wxwindow
->allocation
.height
;
301 if (win
->HasFlag(wxBORDER_SIMPLE
))
303 GdkGC
* gc
= gdk_gc_new(gdk_event
->window
);
304 gdk_gc_set_foreground(gc
, &widget
->style
->black
);
305 gdk_draw_rectangle(gdk_event
->window
, gc
, false, x
, y
, w
- 1, h
- 1);
310 GtkShadowType shadow
= GTK_SHADOW_IN
;
311 if (win
->HasFlag(wxBORDER_RAISED
))
312 shadow
= GTK_SHADOW_OUT
;
314 // Style detail to use
316 if (widget
== win
->m_wxwindow
)
317 // for non-scrollable wxWindows
320 // for scrollable ones
323 GtkWidget
* styleWidget
= GetEntryWidget();
325 styleWidget
->style
, gdk_event
->window
, GTK_STATE_NORMAL
,
326 shadow
, NULL
, styleWidget
, detail
, x
, y
, w
, h
);
329 // no further painting is needed for border-only GdkWindow
330 return win
->m_wxwindow
== win
->m_widget
;
333 #endif // !__WXUNIVERSAL__
335 //-----------------------------------------------------------------------------
336 // "key_press_event" from any window
337 //-----------------------------------------------------------------------------
339 // These are used when transforming Ctrl-alpha to ascii values 1-26
340 inline bool wxIsLowerChar(int code
)
342 return (code
>= 'a' && code
<= 'z' );
345 inline bool wxIsUpperChar(int code
)
347 return (code
>= 'A' && code
<= 'Z' );
351 // set WXTRACE to this to see the key event codes on the console
352 #define TRACE_KEYS _T("keyevent")
354 // translates an X key symbol to WXK_XXX value
356 // if isChar is true it means that the value returned will be used for EVT_CHAR
357 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
358 // for example, while if it is false it means that the value is going to be
359 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
361 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
367 // Shift, Control and Alt don't generate the CHAR events at all
370 key_code
= isChar
? 0 : WXK_SHIFT
;
374 key_code
= isChar
? 0 : WXK_CONTROL
;
382 key_code
= isChar
? 0 : WXK_ALT
;
385 // neither do the toggle modifies
386 case GDK_Scroll_Lock
:
387 key_code
= isChar
? 0 : WXK_SCROLL
;
391 key_code
= isChar
? 0 : WXK_CAPITAL
;
395 key_code
= isChar
? 0 : WXK_NUMLOCK
;
399 // various other special keys
412 case GDK_ISO_Left_Tab
:
419 key_code
= WXK_RETURN
;
423 key_code
= WXK_CLEAR
;
427 key_code
= WXK_PAUSE
;
431 key_code
= WXK_SELECT
;
435 key_code
= WXK_PRINT
;
439 key_code
= WXK_EXECUTE
;
443 key_code
= WXK_ESCAPE
;
446 // cursor and other extended keyboard keys
448 key_code
= WXK_DELETE
;
464 key_code
= WXK_RIGHT
;
471 case GDK_Prior
: // == GDK_Page_Up
472 key_code
= WXK_PAGEUP
;
475 case GDK_Next
: // == GDK_Page_Down
476 key_code
= WXK_PAGEDOWN
;
488 key_code
= WXK_INSERT
;
503 key_code
= (isChar
? '0' : int(WXK_NUMPAD0
)) + keysym
- GDK_KP_0
;
507 key_code
= isChar
? ' ' : int(WXK_NUMPAD_SPACE
);
511 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
515 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
519 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
523 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
527 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
531 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
535 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
539 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
543 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
547 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
551 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
554 case GDK_KP_Prior
: // == GDK_KP_Page_Up
555 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
558 case GDK_KP_Next
: // == GDK_KP_Page_Down
559 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
563 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
567 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
571 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
575 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
579 key_code
= isChar
? '=' : int(WXK_NUMPAD_EQUAL
);
582 case GDK_KP_Multiply
:
583 key_code
= isChar
? '*' : int(WXK_NUMPAD_MULTIPLY
);
587 key_code
= isChar
? '+' : int(WXK_NUMPAD_ADD
);
590 case GDK_KP_Separator
:
591 // FIXME: what is this?
592 key_code
= isChar
? '.' : int(WXK_NUMPAD_SEPARATOR
);
595 case GDK_KP_Subtract
:
596 key_code
= isChar
? '-' : int(WXK_NUMPAD_SUBTRACT
);
600 key_code
= isChar
? '.' : int(WXK_NUMPAD_DECIMAL
);
604 key_code
= isChar
? '/' : int(WXK_NUMPAD_DIVIDE
);
621 key_code
= WXK_F1
+ keysym
- GDK_F1
;
631 static inline bool wxIsAsciiKeysym(KeySym ks
)
636 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
638 GdkEventKey
*gdk_event
)
642 GdkModifierType state
;
643 if (gdk_event
->window
)
644 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
646 event
.SetTimestamp( gdk_event
->time
);
647 event
.SetId(win
->GetId());
648 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
649 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
650 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
651 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
652 event
.m_scanCode
= gdk_event
->keyval
;
653 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
654 event
.m_rawFlags
= 0;
656 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
658 wxGetMousePosition( &x
, &y
);
659 win
->ScreenToClient( &x
, &y
);
662 event
.SetEventObject( win
);
667 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
669 GdkEventKey
*gdk_event
)
671 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
672 // but only event->keyval which is quite useless to us, so remember
673 // the last character from GDK_KEY_PRESS and reuse it as last resort
675 // NB: should be MT-safe as we're always called from the main thread only
680 } s_lastKeyPress
= { 0, 0 };
682 KeySym keysym
= gdk_event
->keyval
;
684 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
685 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
689 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
693 // do we have the translation or is it a plain ASCII character?
694 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
696 // we should use keysym if it is ASCII as X does some translations
697 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
698 // which we don't want here (but which we do use for OnChar())
699 if ( !wxIsAsciiKeysym(keysym
) )
701 keysym
= (KeySym
)gdk_event
->string
[0];
704 // we want to always get the same key code when the same key is
705 // pressed regardless of the state of the modifiers, i.e. on a
706 // standard US keyboard pressing '5' or '%' ('5' key with
707 // Shift) should result in the same key code in OnKeyDown():
708 // '5' (although OnChar() will get either '5' or '%').
710 // to do it we first translate keysym to keycode (== scan code)
711 // and then back but always using the lower register
712 Display
*dpy
= (Display
*)wxGetDisplay();
713 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
715 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
717 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
719 // use the normalized, i.e. lower register, keysym if we've
721 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
723 // as explained above, we want to have lower register key codes
724 // normally but for the letter keys we want to have the upper ones
726 // NB: don't use XConvertCase() here, we want to do it for letters
728 key_code
= toupper(key_code
);
730 else // non ASCII key, what to do?
732 // by default, ignore it
735 // but if we have cached information from the last KEY_PRESS
736 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
739 if ( keysym
== s_lastKeyPress
.keysym
)
741 key_code
= s_lastKeyPress
.keycode
;
746 if ( gdk_event
->type
== GDK_KEY_PRESS
)
748 // remember it to be reused for KEY_UP event later
749 s_lastKeyPress
.keysym
= keysym
;
750 s_lastKeyPress
.keycode
= key_code
;
754 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
756 // sending unknown key events doesn't really make sense
760 // now fill all the other fields
761 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
763 event
.m_keyCode
= key_code
;
765 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
767 event
.m_uniChar
= key_code
;
777 GtkIMContext
*context
;
778 GdkEventKey
*lastKeyEvent
;
782 context
= gtk_im_multicontext_new();
787 g_object_unref (context
);
793 gtk_window_key_press_callback( GtkWidget
*widget
,
794 GdkEventKey
*gdk_event
,
799 if (g_blockEventsOnDrag
)
802 // GTK+ sends keypress events to the focus widget and then
803 // to all its parent and grandparent widget. We only want
804 // the key events from the focus widget.
805 if (!GTK_WIDGET_HAS_FOCUS(widget
))
808 wxKeyEvent
event( wxEVT_KEY_DOWN
);
810 bool return_after_IM
= false;
812 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
814 // Emit KEY_DOWN event
815 ret
= win
->HandleWindowEvent( event
);
819 // Return after IM processing as we cannot do
820 // anything with it anyhow.
821 return_after_IM
= true;
824 if ((!ret
) && (win
->m_imData
!= NULL
))
826 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
827 // docs, if IM filter returns true, no further processing should be done.
828 // we should send the key_down event anyway.
829 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
830 win
->m_imData
->lastKeyEvent
= NULL
;
831 if (intercepted_by_IM
)
833 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
844 wxWindowGTK
*ancestor
= win
;
847 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
850 wxCommandEvent
menu_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
851 ret
= ancestor
->HandleWindowEvent( menu_event
);
855 // if the accelerator wasn't handled as menu event, try
856 // it as button click (for compatibility with other
858 wxCommandEvent
button_event( wxEVT_COMMAND_BUTTON_CLICKED
, command
);
859 ret
= ancestor
->HandleWindowEvent( button_event
);
864 if (ancestor
->IsTopLevel())
866 ancestor
= ancestor
->GetParent();
869 #endif // wxUSE_ACCEL
871 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
872 // will only be sent if it is not in an accelerator table.
876 KeySym keysym
= gdk_event
->keyval
;
877 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
878 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
881 if ( wxIsAsciiKeysym(keysym
) )
884 key_code
= (unsigned char)keysym
;
886 // gdk_event->string is actually deprecated
887 else if ( gdk_event
->length
== 1 )
889 key_code
= (unsigned char)gdk_event
->string
[0];
895 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
897 event
.m_keyCode
= key_code
;
899 // To conform to the docs we need to translate Ctrl-alpha
900 // characters to values in the range 1-26.
901 if ( event
.ControlDown() &&
902 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
904 if ( wxIsLowerChar(key_code
) )
905 event
.m_keyCode
= key_code
- 'a' + 1;
906 if ( wxIsUpperChar(key_code
) )
907 event
.m_keyCode
= key_code
- 'A' + 1;
909 event
.m_uniChar
= event
.m_keyCode
;
913 // Implement OnCharHook by checking ancestor top level windows
914 wxWindow
*parent
= win
;
915 while (parent
&& !parent
->IsTopLevel())
916 parent
= parent
->GetParent();
919 event
.SetEventType( wxEVT_CHAR_HOOK
);
920 ret
= parent
->HandleWindowEvent( event
);
925 event
.SetEventType(wxEVT_CHAR
);
926 ret
= win
->HandleWindowEvent( event
);
937 gtk_wxwindow_commit_cb (GtkIMContext
* WXUNUSED(context
),
941 wxKeyEvent
event( wxEVT_KEY_DOWN
);
943 // take modifiers, cursor position, timestamp etc. from the last
944 // key_press_event that was fed into Input Method:
945 if (window
->m_imData
->lastKeyEvent
)
947 wxFillOtherKeyEventFields(event
,
948 window
, window
->m_imData
->lastKeyEvent
);
952 event
.SetEventObject( window
);
955 const wxString
data(wxGTK_CONV_BACK_SYS(str
));
961 // Implement OnCharHook by checking ancestor top level windows
962 wxWindow
*parent
= window
;
963 while (parent
&& !parent
->IsTopLevel())
964 parent
= parent
->GetParent();
966 for( wxString::const_iterator pstr
= data
.begin(); pstr
!= data
.end(); ++pstr
)
969 event
.m_uniChar
= *pstr
;
970 // Backward compatible for ISO-8859-1
971 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
972 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
974 event
.m_keyCode
= (char)*pstr
;
975 #endif // wxUSE_UNICODE
977 // To conform to the docs we need to translate Ctrl-alpha
978 // characters to values in the range 1-26.
979 if ( event
.ControlDown() &&
980 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
982 if ( wxIsLowerChar(*pstr
) )
983 event
.m_keyCode
= *pstr
- 'a' + 1;
984 if ( wxIsUpperChar(*pstr
) )
985 event
.m_keyCode
= *pstr
- 'A' + 1;
987 event
.m_keyCode
= *pstr
- 'a' + 1;
989 event
.m_uniChar
= event
.m_keyCode
;
995 event
.SetEventType( wxEVT_CHAR_HOOK
);
996 ret
= parent
->HandleWindowEvent( event
);
1001 event
.SetEventType(wxEVT_CHAR
);
1002 ret
= window
->HandleWindowEvent( event
);
1009 //-----------------------------------------------------------------------------
1010 // "key_release_event" from any window
1011 //-----------------------------------------------------------------------------
1015 gtk_window_key_release_callback( GtkWidget
* WXUNUSED(widget
),
1016 GdkEventKey
*gdk_event
,
1022 if (g_blockEventsOnDrag
)
1025 wxKeyEvent
event( wxEVT_KEY_UP
);
1026 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1028 // unknown key pressed, ignore (the event would be useless anyhow)
1032 return win
->GTKProcessEvent(event
);
1036 // ============================================================================
1038 // ============================================================================
1040 // ----------------------------------------------------------------------------
1041 // mouse event processing helpers
1042 // ----------------------------------------------------------------------------
1044 // init wxMouseEvent with the info from GdkEventXXX struct
1045 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1046 wxMouseEvent
& event
,
1049 event
.SetTimestamp( gdk_event
->time
);
1050 event
.m_shiftDown
= gdk_event
->state
& GDK_SHIFT_MASK
;
1051 event
.m_controlDown
= gdk_event
->state
& GDK_CONTROL_MASK
;
1052 event
.m_altDown
= gdk_event
->state
& GDK_MOD1_MASK
;
1053 event
.m_metaDown
= gdk_event
->state
& GDK_MOD2_MASK
;
1054 event
.m_leftDown
= gdk_event
->state
& GDK_BUTTON1_MASK
;
1055 event
.m_middleDown
= gdk_event
->state
& GDK_BUTTON2_MASK
;
1056 event
.m_rightDown
= gdk_event
->state
& GDK_BUTTON3_MASK
;
1057 event
.m_aux1Down
= gdk_event
->state
& GDK_BUTTON4_MASK
;
1058 event
.m_aux2Down
= gdk_event
->state
& GDK_BUTTON5_MASK
;
1060 wxPoint pt
= win
->GetClientAreaOrigin();
1061 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1062 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1064 if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
))
1066 // origin in the upper right corner
1067 int window_width
= win
->m_wxwindow
->allocation
.width
;
1068 event
.m_x
= window_width
- event
.m_x
;
1071 event
.SetEventObject( win
);
1072 event
.SetId( win
->GetId() );
1073 event
.SetTimestamp( gdk_event
->time
);
1076 static void AdjustEventButtonState(wxMouseEvent
& event
)
1078 // GDK reports the old state of the button for a button press event, but
1079 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1080 // for a LEFT_DOWN event, not FALSE, so we will invert
1081 // left/right/middleDown for the corresponding click events
1083 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1084 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1085 (event
.GetEventType() == wxEVT_LEFT_UP
))
1087 event
.m_leftDown
= !event
.m_leftDown
;
1091 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1092 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1093 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1095 event
.m_middleDown
= !event
.m_middleDown
;
1099 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1100 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1101 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1103 event
.m_rightDown
= !event
.m_rightDown
;
1108 // find the window to send the mouse event too
1110 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1115 if (win
->m_wxwindow
)
1117 wxPizza
* pizza
= WX_PIZZA(win
->m_wxwindow
);
1118 xx
+= pizza
->m_scroll_x
;
1119 yy
+= pizza
->m_scroll_y
;
1122 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1125 wxWindowGTK
*child
= node
->GetData();
1127 node
= node
->GetNext();
1128 if (!child
->IsShown())
1131 if (child
->IsTransparentForMouse())
1133 // wxStaticBox is transparent in the box itself
1134 int xx1
= child
->m_x
;
1135 int yy1
= child
->m_y
;
1136 int xx2
= child
->m_x
+ child
->m_width
;
1137 int yy2
= child
->m_y
+ child
->m_height
;
1140 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1142 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1144 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1146 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1157 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1158 (child
->m_x
<= xx
) &&
1159 (child
->m_y
<= yy
) &&
1160 (child
->m_x
+child
->m_width
>= xx
) &&
1161 (child
->m_y
+child
->m_height
>= yy
))
1174 // ----------------------------------------------------------------------------
1175 // common event handlers helpers
1176 // ----------------------------------------------------------------------------
1178 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const
1180 // nothing special at this level
1181 return HandleWindowEvent(event
);
1184 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1188 if (g_blockEventsOnDrag
)
1190 if (g_blockEventsOnScroll
)
1193 if (!GTKIsOwnWindow(event
->window
))
1199 // overloads for all GDK event types we use here: we need to have this as
1200 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1201 // derives from it in the sense that the structs have the same layout
1202 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1203 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1205 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1208 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1209 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1210 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1212 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1214 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1215 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1219 // all event handlers must have C linkage as they're called from GTK+ C code
1223 //-----------------------------------------------------------------------------
1224 // "button_press_event"
1225 //-----------------------------------------------------------------------------
1228 gtk_window_button_press_callback( GtkWidget
*widget
,
1229 GdkEventButton
*gdk_event
,
1232 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1234 g_lastButtonNumber
= gdk_event
->button
;
1236 // GDK sends surplus button down events
1237 // before a double click event. We
1238 // need to filter these out.
1239 if ((gdk_event
->type
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
))
1241 GdkEvent
*peek_event
= gdk_event_peek();
1244 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1245 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1247 gdk_event_free( peek_event
);
1252 gdk_event_free( peek_event
);
1257 wxEventType event_type
= wxEVT_NULL
;
1259 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1260 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1262 // Reset GDK internal timestamp variables in order to disable GDK
1263 // triple click events. GDK will then next time believe no button has
1264 // been clicked just before, and send a normal button click event.
1265 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1266 display
->button_click_time
[1] = 0;
1267 display
->button_click_time
[0] = 0;
1270 if (gdk_event
->button
== 1)
1272 // note that GDK generates triple click events which are not supported
1273 // by wxWidgets but still have to be passed to the app as otherwise
1274 // clicks would simply go missing
1275 switch (gdk_event
->type
)
1277 // we shouldn't get triple clicks at all for GTK2 because we
1278 // suppress them artificially using the code above but we still
1279 // should map them to something for GTK1 and not just ignore them
1280 // as this would lose clicks
1281 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1282 case GDK_BUTTON_PRESS
:
1283 event_type
= wxEVT_LEFT_DOWN
;
1286 case GDK_2BUTTON_PRESS
:
1287 event_type
= wxEVT_LEFT_DCLICK
;
1291 // just to silence gcc warnings
1295 else if (gdk_event
->button
== 2)
1297 switch (gdk_event
->type
)
1299 case GDK_3BUTTON_PRESS
:
1300 case GDK_BUTTON_PRESS
:
1301 event_type
= wxEVT_MIDDLE_DOWN
;
1304 case GDK_2BUTTON_PRESS
:
1305 event_type
= wxEVT_MIDDLE_DCLICK
;
1312 else if (gdk_event
->button
== 3)
1314 switch (gdk_event
->type
)
1316 case GDK_3BUTTON_PRESS
:
1317 case GDK_BUTTON_PRESS
:
1318 event_type
= wxEVT_RIGHT_DOWN
;
1321 case GDK_2BUTTON_PRESS
:
1322 event_type
= wxEVT_RIGHT_DCLICK
;
1330 if ( event_type
== wxEVT_NULL
)
1332 // unknown mouse button or click type
1336 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1338 wxMouseEvent
event( event_type
);
1339 InitMouseEvent( win
, event
, gdk_event
);
1341 AdjustEventButtonState(event
);
1343 // wxListBox actually gets mouse events from the item, so we need to give it
1344 // a chance to correct this
1345 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1347 // find the correct window to send the event to: it may be a different one
1348 // from the one which got it at GTK+ level because some controls don't have
1349 // their own X window and thus cannot get any events.
1350 if ( !g_captureWindow
)
1351 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1353 // reset the event object and id in case win changed.
1354 event
.SetEventObject( win
);
1355 event
.SetId( win
->GetId() );
1357 bool ret
= win
->GTKProcessEvent( event
);
1358 g_lastMouseEvent
= NULL
;
1362 if ((event_type
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&
1363 (gs_currentFocus
!= win
) /* && win->IsFocusable() */)
1368 if (event_type
== wxEVT_RIGHT_DOWN
)
1370 // generate a "context menu" event: this is similar to right mouse
1371 // click under many GUIs except that it is generated differently
1372 // (right up under MSW, ctrl-click under Mac, right down here) and
1374 // (a) it's a command event and so is propagated to the parent
1375 // (b) under some ports it can be generated from kbd too
1376 // (c) it uses screen coords (because of (a))
1377 wxContextMenuEvent
evtCtx(
1380 win
->ClientToScreen(event
.GetPosition()));
1381 evtCtx
.SetEventObject(win
);
1382 return win
->GTKProcessEvent(evtCtx
);
1388 //-----------------------------------------------------------------------------
1389 // "button_release_event"
1390 //-----------------------------------------------------------------------------
1393 gtk_window_button_release_callback( GtkWidget
*widget
,
1394 GdkEventButton
*gdk_event
,
1397 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1399 g_lastButtonNumber
= 0;
1401 wxEventType event_type
= wxEVT_NULL
;
1403 switch (gdk_event
->button
)
1406 event_type
= wxEVT_LEFT_UP
;
1410 event_type
= wxEVT_MIDDLE_UP
;
1414 event_type
= wxEVT_RIGHT_UP
;
1418 // unknown button, don't process
1422 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1424 wxMouseEvent
event( event_type
);
1425 InitMouseEvent( win
, event
, gdk_event
);
1427 AdjustEventButtonState(event
);
1429 // same wxListBox hack as above
1430 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1432 if ( !g_captureWindow
)
1433 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1435 // reset the event object and id in case win changed.
1436 event
.SetEventObject( win
);
1437 event
.SetId( win
->GetId() );
1439 bool ret
= win
->GTKProcessEvent(event
);
1441 g_lastMouseEvent
= NULL
;
1446 //-----------------------------------------------------------------------------
1447 // "motion_notify_event"
1448 //-----------------------------------------------------------------------------
1451 gtk_window_motion_notify_callback( GtkWidget
* WXUNUSED(widget
),
1452 GdkEventMotion
*gdk_event
,
1455 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1457 if (gdk_event
->is_hint
)
1461 GdkModifierType state
;
1462 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1467 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1469 wxMouseEvent
event( wxEVT_MOTION
);
1470 InitMouseEvent(win
, event
, gdk_event
);
1472 if ( g_captureWindow
)
1474 // synthesise a mouse enter or leave event if needed
1475 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1476 // This seems to be necessary and actually been added to
1477 // GDK itself in version 2.0.X
1480 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1481 if ( hasMouse
!= g_captureWindowHasMouse
)
1483 // the mouse changed window
1484 g_captureWindowHasMouse
= hasMouse
;
1486 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1487 : wxEVT_LEAVE_WINDOW
);
1488 InitMouseEvent(win
, eventM
, gdk_event
);
1489 eventM
.SetEventObject(win
);
1490 win
->GTKProcessEvent(eventM
);
1495 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1497 // reset the event object and id in case win changed.
1498 event
.SetEventObject( win
);
1499 event
.SetId( win
->GetId() );
1502 if ( !g_captureWindow
)
1504 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1505 if (win
->GTKProcessEvent( cevent
))
1507 win
->SetCursor( cevent
.GetCursor() );
1511 bool ret
= win
->GTKProcessEvent(event
);
1513 g_lastMouseEvent
= NULL
;
1518 //-----------------------------------------------------------------------------
1519 // "scroll_event" (mouse wheel event)
1520 //-----------------------------------------------------------------------------
1523 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1525 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1526 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1531 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1532 InitMouseEvent(win
, event
, gdk_event
);
1534 // FIXME: Get these values from GTK or GDK
1535 event
.m_linesPerAction
= 3;
1536 event
.m_wheelDelta
= 120;
1537 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1538 event
.m_wheelRotation
= 120;
1540 event
.m_wheelRotation
= -120;
1542 return win
->GTKProcessEvent(event
);
1545 //-----------------------------------------------------------------------------
1547 //-----------------------------------------------------------------------------
1549 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1551 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1552 event
.SetEventObject(win
);
1553 return win
->GTKProcessEvent(event
);
1556 //-----------------------------------------------------------------------------
1558 //-----------------------------------------------------------------------------
1561 gtk_window_focus_in_callback( GtkWidget
* WXUNUSED(widget
),
1562 GdkEventFocus
*WXUNUSED(event
),
1565 return win
->GTKHandleFocusIn();
1568 //-----------------------------------------------------------------------------
1569 // "focus_out_event"
1570 //-----------------------------------------------------------------------------
1573 gtk_window_focus_out_callback( GtkWidget
* WXUNUSED(widget
),
1574 GdkEventFocus
* WXUNUSED(gdk_event
),
1577 return win
->GTKHandleFocusOut();
1580 //-----------------------------------------------------------------------------
1582 //-----------------------------------------------------------------------------
1585 wx_window_focus_callback(GtkWidget
*widget
,
1586 GtkDirectionType
WXUNUSED(direction
),
1589 // the default handler for focus signal in GtkScrolledWindow sets
1590 // focus to the window itself even if it doesn't accept focus, i.e. has no
1591 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1592 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1593 // any children which might accept focus (we know we don't accept the focus
1594 // ourselves as this signal is only connected in this case)
1595 if ( win
->GetChildren().empty() )
1596 g_signal_stop_emission_by_name(widget
, "focus");
1598 // we didn't change the focus
1602 //-----------------------------------------------------------------------------
1603 // "enter_notify_event"
1604 //-----------------------------------------------------------------------------
1607 gtk_window_enter_callback( GtkWidget
*widget
,
1608 GdkEventCrossing
*gdk_event
,
1611 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1613 // Event was emitted after a grab
1614 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1618 GdkModifierType state
= (GdkModifierType
)0;
1620 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1622 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1623 InitMouseEvent(win
, event
, gdk_event
);
1624 wxPoint pt
= win
->GetClientAreaOrigin();
1625 event
.m_x
= x
+ pt
.x
;
1626 event
.m_y
= y
+ pt
.y
;
1628 if ( !g_captureWindow
)
1630 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1631 if (win
->GTKProcessEvent( cevent
))
1633 win
->SetCursor( cevent
.GetCursor() );
1637 return win
->GTKProcessEvent(event
);
1640 //-----------------------------------------------------------------------------
1641 // "leave_notify_event"
1642 //-----------------------------------------------------------------------------
1645 gtk_window_leave_callback( GtkWidget
*widget
,
1646 GdkEventCrossing
*gdk_event
,
1649 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1651 // Event was emitted after an ungrab
1652 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1654 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1658 GdkModifierType state
= (GdkModifierType
)0;
1660 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1662 InitMouseEvent(win
, event
, gdk_event
);
1664 return win
->GTKProcessEvent(event
);
1667 //-----------------------------------------------------------------------------
1668 // "value_changed" from scrollbar
1669 //-----------------------------------------------------------------------------
1672 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
1674 wxEventType eventType
= win
->GetScrollEventType(range
);
1675 if (eventType
!= wxEVT_NULL
)
1677 // Convert scroll event type to scrollwin event type
1678 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
1680 // find the scrollbar which generated the event
1681 wxWindowGTK::ScrollDir dir
= win
->ScrollDirFromRange(range
);
1683 // generate the corresponding wx event
1684 const int orient
= wxWindow::OrientFromScrollDir(dir
);
1685 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
1686 event
.SetEventObject(win
);
1688 win
->GTKProcessEvent(event
);
1692 //-----------------------------------------------------------------------------
1693 // "button_press_event" from scrollbar
1694 //-----------------------------------------------------------------------------
1697 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
1699 g_blockEventsOnScroll
= true;
1700 win
->m_mouseButtonDown
= true;
1705 //-----------------------------------------------------------------------------
1706 // "event_after" from scrollbar
1707 //-----------------------------------------------------------------------------
1710 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
1712 if (event
->type
== GDK_BUTTON_RELEASE
)
1714 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1716 const int orient
= wxWindow::OrientFromScrollDir(
1717 win
->ScrollDirFromRange(range
));
1718 wxScrollWinEvent
evt(wxEVT_SCROLLWIN_THUMBRELEASE
,
1719 win
->GetScrollPos(orient
), orient
);
1720 evt
.SetEventObject(win
);
1721 win
->GTKProcessEvent(evt
);
1725 //-----------------------------------------------------------------------------
1726 // "button_release_event" from scrollbar
1727 //-----------------------------------------------------------------------------
1730 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
1732 g_blockEventsOnScroll
= false;
1733 win
->m_mouseButtonDown
= false;
1734 // If thumb tracking
1735 if (win
->m_isScrolling
)
1737 win
->m_isScrolling
= false;
1738 // Hook up handler to send thumb release event after this emission is finished.
1739 // To allow setting scroll position from event handler, sending event must
1740 // be deferred until after the GtkRange handler for this signal has run
1741 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1747 //-----------------------------------------------------------------------------
1748 // "realize" from m_widget
1749 //-----------------------------------------------------------------------------
1752 gtk_window_realized_callback(GtkWidget
* widget
, wxWindow
* win
)
1756 gtk_im_context_set_client_window( win
->m_imData
->context
,
1760 // We cannot set colours and fonts before the widget
1761 // been realized, so we do this directly after realization
1762 // or otherwise in idle time
1764 if (win
->m_needsStyleChange
)
1766 win
->SetBackgroundStyle(win
->GetBackgroundStyle());
1767 win
->m_needsStyleChange
= false;
1770 wxWindowCreateEvent
event( win
);
1771 event
.SetEventObject( win
);
1772 win
->GTKProcessEvent( event
);
1775 //-----------------------------------------------------------------------------
1776 // "size_allocate" from m_wxwindow or m_widget
1777 //-----------------------------------------------------------------------------
1780 size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxWindow
* win
)
1782 int w
= alloc
->width
;
1783 int h
= alloc
->height
;
1784 if (win
->m_wxwindow
)
1786 int border_x
, border_y
;
1787 WX_PIZZA(win
->m_wxwindow
)->get_border_widths(border_x
, border_y
);
1793 if (win
->m_oldClientWidth
!= w
|| win
->m_oldClientHeight
!= h
)
1795 win
->m_oldClientWidth
= w
;
1796 win
->m_oldClientHeight
= h
;
1797 // this callback can be connected to m_wxwindow,
1798 // so always get size from m_widget->allocation
1799 win
->m_width
= win
->m_widget
->allocation
.width
;
1800 win
->m_height
= win
->m_widget
->allocation
.height
;
1801 if (!win
->m_nativeSizeEvent
)
1803 wxSizeEvent
event(win
->GetSize(), win
->GetId());
1804 event
.SetEventObject(win
);
1805 win
->GTKProcessEvent(event
);
1810 //-----------------------------------------------------------------------------
1812 //-----------------------------------------------------------------------------
1814 #if GTK_CHECK_VERSION(2, 8, 0)
1816 gtk_window_grab_broken( GtkWidget
*,
1817 GdkEventGrabBroken
*event
,
1820 // Mouse capture has been lost involuntarily, notify the application
1821 if(!event
->keyboard
&& wxWindow::GetCapture() == win
)
1823 wxMouseCaptureLostEvent
evt( win
->GetId() );
1824 evt
.SetEventObject( win
);
1825 win
->HandleWindowEvent( evt
);
1831 //-----------------------------------------------------------------------------
1833 //-----------------------------------------------------------------------------
1836 void gtk_window_style_set_callback( GtkWidget
*WXUNUSED(widget
),
1837 GtkStyle
*previous_style
,
1840 if (win
&& previous_style
)
1842 wxSysColourChangedEvent event
;
1843 event
.SetEventObject(win
);
1845 win
->GTKProcessEvent( event
);
1851 // Helper to suspend colour change event event processing while we change a widget's style
1852 class wxSuspendStyleEvents
1855 wxSuspendStyleEvents(wxWindow
* win
)
1858 if (win
->m_wxwindow
&& win
->IsTopLevel())
1861 g_signal_handlers_block_by_func(
1862 m_win
->m_wxwindow
, (void*)gtk_window_style_set_callback
, m_win
);
1865 ~wxSuspendStyleEvents()
1868 g_signal_handlers_unblock_by_func(
1869 m_win
->m_wxwindow
, (void*)gtk_window_style_set_callback
, m_win
);
1875 // ----------------------------------------------------------------------------
1876 // this wxWindowBase function is implemented here (in platform-specific file)
1877 // because it is static and so couldn't be made virtual
1878 // ----------------------------------------------------------------------------
1880 wxWindow
*wxWindowBase::DoFindFocus()
1882 wxWindowGTK
*focus
= gs_pendingFocus
? gs_pendingFocus
: gs_currentFocus
;
1883 // the cast is necessary when we compile in wxUniversal mode
1884 return wx_static_cast(wxWindow
*, focus
);
1887 //-----------------------------------------------------------------------------
1888 // InsertChild for wxWindowGTK.
1889 //-----------------------------------------------------------------------------
1891 /* Callback for wxWindowGTK. This very strange beast has to be used because
1892 * C++ has no virtual methods in a constructor. We have to emulate a
1893 * virtual function here as wxNotebook requires a different way to insert
1894 * a child in it. I had opted for creating a wxNotebookPage window class
1895 * which would have made this superfluous (such in the MDI window system),
1896 * but no-one was listening to me... */
1898 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
1900 /* the window might have been scrolled already, do we
1901 have to adapt the position */
1902 wxPizza
* pizza
= WX_PIZZA(parent
->m_wxwindow
);
1903 child
->m_x
+= pizza
->m_scroll_x
;
1904 child
->m_y
+= pizza
->m_scroll_y
;
1906 gtk_widget_set_size_request(
1907 child
->m_widget
, child
->m_width
, child
->m_height
);
1909 GTK_FIXED(parent
->m_wxwindow
), child
->m_widget
, child
->m_x
, child
->m_y
);
1912 //-----------------------------------------------------------------------------
1914 //-----------------------------------------------------------------------------
1916 wxWindow
*wxGetActiveWindow()
1918 return wxWindow::FindFocus();
1922 wxMouseState
wxGetMouseState()
1928 GdkModifierType mask
;
1930 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
1934 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
1935 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
1936 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
1937 ms
.SetAux1Down(mask
& GDK_BUTTON4_MASK
);
1938 ms
.SetAux2Down(mask
& GDK_BUTTON5_MASK
);
1940 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
1941 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
1942 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
1943 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
1948 //-----------------------------------------------------------------------------
1950 //-----------------------------------------------------------------------------
1952 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
1954 #ifdef __WXUNIVERSAL__
1955 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
1957 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
1958 #endif // __WXUNIVERSAL__/__WXGTK__
1960 void wxWindowGTK::Init()
1963 m_widget
= (GtkWidget
*) NULL
;
1964 m_wxwindow
= (GtkWidget
*) NULL
;
1965 m_focusWidget
= (GtkWidget
*) NULL
;
1974 m_isBeingDeleted
= false;
1976 m_showOnIdle
= false;
1979 m_nativeSizeEvent
= false;
1981 m_isScrolling
= false;
1982 m_mouseButtonDown
= false;
1984 // initialize scrolling stuff
1985 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
1987 m_scrollBar
[dir
] = NULL
;
1988 m_scrollPos
[dir
] = 0;
1992 m_oldClientHeight
= 0;
1994 m_insertCallback
= wxInsertChildInWindow
;
1996 m_clipPaintRegion
= false;
1998 m_needsStyleChange
= false;
2000 m_cursor
= *wxSTANDARD_CURSOR
;
2003 m_dirtyTabOrder
= false;
2006 wxWindowGTK::wxWindowGTK()
2011 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2016 const wxString
&name
)
2020 Create( parent
, id
, pos
, size
, style
, name
);
2023 bool wxWindowGTK::Create( wxWindow
*parent
,
2028 const wxString
&name
)
2030 // Get default border
2031 wxBorder border
= GetBorder(style
);
2032 style
&= ~wxBORDER_MASK
;
2035 if (!PreCreation( parent
, pos
, size
) ||
2036 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2038 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2043 m_wxwindow
= wxPizza::New(m_windowStyle
);
2044 if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
))
2045 m_widget
= m_wxwindow
;
2048 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2050 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2052 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2053 scroll_class
->scrollbar_spacing
= 0;
2055 // There is a conflict with default bindings at GTK+
2056 // level between scrolled windows and notebooks both of which want to use
2057 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2058 // direction and notebooks for changing pages -- we decide that if we don't
2059 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2060 // means we can get working keyboard navigation in notebooks
2061 if ( !HasFlag(wxHSCROLL
) )
2064 bindings
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
));
2067 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
);
2068 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
);
2072 if (HasFlag(wxALWAYS_SHOW_SB
))
2074 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
2076 scrolledWindow
->hscrollbar_visible
= TRUE
;
2077 scrolledWindow
->vscrollbar_visible
= TRUE
;
2081 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2084 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2085 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2086 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2087 gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE
);
2089 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2091 // connect various scroll-related events
2092 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2094 // these handlers block mouse events to any window during scrolling
2095 // such as motion events and prevent GTK and wxWidgets from fighting
2096 // over where the slider should be
2097 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2098 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2099 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2100 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2102 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2103 G_CALLBACK(gtk_scrollbar_event_after
), this);
2104 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2106 // these handlers get notified when scrollbar slider moves
2107 g_signal_connect_after(m_scrollBar
[dir
], "value_changed",
2108 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2111 gtk_widget_show( m_wxwindow
);
2115 m_parent
->DoAddChild( this );
2117 m_focusWidget
= m_wxwindow
;
2119 SetCanFocus(AcceptsFocus());
2126 wxWindowGTK::~wxWindowGTK()
2130 if (gs_currentFocus
== this)
2131 gs_currentFocus
= NULL
;
2132 if (gs_pendingFocus
== this)
2133 gs_pendingFocus
= NULL
;
2135 if ( gs_deferredFocusOut
== this )
2136 gs_deferredFocusOut
= NULL
;
2138 m_isBeingDeleted
= true;
2141 // destroy children before destroying this window itself
2144 // unhook focus handlers to prevent stray events being
2145 // propagated to this (soon to be) dead object
2146 if (m_focusWidget
!= NULL
)
2148 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2149 (gpointer
) gtk_window_focus_in_callback
,
2151 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2152 (gpointer
) gtk_window_focus_out_callback
,
2159 // delete before the widgets to avoid a crash on solaris
2162 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2164 gtk_widget_destroy( m_wxwindow
);
2165 m_wxwindow
= (GtkWidget
*) NULL
;
2170 gtk_widget_destroy( m_widget
);
2171 m_widget
= (GtkWidget
*) NULL
;
2175 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2177 if ( GTKNeedsParent() )
2179 wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") );
2182 // Use either the given size, or the default if -1 is given.
2183 // See wxWindowBase for these functions.
2184 m_width
= WidthDefault(size
.x
) ;
2185 m_height
= HeightDefault(size
.y
);
2193 void wxWindowGTK::PostCreation()
2195 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2201 // these get reported to wxWidgets -> wxPaintEvent
2203 g_signal_connect (m_wxwindow
, "expose_event",
2204 G_CALLBACK (gtk_window_expose_callback
), this);
2206 if (GetLayoutDirection() == wxLayout_LeftToRight
)
2207 gtk_widget_set_redraw_on_allocate(m_wxwindow
, HasFlag(wxFULL_REPAINT_ON_RESIZE
));
2210 // Create input method handler
2211 m_imData
= new wxGtkIMData
;
2213 // Cannot handle drawing preedited text yet
2214 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2216 g_signal_connect (m_imData
->context
, "commit",
2217 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2220 #ifndef __WXUNIVERSAL__
2221 if (HasFlag(wxPizza::BORDER_STYLES
))
2223 g_signal_connect(m_widget
, "expose_event",
2224 G_CALLBACK(expose_event_border
), this);
2231 if (!GTK_IS_WINDOW(m_widget
))
2233 if (m_focusWidget
== NULL
)
2234 m_focusWidget
= m_widget
;
2238 g_signal_connect (m_focusWidget
, "focus_in_event",
2239 G_CALLBACK (gtk_window_focus_in_callback
), this);
2240 g_signal_connect (m_focusWidget
, "focus_out_event",
2241 G_CALLBACK (gtk_window_focus_out_callback
), this);
2245 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2246 G_CALLBACK (gtk_window_focus_in_callback
), this);
2247 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2248 G_CALLBACK (gtk_window_focus_out_callback
), this);
2252 if ( !AcceptsFocusFromKeyboard() )
2256 g_signal_connect(m_widget
, "focus",
2257 G_CALLBACK(wx_window_focus_callback
), this);
2260 // connect to the various key and mouse handlers
2262 GtkWidget
*connect_widget
= GetConnectWidget();
2264 ConnectWidget( connect_widget
);
2266 /* We cannot set colours, fonts and cursors before the widget has
2267 been realized, so we do this directly after realization */
2268 g_signal_connect (connect_widget
, "realize",
2269 G_CALLBACK (gtk_window_realized_callback
), this);
2273 g_signal_connect(m_wxwindow
? m_wxwindow
: m_widget
, "size_allocate",
2274 G_CALLBACK(size_allocate
), this);
2279 #if GTK_CHECK_VERSION(2, 8, 0)
2280 if (!gtk_check_version(2,8,0))
2282 // Make sure we can notify the app when mouse capture is lost
2283 g_signal_connect (m_wxwindow
, "grab_broken_event",
2284 G_CALLBACK (gtk_window_grab_broken
), this);
2289 if ( connect_widget
!= m_wxwindow
)
2291 #if GTK_CHECK_VERSION(2, 8, 0)
2292 if (!gtk_check_version(2,8,0))
2294 // Make sure we can notify app code when mouse capture is lost
2295 g_signal_connect (connect_widget
, "grab_broken_event",
2296 G_CALLBACK (gtk_window_grab_broken
), this);
2301 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2302 if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2304 // If we connect to the "size_request" signal of a GtkFileChooserButton
2305 // then that control won't be sized properly when placed inside sizers
2306 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2307 // FIXME: what should be done here ?
2310 if ( !IsTopLevel() ) // top level windows use their own callback
2312 // This is needed if we want to add our windows into native
2313 // GTK controls, such as the toolbar. With this callback, the
2314 // toolbar gets to know the correct size (the one set by the
2315 // programmer). Sadly, it misbehaves for wxComboBox.
2316 g_signal_connect (m_widget
, "size_request",
2317 G_CALLBACK (wxgtk_window_size_request_callback
),
2321 InheritAttributes();
2325 SetLayoutDirection(wxLayout_Default
);
2327 // unless the window was created initially hidden (i.e. Hide() had been
2328 // called before Create()), we should show it at GTK+ level as well
2330 gtk_widget_show( m_widget
);
2333 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2335 g_signal_connect (widget
, "key_press_event",
2336 G_CALLBACK (gtk_window_key_press_callback
), this);
2337 g_signal_connect (widget
, "key_release_event",
2338 G_CALLBACK (gtk_window_key_release_callback
), this);
2339 g_signal_connect (widget
, "button_press_event",
2340 G_CALLBACK (gtk_window_button_press_callback
), this);
2341 g_signal_connect (widget
, "button_release_event",
2342 G_CALLBACK (gtk_window_button_release_callback
), this);
2343 g_signal_connect (widget
, "motion_notify_event",
2344 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2345 g_signal_connect (widget
, "scroll_event",
2346 G_CALLBACK (window_scroll_event
), this);
2347 g_signal_connect (widget
, "popup_menu",
2348 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2349 g_signal_connect (widget
, "enter_notify_event",
2350 G_CALLBACK (gtk_window_enter_callback
), this);
2351 g_signal_connect (widget
, "leave_notify_event",
2352 G_CALLBACK (gtk_window_leave_callback
), this);
2354 if (IsTopLevel() && m_wxwindow
)
2355 g_signal_connect (m_wxwindow
, "style_set",
2356 G_CALLBACK (gtk_window_style_set_callback
), this);
2359 bool wxWindowGTK::Destroy()
2361 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2365 return wxWindowBase::Destroy();
2368 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2370 gtk_widget_set_size_request(m_widget
, width
, height
);
2371 // inform the parent to perform the move
2372 WX_PIZZA(m_parent
->m_wxwindow
)->move(m_widget
, x
, y
);
2375 void wxWindowGTK::ConstrainSize()
2378 // GPE's window manager doesn't like size hints at all, esp. when the user
2379 // has to use the virtual keyboard, so don't constrain size there
2383 const wxSize minSize
= GetMinSize();
2384 const wxSize maxSize
= GetMaxSize();
2385 if (minSize
.x
> 0 && m_width
< minSize
.x
) m_width
= minSize
.x
;
2386 if (minSize
.y
> 0 && m_height
< minSize
.y
) m_height
= minSize
.y
;
2387 if (maxSize
.x
> 0 && m_width
> maxSize
.x
) m_width
= maxSize
.x
;
2388 if (maxSize
.y
> 0 && m_height
> maxSize
.y
) m_height
= maxSize
.y
;
2392 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2394 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2395 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2397 int currentX
, currentY
;
2398 GetPosition(¤tX
, ¤tY
);
2399 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2401 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2403 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2405 // calculate the best size if we should auto size the window
2406 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2407 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2409 const wxSize sizeBest
= GetBestSize();
2410 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2412 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2413 height
= sizeBest
.y
;
2416 const wxSize
oldSize(m_width
, m_height
);
2422 if (m_parent
->m_wxwindow
)
2424 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2425 m_x
= x
+ pizza
->m_scroll_x
;
2426 m_y
= y
+ pizza
->m_scroll_y
;
2428 int left_border
= 0;
2429 int right_border
= 0;
2431 int bottom_border
= 0;
2433 /* the default button has a border around it */
2434 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2436 GtkBorder
*default_border
= NULL
;
2437 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2440 left_border
+= default_border
->left
;
2441 right_border
+= default_border
->right
;
2442 top_border
+= default_border
->top
;
2443 bottom_border
+= default_border
->bottom
;
2444 gtk_border_free( default_border
);
2448 DoMoveWindow( m_x
- left_border
,
2450 m_width
+left_border
+right_border
,
2451 m_height
+top_border
+bottom_border
);
2454 if (m_width
!= oldSize
.x
|| m_height
!= oldSize
.y
)
2456 // update these variables to keep size_allocate handler
2457 // from sending another size event for this change
2458 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2460 gtk_widget_queue_resize(m_widget
);
2461 if (!m_nativeSizeEvent
)
2463 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2464 event
.SetEventObject( this );
2465 HandleWindowEvent( event
);
2470 bool wxWindowGTK::GtkShowFromOnIdle()
2472 if (IsShown() && m_showOnIdle
&& !GTK_WIDGET_VISIBLE (m_widget
))
2474 GtkAllocation alloc
;
2477 alloc
.width
= m_width
;
2478 alloc
.height
= m_height
;
2479 gtk_widget_size_allocate( m_widget
, &alloc
);
2480 gtk_widget_show( m_widget
);
2481 wxShowEvent
eventShow(GetId(), true);
2482 eventShow
.SetEventObject(this);
2483 HandleWindowEvent(eventShow
);
2484 m_showOnIdle
= false;
2491 void wxWindowGTK::OnInternalIdle()
2493 if ( gs_deferredFocusOut
)
2494 GTKHandleDeferredFocusOut();
2496 // Check if we have to show window now
2497 if (GtkShowFromOnIdle()) return;
2499 if ( m_dirtyTabOrder
)
2501 m_dirtyTabOrder
= false;
2505 // Update style if the window was not yet realized
2506 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2507 if (m_needsStyleChange
)
2509 SetBackgroundStyle(GetBackgroundStyle());
2510 m_needsStyleChange
= false;
2513 wxCursor cursor
= m_cursor
;
2514 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2518 /* I now set the cursor anew in every OnInternalIdle call
2519 as setting the cursor in a parent window also effects the
2520 windows above so that checking for the current cursor is
2523 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2525 GdkWindow
*window
= m_wxwindow
->window
;
2527 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2529 if (!g_globalCursor
.Ok())
2530 cursor
= *wxSTANDARD_CURSOR
;
2532 window
= m_widget
->window
;
2533 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2534 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2537 else if ( m_widget
)
2539 GdkWindow
*window
= m_widget
->window
;
2540 if ( window
&& !GTK_WIDGET_NO_WINDOW(m_widget
) )
2541 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2545 if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
2546 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2549 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2551 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2553 if (width
) (*width
) = m_width
;
2554 if (height
) (*height
) = m_height
;
2557 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2559 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2561 const wxSize size
= GetSize();
2562 const wxSize clientSize
= GetClientSize();
2563 SetSize(width
+ (size
.x
- clientSize
.x
), height
+ (size
.y
- clientSize
.y
));
2566 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2568 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2575 // if window is scrollable, account for scrollbars
2576 for (int i
= 0; i
< 2 && m_scrollBar
[i
]; i
++)
2579 GtkAdjustment
* adj
= gtk_range_get_adjustment(m_scrollBar
[i
]);
2580 // if scrollbar enabled
2581 if (adj
->upper
> adj
->page_size
)
2583 gtk_widget_size_request(GTK_WIDGET(m_scrollBar
[i
]), &req
);
2584 if (i
== ScrollDir_Horz
)
2591 int border_x
, border_y
;
2592 WX_PIZZA(m_wxwindow
)->get_border_widths(border_x
, border_y
);
2602 if (width
) *width
= w
;
2603 if (height
) *height
= h
;
2606 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2608 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2612 if (!IsTopLevel() && m_parent
&& m_parent
->m_wxwindow
)
2614 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2615 dx
= pizza
->m_scroll_x
;
2616 dy
= pizza
->m_scroll_y
;
2619 if (m_x
== -1 && m_y
== -1)
2621 GdkWindow
*source
= (GdkWindow
*) NULL
;
2623 source
= m_wxwindow
->window
;
2625 source
= m_widget
->window
;
2631 gdk_window_get_origin( source
, &org_x
, &org_y
);
2634 m_parent
->ScreenToClient(&org_x
, &org_y
);
2636 wx_const_cast(wxWindowGTK
*, this)->m_x
= org_x
;
2637 wx_const_cast(wxWindowGTK
*, this)->m_y
= org_y
;
2641 if (x
) (*x
) = m_x
- dx
;
2642 if (y
) (*y
) = m_y
- dy
;
2645 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2647 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2649 if (!m_widget
->window
) return;
2651 GdkWindow
*source
= (GdkWindow
*) NULL
;
2653 source
= m_wxwindow
->window
;
2655 source
= m_widget
->window
;
2659 gdk_window_get_origin( source
, &org_x
, &org_y
);
2663 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2665 org_x
+= m_widget
->allocation
.x
;
2666 org_y
+= m_widget
->allocation
.y
;
2673 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2674 *x
= (GetClientSize().x
- *x
) + org_x
;
2682 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
2684 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2686 if (!m_widget
->window
) return;
2688 GdkWindow
*source
= (GdkWindow
*) NULL
;
2690 source
= m_wxwindow
->window
;
2692 source
= m_widget
->window
;
2696 gdk_window_get_origin( source
, &org_x
, &org_y
);
2700 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2702 org_x
+= m_widget
->allocation
.x
;
2703 org_y
+= m_widget
->allocation
.y
;
2709 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2710 *x
= (GetClientSize().x
- *x
) - org_x
;
2717 bool wxWindowGTK::Show( bool show
)
2719 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
2721 if (!wxWindowBase::Show(show
))
2727 if (show
&& m_showOnIdle
)
2734 gtk_widget_show(m_widget
);
2736 gtk_widget_hide(m_widget
);
2737 wxShowEvent
eventShow(GetId(), show
);
2738 eventShow
.SetEventObject(this);
2739 HandleWindowEvent(eventShow
);
2745 void wxWindowGTK::DoEnable( bool enable
)
2747 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2749 gtk_widget_set_sensitive( m_widget
, enable
);
2750 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2751 gtk_widget_set_sensitive( m_wxwindow
, enable
);
2754 int wxWindowGTK::GetCharHeight() const
2756 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
2758 wxFont font
= GetFont();
2759 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
2761 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2766 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2767 PangoLayout
*layout
= pango_layout_new(context
);
2768 pango_layout_set_font_description(layout
, desc
);
2769 pango_layout_set_text(layout
, "H", 1);
2770 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2772 PangoRectangle rect
;
2773 pango_layout_line_get_extents(line
, NULL
, &rect
);
2775 g_object_unref (layout
);
2777 return (int) PANGO_PIXELS(rect
.height
);
2780 int wxWindowGTK::GetCharWidth() const
2782 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
2784 wxFont font
= GetFont();
2785 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
2787 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2792 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2793 PangoLayout
*layout
= pango_layout_new(context
);
2794 pango_layout_set_font_description(layout
, desc
);
2795 pango_layout_set_text(layout
, "g", 1);
2796 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2798 PangoRectangle rect
;
2799 pango_layout_line_get_extents(line
, NULL
, &rect
);
2801 g_object_unref (layout
);
2803 return (int) PANGO_PIXELS(rect
.width
);
2806 void wxWindowGTK::GetTextExtent( const wxString
& string
,
2810 int *externalLeading
,
2811 const wxFont
*theFont
) const
2813 wxFont fontToUse
= theFont
? *theFont
: GetFont();
2815 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
2824 PangoContext
*context
= NULL
;
2826 context
= gtk_widget_get_pango_context( m_widget
);
2835 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
2836 PangoLayout
*layout
= pango_layout_new(context
);
2837 pango_layout_set_font_description(layout
, desc
);
2839 const wxCharBuffer data
= wxGTK_CONV( string
);
2841 pango_layout_set_text(layout
, data
, strlen(data
));
2844 PangoRectangle rect
;
2845 pango_layout_get_extents(layout
, NULL
, &rect
);
2847 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
2848 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
2851 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
2852 int baseline
= pango_layout_iter_get_baseline(iter
);
2853 pango_layout_iter_free(iter
);
2854 *descent
= *y
- PANGO_PIXELS(baseline
);
2856 if (externalLeading
) (*externalLeading
) = 0; // ??
2858 g_object_unref (layout
);
2862 bool wxWindowGTK::GTKHandleFocusIn()
2864 // Disable default focus handling for custom windows since the default GTK+
2865 // handler issues a repaint
2866 const bool retval
= m_wxwindow
? true : false;
2869 // NB: if there's still unprocessed deferred focus-out event (see
2870 // GTKHandleFocusOut() for explanation), we need to process it first so
2871 // that the order of focus events -- focus-out first, then focus-in
2872 // elsewhere -- is preserved
2873 if ( gs_deferredFocusOut
)
2875 if ( GTKNeedsToFilterSameWindowFocus() &&
2876 gs_deferredFocusOut
== this )
2878 // GTK+ focus changed from this wxWindow back to itself, so don't
2879 // emit any events at all
2880 wxLogTrace(TRACE_FOCUS
,
2881 "filtered out spurious focus change within %s(%p, %s)",
2882 GetClassInfo()->GetClassName(), this, GetLabel());
2883 gs_deferredFocusOut
= NULL
;
2887 // otherwise we need to send focus-out first
2888 wxASSERT_MSG ( gs_deferredFocusOut
!= this,
2889 "GTKHandleFocusIn(GTKFocus_Normal) called even though focus changed back to itself - derived class should handle this" );
2890 GTKHandleDeferredFocusOut();
2894 wxLogTrace(TRACE_FOCUS
,
2895 "handling focus_in event for %s(%p, %s)",
2896 GetClassInfo()->GetClassName(), this, GetLabel());
2899 gtk_im_context_focus_in(m_imData
->context
);
2901 gs_currentFocus
= this;
2902 gs_pendingFocus
= NULL
;
2905 // caret needs to be informed about focus change
2906 wxCaret
*caret
= GetCaret();
2909 caret
->OnSetFocus();
2911 #endif // wxUSE_CARET
2913 // Notify the parent keeping track of focus for the kbd navigation
2914 // purposes that we got it.
2915 wxChildFocusEvent
eventChildFocus(this);
2916 GTKProcessEvent(eventChildFocus
);
2918 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, GetId());
2919 eventFocus
.SetEventObject(this);
2920 GTKProcessEvent(eventFocus
);
2925 bool wxWindowGTK::GTKHandleFocusOut()
2927 // Disable default focus handling for custom windows since the default GTK+
2928 // handler issues a repaint
2929 const bool retval
= m_wxwindow
? true : false;
2932 // NB: If a control is composed of several GtkWidgets and when focus
2933 // changes from one of them to another within the same wxWindow, we get
2934 // a focus-out event followed by focus-in for another GtkWidget owned
2935 // by the same wx control. We don't want to generate two spurious
2936 // wxEVT_SET_FOCUS events in this case, so we defer sending wx events
2937 // from GTKHandleFocusOut() until we know for sure it's not coming back
2938 // (i.e. in GTKHandleFocusIn() or at idle time).
2939 if ( GTKNeedsToFilterSameWindowFocus() )
2941 wxASSERT_MSG( gs_deferredFocusOut
== NULL
,
2942 "deferred focus out event already pending" );
2943 wxLogTrace(TRACE_FOCUS
,
2944 "deferring focus_out event for %s(%p, %s)",
2945 GetClassInfo()->GetClassName(), this, GetLabel());
2946 gs_deferredFocusOut
= this;
2950 GTKHandleFocusOutNoDeferring();
2955 void wxWindowGTK::GTKHandleFocusOutNoDeferring()
2957 wxLogTrace(TRACE_FOCUS
,
2958 "handling focus_out event for %s(%p, %s)",
2959 GetClassInfo()->GetClassName(), this, GetLabel());
2962 gtk_im_context_focus_out(m_imData
->context
);
2964 if ( gs_currentFocus
!= this )
2966 // Something is terribly wrong, gs_currentFocus is out of sync with the
2967 // real focus. We will reset it to NULL anyway, because after this
2968 // focus-out event is handled, one of the following with happen:
2970 // * either focus will go out of the app altogether, in which case
2971 // gs_currentFocus _should_ be NULL
2973 // * or it goes to another control, in which case focus-in event will
2974 // follow immediately and it will set gs_currentFocus to the right
2976 wxLogDebug("window %s(%p, %s) lost focus even though it didn't have it",
2977 GetClassInfo()->GetClassName(), this, GetLabel());
2979 gs_currentFocus
= NULL
;
2982 // caret needs to be informed about focus change
2983 wxCaret
*caret
= GetCaret();
2986 caret
->OnKillFocus();
2988 #endif // wxUSE_CARET
2990 wxFocusEvent
event( wxEVT_KILL_FOCUS
, GetId() );
2991 event
.SetEventObject( this );
2992 GTKProcessEvent( event
);
2996 void wxWindowGTK::GTKHandleDeferredFocusOut()
2998 // NB: See GTKHandleFocusOut() for explanation. This function is called
2999 // from either GTKHandleFocusIn() or OnInternalIdle() to process
3001 if ( gs_deferredFocusOut
)
3003 wxWindowGTK
*win
= gs_deferredFocusOut
;
3004 gs_deferredFocusOut
= NULL
;
3006 wxLogTrace(TRACE_FOCUS
,
3007 "processing deferred focus_out event for %s(%p, %s)",
3008 win
->GetClassInfo()->GetClassName(), win
, win
->GetLabel());
3010 win
->GTKHandleFocusOutNoDeferring();
3014 void wxWindowGTK::SetFocus()
3016 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3018 // Setting "physical" focus is not immediate in GTK+ and while
3019 // gtk_widget_is_focus ("determines if the widget is the focus widget
3020 // within its toplevel", i.e. returns true for one widget per TLW, not
3021 // globally) returns true immediately after grabbing focus,
3022 // GTK_WIDGET_HAS_FOCUS (which returns true only for the one widget that
3023 // has focus at the moment) takes affect only after the window is shown
3024 // (if it was hidden at the moment of the call) or at the next event loop
3027 // Because we want to FindFocus() call immediately following
3028 // foo->SetFocus() to return foo, we have to keep track of "pending" focus
3030 gs_pendingFocus
= this;
3032 GtkWidget
*widget
= m_wxwindow
? m_wxwindow
: m_focusWidget
;
3034 if ( GTK_IS_CONTAINER(widget
) &&
3035 !GTK_WIDGET_CAN_FOCUS(widget
) )
3037 wxLogTrace(TRACE_FOCUS
,
3038 _T("Setting focus to a child of %s(%p, %s)"),
3039 GetClassInfo()->GetClassName(), this, GetLabel().c_str());
3040 gtk_widget_child_focus(widget
, GTK_DIR_TAB_FORWARD
);
3044 wxLogTrace(TRACE_FOCUS
,
3045 _T("Setting focus to %s(%p, %s)"),
3046 GetClassInfo()->GetClassName(), this, GetLabel().c_str());
3047 gtk_widget_grab_focus(widget
);
3051 void wxWindowGTK::SetCanFocus(bool canFocus
)
3054 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3056 GTK_WIDGET_UNSET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3058 if ( m_wxwindow
&& (m_widget
!= m_wxwindow
) )
3061 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3063 GTK_WIDGET_UNSET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3067 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3069 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3071 wxWindowGTK
*oldParent
= m_parent
,
3072 *newParent
= (wxWindowGTK
*)newParentBase
;
3074 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3076 if ( !wxWindowBase::Reparent(newParent
) )
3079 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3081 /* prevent GTK from deleting the widget arbitrarily */
3082 gtk_widget_ref( m_widget
);
3086 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3089 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3093 if (GTK_WIDGET_VISIBLE (newParent
->m_widget
))
3095 m_showOnIdle
= true;
3096 gtk_widget_hide( m_widget
);
3099 /* insert GTK representation */
3100 (*(newParent
->m_insertCallback
))(newParent
, this);
3103 /* reverse: prevent GTK from deleting the widget arbitrarily */
3104 gtk_widget_unref( m_widget
);
3106 SetLayoutDirection(wxLayout_Default
);
3111 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3113 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3114 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3119 /* insert GTK representation */
3120 (*m_insertCallback
)(this, child
);
3123 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3125 wxWindowBase::AddChild(child
);
3126 m_dirtyTabOrder
= true;
3127 wxTheApp
->WakeUpIdle();
3130 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3132 wxWindowBase::RemoveChild(child
);
3133 m_dirtyTabOrder
= true;
3134 wxTheApp
->WakeUpIdle();
3138 wxLayoutDirection
wxWindowGTK::GTKGetLayout(GtkWidget
*widget
)
3140 return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
3141 ? wxLayout_RightToLeft
3142 : wxLayout_LeftToRight
;
3146 void wxWindowGTK::GTKSetLayout(GtkWidget
*widget
, wxLayoutDirection dir
)
3148 wxASSERT_MSG( dir
!= wxLayout_Default
, _T("invalid layout direction") );
3150 gtk_widget_set_direction(widget
,
3151 dir
== wxLayout_RightToLeft
? GTK_TEXT_DIR_RTL
3152 : GTK_TEXT_DIR_LTR
);
3155 wxLayoutDirection
wxWindowGTK::GetLayoutDirection() const
3157 return GTKGetLayout(m_widget
);
3160 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
)
3162 if ( dir
== wxLayout_Default
)
3164 const wxWindow
*const parent
= GetParent();
3167 // inherit layout from parent.
3168 dir
= parent
->GetLayoutDirection();
3170 else // no parent, use global default layout
3172 dir
= wxTheApp
->GetLayoutDirection();
3176 if ( dir
== wxLayout_Default
)
3179 GTKSetLayout(m_widget
, dir
);
3181 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3182 GTKSetLayout(m_wxwindow
, dir
);
3186 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
,
3187 wxCoord
WXUNUSED(width
),
3188 wxCoord
WXUNUSED(widthTotal
)) const
3190 // We now mirror the coordinates of RTL windows in wxPizza
3194 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, WindowOrder move
)
3196 wxWindowBase::DoMoveInTabOrder(win
, move
);
3197 m_dirtyTabOrder
= true;
3198 wxTheApp
->WakeUpIdle();
3201 bool wxWindowGTK::DoNavigateIn(int flags
)
3203 if ( flags
& wxNavigationKeyEvent::WinChange
)
3205 wxFAIL_MSG( _T("not implemented") );
3209 else // navigate inside the container
3211 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3212 wxCHECK_MSG( parent
, false, _T("every window must have a TLW parent") );
3214 GtkDirectionType dir
;
3215 dir
= flags
& wxNavigationKeyEvent::IsForward
? GTK_DIR_TAB_FORWARD
3216 : GTK_DIR_TAB_BACKWARD
;
3219 g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
);
3225 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3227 // none needed by default
3231 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3233 // nothing to do by default since none is needed
3236 void wxWindowGTK::RealizeTabOrder()
3240 if ( !m_children
.empty() )
3242 // we don't only construct the correct focus chain but also use
3243 // this opportunity to update the mnemonic widgets for the widgets
3246 GList
*chain
= NULL
;
3247 wxWindowGTK
* mnemonicWindow
= NULL
;
3249 for ( wxWindowList::const_iterator i
= m_children
.begin();
3250 i
!= m_children
.end();
3253 wxWindowGTK
*win
= *i
;
3255 if ( mnemonicWindow
)
3257 if ( win
->AcceptsFocusFromKeyboard() )
3259 // wxComboBox et al. needs to focus on on a different
3260 // widget than m_widget, so if the main widget isn't
3261 // focusable try the connect widget
3262 GtkWidget
* w
= win
->m_widget
;
3263 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3265 w
= win
->GetConnectWidget();
3266 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3272 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3273 mnemonicWindow
= NULL
;
3277 else if ( win
->GTKWidgetNeedsMnemonic() )
3279 mnemonicWindow
= win
;
3282 chain
= g_list_prepend(chain
, win
->m_widget
);
3285 chain
= g_list_reverse(chain
);
3287 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3292 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3297 void wxWindowGTK::Raise()
3299 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3301 if (m_wxwindow
&& m_wxwindow
->window
)
3303 gdk_window_raise( m_wxwindow
->window
);
3305 else if (m_widget
->window
)
3307 gdk_window_raise( m_widget
->window
);
3311 void wxWindowGTK::Lower()
3313 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3315 if (m_wxwindow
&& m_wxwindow
->window
)
3317 gdk_window_lower( m_wxwindow
->window
);
3319 else if (m_widget
->window
)
3321 gdk_window_lower( m_widget
->window
);
3325 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3327 if ( !wxWindowBase::SetCursor(cursor
.Ok() ? cursor
: *wxSTANDARD_CURSOR
) )
3335 void wxWindowGTK::GTKUpdateCursor()
3337 wxCursor
cursor(g_globalCursor
.Ok() ? g_globalCursor
: GetCursor());
3340 wxArrayGdkWindows windowsThis
;
3341 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3344 gdk_window_set_cursor(winThis
, cursor
.GetCursor());
3348 const size_t count
= windowsThis
.size();
3349 for ( size_t n
= 0; n
< count
; n
++ )
3351 GdkWindow
*win
= windowsThis
[n
];
3354 wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?"));
3358 gdk_window_set_cursor(win
, cursor
.GetCursor());
3364 void wxWindowGTK::WarpPointer( int x
, int y
)
3366 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3368 // We provide this function ourselves as it is
3369 // missing in GDK (top of this file).
3371 GdkWindow
*window
= (GdkWindow
*) NULL
;
3373 window
= m_wxwindow
->window
;
3375 window
= GetConnectWidget()->window
;
3378 gdk_window_warp_pointer( window
, x
, y
);
3381 wxWindowGTK::ScrollDir
wxWindowGTK::ScrollDirFromRange(GtkRange
*range
) const
3383 // find the scrollbar which generated the event
3384 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3386 if ( range
== m_scrollBar
[dir
] )
3387 return (ScrollDir
)dir
;
3390 wxFAIL_MSG( _T("event from unknown scrollbar received") );
3392 return ScrollDir_Max
;
3395 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3397 bool changed
= false;
3398 GtkRange
* range
= m_scrollBar
[dir
];
3399 if ( range
&& units
)
3401 GtkAdjustment
* adj
= range
->adjustment
;
3402 gdouble inc
= unit
== ScrollUnit_Line
? adj
->step_increment
3403 : adj
->page_increment
;
3405 const int posOld
= int(adj
->value
+ 0.5);
3406 gtk_range_set_value(range
, posOld
+ units
*inc
);
3408 changed
= int(adj
->value
+ 0.5) != posOld
;
3414 bool wxWindowGTK::ScrollLines(int lines
)
3416 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3419 bool wxWindowGTK::ScrollPages(int pages
)
3421 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3424 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground
),
3429 if (!m_widget
->window
)
3434 if (m_wxwindow
->window
== NULL
) return;
3436 GdkRectangle gdk_rect
,
3440 gdk_rect
.x
= rect
->x
;
3441 gdk_rect
.y
= rect
->y
;
3442 gdk_rect
.width
= rect
->width
;
3443 gdk_rect
.height
= rect
->height
;
3444 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3445 gdk_rect
.x
= GetClientSize().x
- gdk_rect
.x
- gdk_rect
.width
;
3449 else // invalidate everything
3454 gdk_window_invalidate_rect(m_wxwindow
->window
, p
, true);
3458 void wxWindowGTK::Update()
3462 // when we call Update() we really want to update the window immediately on
3463 // screen, even if it means flushing the entire queue and hence slowing down
3464 // everything -- but it should still be done, it's just that Update() should
3465 // be called very rarely
3469 void wxWindowGTK::GtkUpdate()
3471 if (m_wxwindow
&& m_wxwindow
->window
)
3472 gdk_window_process_updates(m_wxwindow
->window
, false);
3473 if (m_widget
&& m_widget
->window
&& (m_wxwindow
!= m_widget
))
3474 gdk_window_process_updates( m_widget
->window
, FALSE
);
3476 // for consistency with other platforms (and also because it's convenient
3477 // to be able to update an entire TLW by calling Update() only once), we
3478 // should also update all our children here
3479 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3481 node
= node
->GetNext() )
3483 node
->GetData()->GtkUpdate();
3487 bool wxWindowGTK::DoIsExposed( int x
, int y
) const
3489 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
3493 bool wxWindowGTK::DoIsExposed( int x
, int y
, int w
, int h
) const
3495 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3496 return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
;
3498 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
3501 void wxWindowGTK::GtkSendPaintEvents()
3505 m_updateRegion
.Clear();
3509 // Clip to paint region in wxClientDC
3510 m_clipPaintRegion
= true;
3512 m_nativeUpdateRegion
= m_updateRegion
;
3514 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3516 // Transform m_updateRegion under RTL
3517 m_updateRegion
.Clear();
3520 gdk_drawable_get_size(m_wxwindow
->window
, &width
, NULL
);
3522 wxRegionIterator
upd( m_nativeUpdateRegion
);
3526 rect
.x
= upd
.GetX();
3527 rect
.y
= upd
.GetY();
3528 rect
.width
= upd
.GetWidth();
3529 rect
.height
= upd
.GetHeight();
3531 rect
.x
= width
- rect
.x
- rect
.width
;
3532 m_updateRegion
.Union( rect
);
3538 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3540 // find ancestor from which to steal background
3541 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3543 parent
= (wxWindow
*)this;
3545 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3547 wxRegionIterator
upd( m_nativeUpdateRegion
);
3551 rect
.x
= upd
.GetX();
3552 rect
.y
= upd
.GetY();
3553 rect
.width
= upd
.GetWidth();
3554 rect
.height
= upd
.GetHeight();
3556 gtk_paint_flat_box( parent
->m_widget
->style
,
3558 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3571 wxWindowDC
dc( (wxWindow
*)this );
3572 dc
.SetDeviceClippingRegion( m_updateRegion
);
3574 // Work around gtk-qt <= 0.60 bug whereby the window colour
3576 if (GetBackgroundStyle() == wxBG_STYLE_COLOUR
&& GetBackgroundColour().Ok() && wxSystemOptions::GetOptionInt(wxT("gtk.window.force-background-colour")) == 1)
3578 dc
.SetBackground(wxBrush(GetBackgroundColour()));
3582 wxEraseEvent
erase_event( GetId(), &dc
);
3583 erase_event
.SetEventObject( this );
3585 HandleWindowEvent(erase_event
);
3588 wxNcPaintEvent
nc_paint_event( GetId() );
3589 nc_paint_event
.SetEventObject( this );
3590 HandleWindowEvent( nc_paint_event
);
3592 wxPaintEvent
paint_event( GetId() );
3593 paint_event
.SetEventObject( this );
3594 HandleWindowEvent( paint_event
);
3596 m_clipPaintRegion
= false;
3598 m_updateRegion
.Clear();
3599 m_nativeUpdateRegion
.Clear();
3602 void wxWindowGTK::SetDoubleBuffered( bool on
)
3604 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3607 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3610 bool wxWindowGTK::IsDoubleBuffered() const
3612 return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow
);
3615 void wxWindowGTK::ClearBackground()
3617 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3621 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3623 wxWindowBase::DoSetToolTip(tip
);
3626 m_tooltip
->Apply( (wxWindow
*)this );
3629 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const gchar
*tip
)
3631 gtk_tooltips_set_tip(tips
, GetConnectWidget(), tip
, NULL
);
3633 #endif // wxUSE_TOOLTIPS
3635 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3637 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3639 if (!wxWindowBase::SetBackgroundColour(colour
))
3644 // We need the pixel value e.g. for background clearing.
3645 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3648 // apply style change (forceStyle=true so that new style is applied
3649 // even if the bg colour changed from valid to wxNullColour)
3650 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3651 ApplyWidgetStyle(true);
3656 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3658 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3660 if (!wxWindowBase::SetForegroundColour(colour
))
3667 // We need the pixel value e.g. for background clearing.
3668 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3671 // apply style change (forceStyle=true so that new style is applied
3672 // even if the bg colour changed from valid to wxNullColour):
3673 ApplyWidgetStyle(true);
3678 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3680 return gtk_widget_get_pango_context( m_widget
);
3683 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3685 // do we need to apply any changes at all?
3688 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3693 GtkRcStyle
*style
= gtk_rc_style_new();
3698 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3701 int flagsNormal
= 0,
3704 flagsInsensitive
= 0;
3706 if ( m_foregroundColour
.Ok() )
3708 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3710 style
->fg
[GTK_STATE_NORMAL
] =
3711 style
->text
[GTK_STATE_NORMAL
] = *fg
;
3712 flagsNormal
|= GTK_RC_FG
| GTK_RC_TEXT
;
3714 style
->fg
[GTK_STATE_PRELIGHT
] =
3715 style
->text
[GTK_STATE_PRELIGHT
] = *fg
;
3716 flagsPrelight
|= GTK_RC_FG
| GTK_RC_TEXT
;
3718 style
->fg
[GTK_STATE_ACTIVE
] =
3719 style
->text
[GTK_STATE_ACTIVE
] = *fg
;
3720 flagsActive
|= GTK_RC_FG
| GTK_RC_TEXT
;
3723 if ( m_backgroundColour
.Ok() )
3725 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3727 style
->bg
[GTK_STATE_NORMAL
] =
3728 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3729 flagsNormal
|= GTK_RC_BG
| GTK_RC_BASE
;
3731 style
->bg
[GTK_STATE_PRELIGHT
] =
3732 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3733 flagsPrelight
|= GTK_RC_BG
| GTK_RC_BASE
;
3735 style
->bg
[GTK_STATE_ACTIVE
] =
3736 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3737 flagsActive
|= GTK_RC_BG
| GTK_RC_BASE
;
3739 style
->bg
[GTK_STATE_INSENSITIVE
] =
3740 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3741 flagsInsensitive
|= GTK_RC_BG
| GTK_RC_BASE
;
3744 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
;
3745 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
;
3746 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
;
3747 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
;
3752 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3754 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3757 DoApplyWidgetStyle(style
);
3758 gtk_rc_style_unref(style
);
3761 // Style change may affect GTK+'s size calculation:
3762 InvalidateBestSize();
3765 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3767 wxSuspendStyleEvents
s(static_cast<wxWindow
*>(this));
3770 gtk_widget_modify_style(m_wxwindow
, style
);
3772 gtk_widget_modify_style(m_widget
, style
);
3775 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3777 wxWindowBase::SetBackgroundStyle(style
);
3779 if (style
== wxBG_STYLE_CUSTOM
)
3784 window
= m_wxwindow
->window
;
3788 GtkWidget
* const w
= GetConnectWidget();
3789 window
= w
? w
->window
: NULL
;
3794 // Make sure GDK/X11 doesn't refresh the window
3796 gdk_window_set_back_pixmap( window
, None
, False
);
3798 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3801 m_needsStyleChange
= false;
3803 else // window not realized yet
3805 // Do in OnIdle, because the window is not yet available
3806 m_needsStyleChange
= true;
3809 // Don't apply widget style, or we get a grey background
3813 // apply style change (forceStyle=true so that new style is applied
3814 // even if the bg colour changed from valid to wxNullColour):
3815 ApplyWidgetStyle(true);
3820 // ----------------------------------------------------------------------------
3821 // Pop-up menu stuff
3822 // ----------------------------------------------------------------------------
3824 #if wxUSE_MENUS_NATIVE
3826 static void SetInvokingWindow( wxMenu
*menu
, wxWindow
* win
)
3828 menu
->SetInvokingWindow( win
);
3830 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
3833 wxMenuItem
*menuitem
= node
->GetData();
3834 if (menuitem
->IsSubMenu())
3836 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3839 node
= node
->GetNext();
3845 void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3847 gboolean
* WXUNUSED(whatever
),
3848 gpointer user_data
)
3850 // ensure that the menu appears entirely on screen
3852 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3854 wxSize sizeScreen
= wxGetDisplaySize();
3855 wxPoint
*pos
= (wxPoint
*)user_data
;
3857 gint xmax
= sizeScreen
.x
- req
.width
,
3858 ymax
= sizeScreen
.y
- req
.height
;
3860 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
3861 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
3865 void wxWindowGTK::DoPopupMenuUpdateUI(wxMenu
* menu
)
3870 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3872 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3874 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
3876 SetInvokingWindow( menu
, this );
3878 DoPopupMenuUpdateUI(menu
);
3882 GtkMenuPositionFunc posfunc
;
3883 if ( x
== -1 && y
== -1 )
3885 // use GTK's default positioning algorithm
3891 pos
= ClientToScreen(wxPoint(x
, y
));
3893 posfunc
= wxPopupMenuPositionCallback
;
3896 menu
->m_popupShown
= true;
3898 GTK_MENU(menu
->m_menu
),
3899 (GtkWidget
*) NULL
, // parent menu shell
3900 (GtkWidget
*) NULL
, // parent menu item
3901 posfunc
, // function to position it
3902 userdata
, // client data
3903 0, // button used to activate it
3904 gtk_get_current_event_time()
3907 while (menu
->m_popupShown
)
3909 gtk_main_iteration();
3915 #endif // wxUSE_MENUS_NATIVE
3917 #if wxUSE_DRAG_AND_DROP
3919 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3921 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3923 GtkWidget
*dnd_widget
= GetConnectWidget();
3925 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3927 if (m_dropTarget
) delete m_dropTarget
;
3928 m_dropTarget
= dropTarget
;
3930 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3933 #endif // wxUSE_DRAG_AND_DROP
3935 GtkWidget
* wxWindowGTK::GetConnectWidget()
3937 GtkWidget
*connect_widget
= m_widget
;
3938 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3940 return connect_widget
;
3943 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow
*window
) const
3945 wxArrayGdkWindows windowsThis
;
3946 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3948 return winThis
? window
== winThis
3949 : windowsThis
.Index(window
) != wxNOT_FOUND
;
3952 GdkWindow
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
3954 return m_wxwindow
? m_wxwindow
->window
: m_widget
->window
;
3957 bool wxWindowGTK::SetFont( const wxFont
&font
)
3959 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3961 if (!wxWindowBase::SetFont(font
))
3964 // apply style change (forceStyle=true so that new style is applied
3965 // even if the font changed from valid to wxNullFont):
3966 ApplyWidgetStyle(true);
3971 void wxWindowGTK::DoCaptureMouse()
3973 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3975 GdkWindow
*window
= (GdkWindow
*) NULL
;
3977 window
= m_wxwindow
->window
;
3979 window
= GetConnectWidget()->window
;
3981 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3983 const wxCursor
* cursor
= &m_cursor
;
3985 cursor
= wxSTANDARD_CURSOR
;
3987 gdk_pointer_grab( window
, FALSE
,
3989 (GDK_BUTTON_PRESS_MASK
|
3990 GDK_BUTTON_RELEASE_MASK
|
3991 GDK_POINTER_MOTION_HINT_MASK
|
3992 GDK_POINTER_MOTION_MASK
),
3994 cursor
->GetCursor(),
3995 (guint32
)GDK_CURRENT_TIME
);
3996 g_captureWindow
= this;
3997 g_captureWindowHasMouse
= true;
4000 void wxWindowGTK::DoReleaseMouse()
4002 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4004 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4006 g_captureWindow
= (wxWindowGTK
*) NULL
;
4008 GdkWindow
*window
= (GdkWindow
*) NULL
;
4010 window
= m_wxwindow
->window
;
4012 window
= GetConnectWidget()->window
;
4017 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4020 void wxWindowGTK::GTKReleaseMouseAndNotify()
4023 wxMouseCaptureLostEvent
evt(GetId());
4024 evt
.SetEventObject( this );
4025 HandleWindowEvent( evt
);
4029 wxWindow
*wxWindowBase::GetCapture()
4031 return (wxWindow
*)g_captureWindow
;
4034 bool wxWindowGTK::IsRetained() const
4039 void wxWindowGTK::SetScrollbar(int orient
,
4043 bool WXUNUSED(update
))
4045 const int dir
= ScrollDirFromOrient(orient
);
4046 GtkRange
* const sb
= m_scrollBar
[dir
];
4047 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4051 // GtkRange requires upper > lower
4056 GtkAdjustment
* const adj
= sb
->adjustment
;
4057 adj
->step_increment
= 1;
4058 adj
->page_increment
=
4059 adj
->page_size
= thumbVisible
;
4062 g_signal_handlers_block_by_func(
4063 sb
, (void*)gtk_scrollbar_value_changed
, this);
4065 gtk_range_set_range(sb
, 0, range
);
4066 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4068 g_signal_handlers_unblock_by_func(
4069 sb
, (void*)gtk_scrollbar_value_changed
, this);
4072 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4074 const int dir
= ScrollDirFromOrient(orient
);
4075 GtkRange
* const sb
= m_scrollBar
[dir
];
4076 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4078 // This check is more than an optimization. Without it, the slider
4079 // will not move smoothly while tracking when using wxScrollHelper.
4080 if (GetScrollPos(orient
) != pos
)
4082 g_signal_handlers_block_by_func(
4083 sb
, (void*)gtk_scrollbar_value_changed
, this);
4085 gtk_range_set_value(sb
, pos
);
4086 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4088 g_signal_handlers_unblock_by_func(
4089 sb
, (void*)gtk_scrollbar_value_changed
, this);
4093 int wxWindowGTK::GetScrollThumb(int orient
) const
4095 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4096 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4098 return int(sb
->adjustment
->page_size
);
4101 int wxWindowGTK::GetScrollPos( int orient
) const
4103 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4104 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4106 return int(sb
->adjustment
->value
+ 0.5);
4109 int wxWindowGTK::GetScrollRange( int orient
) const
4111 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4112 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4114 return int(sb
->adjustment
->upper
);
4117 // Determine if increment is the same as +/-x, allowing for some small
4118 // difference due to possible inexactness in floating point arithmetic
4119 static inline bool IsScrollIncrement(double increment
, double x
)
4121 wxASSERT(increment
> 0);
4122 const double tolerance
= 1.0 / 1024;
4123 return fabs(increment
- fabs(x
)) < tolerance
;
4126 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4128 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4130 const int barIndex
= range
== m_scrollBar
[1];
4131 GtkAdjustment
* adj
= range
->adjustment
;
4133 const int value
= int(adj
->value
+ 0.5);
4135 // save previous position
4136 const double oldPos
= m_scrollPos
[barIndex
];
4137 // update current position
4138 m_scrollPos
[barIndex
] = adj
->value
;
4139 // If event should be ignored, or integral position has not changed
4140 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4145 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4148 // Difference from last change event
4149 const double diff
= adj
->value
- oldPos
;
4150 const bool isDown
= diff
> 0;
4152 if (IsScrollIncrement(adj
->step_increment
, diff
))
4154 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4156 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4158 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4160 else if (m_mouseButtonDown
)
4162 // Assume track event
4163 m_isScrolling
= true;
4169 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4171 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4173 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4175 // No scrolling requested.
4176 if ((dx
== 0) && (dy
== 0)) return;
4178 m_clipPaintRegion
= true;
4180 WX_PIZZA(m_wxwindow
)->scroll(dx
, dy
);
4182 m_clipPaintRegion
= false;
4185 bool restoreCaret
= (GetCaret() != NULL
&& GetCaret()->IsVisible());
4188 wxRect
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4190 caretRect
.width
+= dx
;
4193 caretRect
.x
+= dx
; caretRect
.width
-= dx
;
4196 caretRect
.height
+= dy
;
4199 caretRect
.y
+= dy
; caretRect
.height
-= dy
;
4202 RefreshRect(caretRect
);
4204 #endif // wxUSE_CARET
4207 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4209 //RN: Note that static controls usually have no border on gtk, so maybe
4210 //it makes sense to treat that as simply no border at the wx level
4212 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4214 GtkShadowType gtkstyle
;
4216 if(wxstyle
& wxBORDER_RAISED
)
4217 gtkstyle
= GTK_SHADOW_OUT
;
4218 else if (wxstyle
& wxBORDER_SUNKEN
)
4219 gtkstyle
= GTK_SHADOW_IN
;
4222 else if (wxstyle
& wxBORDER_DOUBLE
)
4223 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4226 gtkstyle
= GTK_SHADOW_IN
;
4228 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4233 void wxWindowGTK::SetWindowStyleFlag( long style
)
4235 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4236 wxWindowBase::SetWindowStyleFlag(style
);
4239 // Find the wxWindow at the current mouse position, also returning the mouse
4241 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4243 pt
= wxGetMousePosition();
4244 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4248 // Get the current mouse position.
4249 wxPoint
wxGetMousePosition()
4251 /* This crashes when used within wxHelpContext,
4252 so we have to use the X-specific implementation below.
4254 GdkModifierType *mask;
4255 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4257 return wxPoint(x, y);
4261 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4263 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4264 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4265 Window rootReturn
, childReturn
;
4266 int rootX
, rootY
, winX
, winY
;
4267 unsigned int maskReturn
;
4269 XQueryPointer (display
,
4273 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4274 return wxPoint(rootX
, rootY
);
4278 GdkWindow
* wxWindowGTK::GTKGetDrawingWindow() const
4280 GdkWindow
* window
= NULL
;
4282 window
= m_wxwindow
->window
;
4286 // ----------------------------------------------------------------------------
4288 // ----------------------------------------------------------------------------
4293 // this is called if we attempted to freeze unrealized widget when it finally
4294 // is realized (and so can be frozen):
4295 static void wx_frozen_widget_realize(GtkWidget
* w
, void* WXUNUSED(data
))
4297 wxASSERT( w
&& !GTK_WIDGET_NO_WINDOW(w
) );
4298 wxASSERT( GTK_WIDGET_REALIZED(w
) );
4300 g_signal_handlers_disconnect_by_func
4303 (void*)wx_frozen_widget_realize
,
4307 gdk_window_freeze_updates(w
->window
);
4312 void wxWindowGTK::GTKFreezeWidget(GtkWidget
*w
)
4314 if ( !w
|| GTK_WIDGET_NO_WINDOW(w
) )
4315 return; // window-less widget, cannot be frozen
4317 if ( !GTK_WIDGET_REALIZED(w
) )
4319 // we can't thaw unrealized widgets because they don't have GdkWindow,
4320 // so set it up to be done immediately after realization:
4321 g_signal_connect_after
4325 G_CALLBACK(wx_frozen_widget_realize
),
4331 gdk_window_freeze_updates(w
->window
);
4334 void wxWindowGTK::GTKThawWidget(GtkWidget
*w
)
4336 if ( !w
|| GTK_WIDGET_NO_WINDOW(w
) )
4337 return; // window-less widget, cannot be frozen
4339 if ( !GTK_WIDGET_REALIZED(w
) )
4341 // the widget wasn't realized yet, no need to thaw
4342 g_signal_handlers_disconnect_by_func
4345 (void*)wx_frozen_widget_realize
,
4351 gdk_window_thaw_updates(w
->window
);
4354 void wxWindowGTK::DoFreeze()
4356 GTKFreezeWidget(m_widget
);
4357 if ( m_wxwindow
&& m_widget
!= m_wxwindow
)
4358 GTKFreezeWidget(m_wxwindow
);
4361 void wxWindowGTK::DoThaw()
4363 GTKThawWidget(m_widget
);
4364 if ( m_wxwindow
&& m_widget
!= m_wxwindow
)
4365 GTKThawWidget(m_wxwindow
);