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/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 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
190 // the last window which had the focus - this is normally never NULL (except
191 // if we never had focus at all) as even when g_focusWindow is NULL it still
192 // keeps its previous value
193 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
195 // If a window get the focus set but has not been realized
196 // yet, defer setting the focus to idle time.
197 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
199 // global variables because GTK+ DnD want to have the
200 // mouse event that caused it
201 GdkEvent
*g_lastMouseEvent
= (GdkEvent
*) NULL
;
202 int g_lastButtonNumber
= 0;
204 //-----------------------------------------------------------------------------
206 //-----------------------------------------------------------------------------
208 // the trace mask used for the focus debugging messages
209 #define TRACE_FOCUS _T("focus")
211 //-----------------------------------------------------------------------------
212 // missing gdk functions
213 //-----------------------------------------------------------------------------
216 gdk_window_warp_pointer (GdkWindow
*window
,
221 window
= gdk_get_default_root_window();
223 if (!GDK_WINDOW_DESTROYED(window
))
225 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
226 None
, /* not source window -> move from anywhere */
227 GDK_WINDOW_XID(window
), /* dest window */
228 0, 0, 0, 0, /* not source window -> move from anywhere */
233 //-----------------------------------------------------------------------------
234 // local code (see below)
235 //-----------------------------------------------------------------------------
237 // returns the child of win which currently has focus or NULL if not found
239 // Note: can't be static, needed by textctrl.cpp.
240 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
242 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
244 return (wxWindow
*)NULL
;
246 if ( winFocus
== win
)
247 return (wxWindow
*)win
;
249 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
251 node
= node
->GetNext() )
253 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
258 return (wxWindow
*)NULL
;
261 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
)
263 GtkScrolledWindow
* scroll_window
= GTK_SCROLLED_WINDOW(widget
);
264 GtkScrolledWindowClass
* scroll_class
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
));
265 GtkRequisition scroll_req
;
268 if (scroll_window
->vscrollbar_visible
)
270 scroll_req
.width
= 2;
271 scroll_req
.height
= 2;
272 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
273 (scroll_window
->vscrollbar
, &scroll_req
);
274 w
= scroll_req
.width
+
275 scroll_class
->scrollbar_spacing
;
279 if (scroll_window
->hscrollbar_visible
)
281 scroll_req
.width
= 2;
282 scroll_req
.height
= 2;
283 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
284 (scroll_window
->hscrollbar
, &scroll_req
);
285 h
= scroll_req
.height
+
286 scroll_class
->scrollbar_spacing
;
290 //-----------------------------------------------------------------------------
291 // "size_request" of m_widget
292 //-----------------------------------------------------------------------------
294 // make it extern because wxStaticText needs to disconnect this one
296 void wxgtk_window_size_request_callback(GtkWidget
* WXUNUSED(widget
),
297 GtkRequisition
*requisition
,
301 win
->GetSize( &w
, &h
);
307 requisition
->height
= h
;
308 requisition
->width
= w
;
312 //-----------------------------------------------------------------------------
313 // "expose_event" of m_wxwindow
314 //-----------------------------------------------------------------------------
318 gtk_window_expose_callback( GtkWidget
*,
319 GdkEventExpose
*gdk_event
,
325 wxPrintf( wxT("OnExpose from ") );
326 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
327 wxPrintf( win
->GetClassInfo()->GetClassName() );
328 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
329 (int)gdk_event
->area
.y
,
330 (int)gdk_event
->area
.width
,
331 (int)gdk_event
->area
.height
);
336 win
->m_wxwindow
->style
,
340 (GdkRectangle
*) NULL
,
342 (char *)"button", // const_cast
347 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
349 win
->GtkSendPaintEvents();
351 // Let parent window draw window-less widgets
356 //-----------------------------------------------------------------------------
357 // "expose_event" from m_widget, for drawing border
358 //-----------------------------------------------------------------------------
360 #ifndef __WXUNIVERSAL__
362 GtkWidget
* GetEntryWidget();
366 expose_event_border(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxWindow
* win
)
368 // if this event is not for the GdkWindow the border is drawn on
369 if (win
->m_wxwindow
== win
->m_widget
&& gdk_event
->window
== widget
->window
)
374 // GtkScrolledWindow is GTK_NO_WINDOW
375 if (GTK_WIDGET_NO_WINDOW(widget
))
377 x
= widget
->allocation
.x
;
378 y
= widget
->allocation
.y
;
380 int w
= win
->m_wxwindow
->allocation
.width
;
381 int h
= win
->m_wxwindow
->allocation
.height
;
382 if (win
->HasFlag(wxBORDER_SIMPLE
))
384 GdkGC
* gc
= gdk_gc_new(gdk_event
->window
);
385 gdk_gc_set_foreground(gc
, &widget
->style
->black
);
386 gdk_draw_rectangle(gdk_event
->window
, gc
, false, x
, y
, w
- 1, h
- 1);
391 GtkShadowType shadow
= GTK_SHADOW_IN
;
392 if (win
->HasFlag(wxBORDER_RAISED
))
393 shadow
= GTK_SHADOW_OUT
;
395 // Style detail to use
397 if (widget
== win
->m_wxwindow
)
398 // for non-scrollable wxWindows
401 // for scrollable ones
404 GtkWidget
* styleWidget
= GetEntryWidget();
406 styleWidget
->style
, gdk_event
->window
, GTK_STATE_NORMAL
,
407 shadow
, NULL
, styleWidget
, detail
, x
, y
, w
, h
);
410 // no further painting is needed for border-only GdkWindow
411 return win
->m_wxwindow
== win
->m_widget
;
414 #endif // !__WXUNIVERSAL__
416 //-----------------------------------------------------------------------------
417 // "key_press_event" from any window
418 //-----------------------------------------------------------------------------
420 // These are used when transforming Ctrl-alpha to ascii values 1-26
421 inline bool wxIsLowerChar(int code
)
423 return (code
>= 'a' && code
<= 'z' );
426 inline bool wxIsUpperChar(int code
)
428 return (code
>= 'A' && code
<= 'Z' );
432 // set WXTRACE to this to see the key event codes on the console
433 #define TRACE_KEYS _T("keyevent")
435 // translates an X key symbol to WXK_XXX value
437 // if isChar is true it means that the value returned will be used for EVT_CHAR
438 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
439 // for example, while if it is false it means that the value is going to be
440 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
442 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
448 // Shift, Control and Alt don't generate the CHAR events at all
451 key_code
= isChar
? 0 : WXK_SHIFT
;
455 key_code
= isChar
? 0 : WXK_CONTROL
;
463 key_code
= isChar
? 0 : WXK_ALT
;
466 // neither do the toggle modifies
467 case GDK_Scroll_Lock
:
468 key_code
= isChar
? 0 : WXK_SCROLL
;
472 key_code
= isChar
? 0 : WXK_CAPITAL
;
476 key_code
= isChar
? 0 : WXK_NUMLOCK
;
480 // various other special keys
493 case GDK_ISO_Left_Tab
:
500 key_code
= WXK_RETURN
;
504 key_code
= WXK_CLEAR
;
508 key_code
= WXK_PAUSE
;
512 key_code
= WXK_SELECT
;
516 key_code
= WXK_PRINT
;
520 key_code
= WXK_EXECUTE
;
524 key_code
= WXK_ESCAPE
;
527 // cursor and other extended keyboard keys
529 key_code
= WXK_DELETE
;
545 key_code
= WXK_RIGHT
;
552 case GDK_Prior
: // == GDK_Page_Up
553 key_code
= WXK_PAGEUP
;
556 case GDK_Next
: // == GDK_Page_Down
557 key_code
= WXK_PAGEDOWN
;
569 key_code
= WXK_INSERT
;
584 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
588 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
592 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
596 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
600 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
604 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
608 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
612 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
616 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
620 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
624 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
628 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
632 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
635 case GDK_KP_Prior
: // == GDK_KP_Page_Up
636 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
639 case GDK_KP_Next
: // == GDK_KP_Page_Down
640 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
644 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
648 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
652 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
656 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
660 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
663 case GDK_KP_Multiply
:
664 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
668 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
671 case GDK_KP_Separator
:
672 // FIXME: what is this?
673 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
676 case GDK_KP_Subtract
:
677 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
681 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
685 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
702 key_code
= WXK_F1
+ keysym
- GDK_F1
;
712 static inline bool wxIsAsciiKeysym(KeySym ks
)
717 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
719 GdkEventKey
*gdk_event
)
723 GdkModifierType state
;
724 if (gdk_event
->window
)
725 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
727 event
.SetTimestamp( gdk_event
->time
);
728 event
.SetId(win
->GetId());
729 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
730 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
731 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
732 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
733 event
.m_scanCode
= gdk_event
->keyval
;
734 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
735 event
.m_rawFlags
= 0;
737 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
739 wxGetMousePosition( &x
, &y
);
740 win
->ScreenToClient( &x
, &y
);
743 event
.SetEventObject( win
);
748 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
750 GdkEventKey
*gdk_event
)
752 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
753 // but only event->keyval which is quite useless to us, so remember
754 // the last character from GDK_KEY_PRESS and reuse it as last resort
756 // NB: should be MT-safe as we're always called from the main thread only
761 } s_lastKeyPress
= { 0, 0 };
763 KeySym keysym
= gdk_event
->keyval
;
765 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
766 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
770 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
774 // do we have the translation or is it a plain ASCII character?
775 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
777 // we should use keysym if it is ASCII as X does some translations
778 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
779 // which we don't want here (but which we do use for OnChar())
780 if ( !wxIsAsciiKeysym(keysym
) )
782 keysym
= (KeySym
)gdk_event
->string
[0];
785 // we want to always get the same key code when the same key is
786 // pressed regardless of the state of the modifiers, i.e. on a
787 // standard US keyboard pressing '5' or '%' ('5' key with
788 // Shift) should result in the same key code in OnKeyDown():
789 // '5' (although OnChar() will get either '5' or '%').
791 // to do it we first translate keysym to keycode (== scan code)
792 // and then back but always using the lower register
793 Display
*dpy
= (Display
*)wxGetDisplay();
794 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
796 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
798 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
800 // use the normalized, i.e. lower register, keysym if we've
802 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
804 // as explained above, we want to have lower register key codes
805 // normally but for the letter keys we want to have the upper ones
807 // NB: don't use XConvertCase() here, we want to do it for letters
809 key_code
= toupper(key_code
);
811 else // non ASCII key, what to do?
813 // by default, ignore it
816 // but if we have cached information from the last KEY_PRESS
817 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
820 if ( keysym
== s_lastKeyPress
.keysym
)
822 key_code
= s_lastKeyPress
.keycode
;
827 if ( gdk_event
->type
== GDK_KEY_PRESS
)
829 // remember it to be reused for KEY_UP event later
830 s_lastKeyPress
.keysym
= keysym
;
831 s_lastKeyPress
.keycode
= key_code
;
835 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
837 // sending unknown key events doesn't really make sense
841 // now fill all the other fields
842 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
844 event
.m_keyCode
= key_code
;
846 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
848 event
.m_uniChar
= key_code
;
858 GtkIMContext
*context
;
859 GdkEventKey
*lastKeyEvent
;
863 context
= gtk_im_multicontext_new();
868 g_object_unref (context
);
874 gtk_window_key_press_callback( GtkWidget
*widget
,
875 GdkEventKey
*gdk_event
,
880 if (g_blockEventsOnDrag
)
883 // GTK+ sends keypress events to the focus widget and then
884 // to all its parent and grandparent widget. We only want
885 // the key events from the focus widget.
886 if (!GTK_WIDGET_HAS_FOCUS(widget
))
889 wxKeyEvent
event( wxEVT_KEY_DOWN
);
891 bool return_after_IM
= false;
893 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
895 // Emit KEY_DOWN event
896 ret
= win
->HandleWindowEvent( event
);
900 // Return after IM processing as we cannot do
901 // anything with it anyhow.
902 return_after_IM
= true;
905 if ((!ret
) && (win
->m_imData
!= NULL
))
907 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
908 // docs, if IM filter returns true, no further processing should be done.
909 // we should send the key_down event anyway.
910 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
911 win
->m_imData
->lastKeyEvent
= NULL
;
912 if (intercepted_by_IM
)
914 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
925 wxWindowGTK
*ancestor
= win
;
928 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
931 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
932 ret
= ancestor
->HandleWindowEvent( command_event
);
935 if (ancestor
->IsTopLevel())
937 ancestor
= ancestor
->GetParent();
940 #endif // wxUSE_ACCEL
942 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
943 // will only be sent if it is not in an accelerator table.
947 KeySym keysym
= gdk_event
->keyval
;
948 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
949 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
952 if ( wxIsAsciiKeysym(keysym
) )
955 key_code
= (unsigned char)keysym
;
957 // gdk_event->string is actually deprecated
958 else if ( gdk_event
->length
== 1 )
960 key_code
= (unsigned char)gdk_event
->string
[0];
966 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
968 event
.m_keyCode
= key_code
;
970 // To conform to the docs we need to translate Ctrl-alpha
971 // characters to values in the range 1-26.
972 if ( event
.ControlDown() &&
973 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
975 if ( wxIsLowerChar(key_code
) )
976 event
.m_keyCode
= key_code
- 'a' + 1;
977 if ( wxIsUpperChar(key_code
) )
978 event
.m_keyCode
= key_code
- 'A' + 1;
980 event
.m_uniChar
= event
.m_keyCode
;
984 // Implement OnCharHook by checking ancestor top level windows
985 wxWindow
*parent
= win
;
986 while (parent
&& !parent
->IsTopLevel())
987 parent
= parent
->GetParent();
990 event
.SetEventType( wxEVT_CHAR_HOOK
);
991 ret
= parent
->HandleWindowEvent( event
);
996 event
.SetEventType(wxEVT_CHAR
);
997 ret
= win
->HandleWindowEvent( event
);
1008 gtk_wxwindow_commit_cb (GtkIMContext
* WXUNUSED(context
),
1012 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1014 // take modifiers, cursor position, timestamp etc. from the last
1015 // key_press_event that was fed into Input Method:
1016 if (window
->m_imData
->lastKeyEvent
)
1018 wxFillOtherKeyEventFields(event
,
1019 window
, window
->m_imData
->lastKeyEvent
);
1023 event
.SetEventObject( window
);
1026 const wxString
data(wxGTK_CONV_BACK_SYS(str
));
1032 // Implement OnCharHook by checking ancestor top level windows
1033 wxWindow
*parent
= window
;
1034 while (parent
&& !parent
->IsTopLevel())
1035 parent
= parent
->GetParent();
1037 for( wxString::const_iterator pstr
= data
.begin(); pstr
!= data
.end(); ++pstr
)
1040 event
.m_uniChar
= *pstr
;
1041 // Backward compatible for ISO-8859-1
1042 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1043 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1045 event
.m_keyCode
= (char)*pstr
;
1046 #endif // wxUSE_UNICODE
1048 // To conform to the docs we need to translate Ctrl-alpha
1049 // characters to values in the range 1-26.
1050 if ( event
.ControlDown() &&
1051 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
1053 if ( wxIsLowerChar(*pstr
) )
1054 event
.m_keyCode
= *pstr
- 'a' + 1;
1055 if ( wxIsUpperChar(*pstr
) )
1056 event
.m_keyCode
= *pstr
- 'A' + 1;
1058 event
.m_keyCode
= *pstr
- 'a' + 1;
1060 event
.m_uniChar
= event
.m_keyCode
;
1066 event
.SetEventType( wxEVT_CHAR_HOOK
);
1067 ret
= parent
->HandleWindowEvent( event
);
1072 event
.SetEventType(wxEVT_CHAR
);
1073 ret
= window
->HandleWindowEvent( event
);
1080 //-----------------------------------------------------------------------------
1081 // "key_release_event" from any window
1082 //-----------------------------------------------------------------------------
1086 gtk_window_key_release_callback( GtkWidget
* WXUNUSED(widget
),
1087 GdkEventKey
*gdk_event
,
1093 if (g_blockEventsOnDrag
)
1096 wxKeyEvent
event( wxEVT_KEY_UP
);
1097 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1099 // unknown key pressed, ignore (the event would be useless anyhow)
1103 return win
->GTKProcessEvent(event
);
1107 // ============================================================================
1109 // ============================================================================
1111 // ----------------------------------------------------------------------------
1112 // mouse event processing helpers
1113 // ----------------------------------------------------------------------------
1115 // init wxMouseEvent with the info from GdkEventXXX struct
1116 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1117 wxMouseEvent
& event
,
1120 event
.SetTimestamp( gdk_event
->time
);
1121 event
.m_shiftDown
= gdk_event
->state
& GDK_SHIFT_MASK
;
1122 event
.m_controlDown
= gdk_event
->state
& GDK_CONTROL_MASK
;
1123 event
.m_altDown
= gdk_event
->state
& GDK_MOD1_MASK
;
1124 event
.m_metaDown
= gdk_event
->state
& GDK_MOD2_MASK
;
1125 event
.m_leftDown
= gdk_event
->state
& GDK_BUTTON1_MASK
;
1126 event
.m_middleDown
= gdk_event
->state
& GDK_BUTTON2_MASK
;
1127 event
.m_rightDown
= gdk_event
->state
& GDK_BUTTON3_MASK
;
1128 event
.m_aux1Down
= gdk_event
->state
& GDK_BUTTON4_MASK
;
1129 event
.m_aux2Down
= gdk_event
->state
& GDK_BUTTON5_MASK
;
1131 wxPoint pt
= win
->GetClientAreaOrigin();
1132 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1133 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1135 if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
))
1137 // origin in the upper right corner
1138 int window_width
= win
->m_wxwindow
->allocation
.width
;
1139 event
.m_x
= window_width
- event
.m_x
;
1142 event
.SetEventObject( win
);
1143 event
.SetId( win
->GetId() );
1144 event
.SetTimestamp( gdk_event
->time
);
1147 static void AdjustEventButtonState(wxMouseEvent
& event
)
1149 // GDK reports the old state of the button for a button press event, but
1150 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1151 // for a LEFT_DOWN event, not FALSE, so we will invert
1152 // left/right/middleDown for the corresponding click events
1154 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1155 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1156 (event
.GetEventType() == wxEVT_LEFT_UP
))
1158 event
.m_leftDown
= !event
.m_leftDown
;
1162 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1163 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1164 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1166 event
.m_middleDown
= !event
.m_middleDown
;
1170 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1171 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1172 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1174 event
.m_rightDown
= !event
.m_rightDown
;
1179 // find the window to send the mouse event too
1181 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1186 if (win
->m_wxwindow
)
1188 wxPizza
* pizza
= WX_PIZZA(win
->m_wxwindow
);
1189 xx
+= pizza
->m_scroll_x
;
1190 yy
+= pizza
->m_scroll_y
;
1193 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1196 wxWindowGTK
*child
= node
->GetData();
1198 node
= node
->GetNext();
1199 if (!child
->IsShown())
1202 if (child
->IsTransparentForMouse())
1204 // wxStaticBox is transparent in the box itself
1205 int xx1
= child
->m_x
;
1206 int yy1
= child
->m_y
;
1207 int xx2
= child
->m_x
+ child
->m_width
;
1208 int yy2
= child
->m_y
+ child
->m_height
;
1211 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1213 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1215 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1217 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1228 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1229 (child
->m_x
<= xx
) &&
1230 (child
->m_y
<= yy
) &&
1231 (child
->m_x
+child
->m_width
>= xx
) &&
1232 (child
->m_y
+child
->m_height
>= yy
))
1245 // ----------------------------------------------------------------------------
1246 // common event handlers helpers
1247 // ----------------------------------------------------------------------------
1249 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const
1251 // nothing special at this level
1252 return HandleWindowEvent(event
);
1255 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1259 if (g_blockEventsOnDrag
)
1261 if (g_blockEventsOnScroll
)
1264 if (!GTKIsOwnWindow(event
->window
))
1270 // overloads for all GDK event types we use here: we need to have this as
1271 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1272 // derives from it in the sense that the structs have the same layout
1273 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1274 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1276 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1279 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1280 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1281 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1283 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1285 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1286 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1290 // send the wxChildFocusEvent and wxFocusEvent, common code of
1291 // gtk_window_focus_in_callback() and SetFocus()
1292 static bool DoSendFocusEvents(wxWindow
*win
)
1294 // Notify the parent keeping track of focus for the kbd navigation
1295 // purposes that we got it.
1296 wxChildFocusEvent
eventChildFocus(win
);
1297 (void)win
->HandleWindowEvent(eventChildFocus
);
1299 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1300 eventFocus
.SetEventObject(win
);
1302 return win
->HandleWindowEvent(eventFocus
);
1305 // all event handlers must have C linkage as they're called from GTK+ C code
1309 //-----------------------------------------------------------------------------
1310 // "button_press_event"
1311 //-----------------------------------------------------------------------------
1314 gtk_window_button_press_callback( GtkWidget
*widget
,
1315 GdkEventButton
*gdk_event
,
1318 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1320 g_lastButtonNumber
= gdk_event
->button
;
1322 // GDK sends surplus button down events
1323 // before a double click event. We
1324 // need to filter these out.
1325 if ((gdk_event
->type
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
))
1327 GdkEvent
*peek_event
= gdk_event_peek();
1330 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1331 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1333 gdk_event_free( peek_event
);
1338 gdk_event_free( peek_event
);
1343 wxEventType event_type
= wxEVT_NULL
;
1345 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1346 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1348 // Reset GDK internal timestamp variables in order to disable GDK
1349 // triple click events. GDK will then next time believe no button has
1350 // been clicked just before, and send a normal button click event.
1351 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1352 display
->button_click_time
[1] = 0;
1353 display
->button_click_time
[0] = 0;
1356 if (gdk_event
->button
== 1)
1358 // note that GDK generates triple click events which are not supported
1359 // by wxWidgets but still have to be passed to the app as otherwise
1360 // clicks would simply go missing
1361 switch (gdk_event
->type
)
1363 // we shouldn't get triple clicks at all for GTK2 because we
1364 // suppress them artificially using the code above but we still
1365 // should map them to something for GTK1 and not just ignore them
1366 // as this would lose clicks
1367 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1368 case GDK_BUTTON_PRESS
:
1369 event_type
= wxEVT_LEFT_DOWN
;
1372 case GDK_2BUTTON_PRESS
:
1373 event_type
= wxEVT_LEFT_DCLICK
;
1377 // just to silence gcc warnings
1381 else if (gdk_event
->button
== 2)
1383 switch (gdk_event
->type
)
1385 case GDK_3BUTTON_PRESS
:
1386 case GDK_BUTTON_PRESS
:
1387 event_type
= wxEVT_MIDDLE_DOWN
;
1390 case GDK_2BUTTON_PRESS
:
1391 event_type
= wxEVT_MIDDLE_DCLICK
;
1398 else if (gdk_event
->button
== 3)
1400 switch (gdk_event
->type
)
1402 case GDK_3BUTTON_PRESS
:
1403 case GDK_BUTTON_PRESS
:
1404 event_type
= wxEVT_RIGHT_DOWN
;
1407 case GDK_2BUTTON_PRESS
:
1408 event_type
= wxEVT_RIGHT_DCLICK
;
1416 if ( event_type
== wxEVT_NULL
)
1418 // unknown mouse button or click type
1422 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1424 wxMouseEvent
event( event_type
);
1425 InitMouseEvent( win
, event
, gdk_event
);
1427 AdjustEventButtonState(event
);
1429 // wxListBox actually gets mouse events from the item, so we need to give it
1430 // a chance to correct this
1431 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1433 // find the correct window to send the event to: it may be a different one
1434 // from the one which got it at GTK+ level because some controls don't have
1435 // their own X window and thus cannot get any events.
1436 if ( !g_captureWindow
)
1437 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1439 // reset the event object and id in case win changed.
1440 event
.SetEventObject( win
);
1441 event
.SetId( win
->GetId() );
1443 bool ret
= win
->GTKProcessEvent( event
);
1444 g_lastMouseEvent
= NULL
;
1448 if ((event_type
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&
1449 (g_focusWindow
!= win
) /* && win->IsFocusable() */)
1454 if (event_type
== wxEVT_RIGHT_DOWN
)
1456 // generate a "context menu" event: this is similar to right mouse
1457 // click under many GUIs except that it is generated differently
1458 // (right up under MSW, ctrl-click under Mac, right down here) and
1460 // (a) it's a command event and so is propagated to the parent
1461 // (b) under some ports it can be generated from kbd too
1462 // (c) it uses screen coords (because of (a))
1463 wxContextMenuEvent
evtCtx(
1466 win
->ClientToScreen(event
.GetPosition()));
1467 evtCtx
.SetEventObject(win
);
1468 return win
->GTKProcessEvent(evtCtx
);
1474 //-----------------------------------------------------------------------------
1475 // "button_release_event"
1476 //-----------------------------------------------------------------------------
1479 gtk_window_button_release_callback( GtkWidget
*widget
,
1480 GdkEventButton
*gdk_event
,
1483 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1485 g_lastButtonNumber
= 0;
1487 wxEventType event_type
= wxEVT_NULL
;
1489 switch (gdk_event
->button
)
1492 event_type
= wxEVT_LEFT_UP
;
1496 event_type
= wxEVT_MIDDLE_UP
;
1500 event_type
= wxEVT_RIGHT_UP
;
1504 // unknown button, don't process
1508 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1510 wxMouseEvent
event( event_type
);
1511 InitMouseEvent( win
, event
, gdk_event
);
1513 AdjustEventButtonState(event
);
1515 // same wxListBox hack as above
1516 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1518 if ( !g_captureWindow
)
1519 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1521 // reset the event object and id in case win changed.
1522 event
.SetEventObject( win
);
1523 event
.SetId( win
->GetId() );
1525 bool ret
= win
->GTKProcessEvent(event
);
1527 g_lastMouseEvent
= NULL
;
1532 //-----------------------------------------------------------------------------
1533 // "motion_notify_event"
1534 //-----------------------------------------------------------------------------
1537 gtk_window_motion_notify_callback( GtkWidget
* WXUNUSED(widget
),
1538 GdkEventMotion
*gdk_event
,
1541 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1543 if (gdk_event
->is_hint
)
1547 GdkModifierType state
;
1548 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1553 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1555 wxMouseEvent
event( wxEVT_MOTION
);
1556 InitMouseEvent(win
, event
, gdk_event
);
1558 if ( g_captureWindow
)
1560 // synthesise a mouse enter or leave event if needed
1561 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1562 // This seems to be necessary and actually been added to
1563 // GDK itself in version 2.0.X
1566 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1567 if ( hasMouse
!= g_captureWindowHasMouse
)
1569 // the mouse changed window
1570 g_captureWindowHasMouse
= hasMouse
;
1572 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1573 : wxEVT_LEAVE_WINDOW
);
1574 InitMouseEvent(win
, eventM
, gdk_event
);
1575 eventM
.SetEventObject(win
);
1576 win
->GTKProcessEvent(eventM
);
1581 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1583 // reset the event object and id in case win changed.
1584 event
.SetEventObject( win
);
1585 event
.SetId( win
->GetId() );
1588 if ( !g_captureWindow
)
1590 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1591 if (win
->GTKProcessEvent( cevent
))
1593 win
->SetCursor( cevent
.GetCursor() );
1597 bool ret
= win
->GTKProcessEvent(event
);
1599 g_lastMouseEvent
= NULL
;
1604 //-----------------------------------------------------------------------------
1605 // "scroll_event" (mouse wheel event)
1606 //-----------------------------------------------------------------------------
1609 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1611 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1612 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1617 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1618 InitMouseEvent(win
, event
, gdk_event
);
1620 // FIXME: Get these values from GTK or GDK
1621 event
.m_linesPerAction
= 3;
1622 event
.m_wheelDelta
= 120;
1623 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1624 event
.m_wheelRotation
= 120;
1626 event
.m_wheelRotation
= -120;
1628 return win
->GTKProcessEvent(event
);
1631 //-----------------------------------------------------------------------------
1633 //-----------------------------------------------------------------------------
1635 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1637 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1638 event
.SetEventObject(win
);
1639 return win
->GTKProcessEvent(event
);
1642 //-----------------------------------------------------------------------------
1644 //-----------------------------------------------------------------------------
1647 gtk_window_focus_in_callback( GtkWidget
* WXUNUSED(widget
),
1648 GdkEventFocus
*WXUNUSED(event
),
1652 gtk_im_context_focus_in(win
->m_imData
->context
);
1655 g_focusWindow
= win
;
1657 wxLogTrace(TRACE_FOCUS
,
1658 _T("%s: focus in"), win
->GetName().c_str());
1661 // caret needs to be informed about focus change
1662 wxCaret
*caret
= win
->GetCaret();
1665 caret
->OnSetFocus();
1667 #endif // wxUSE_CARET
1669 gboolean ret
= FALSE
;
1671 // does the window itself think that it has the focus?
1672 if ( !win
->m_hasFocus
)
1674 // not yet, notify it
1675 win
->m_hasFocus
= true;
1677 (void)DoSendFocusEvents(win
);
1682 // Disable default focus handling for custom windows
1683 // since the default GTK+ handler issues a repaint
1684 if (win
->m_wxwindow
)
1690 //-----------------------------------------------------------------------------
1691 // "focus_out_event"
1692 //-----------------------------------------------------------------------------
1695 gtk_window_focus_out_callback( GtkWidget
* WXUNUSED(widget
),
1696 GdkEventFocus
* WXUNUSED(gdk_event
),
1700 gtk_im_context_focus_out(win
->m_imData
->context
);
1702 wxLogTrace( TRACE_FOCUS
,
1703 _T("%s: focus out"), win
->GetName().c_str() );
1706 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1710 g_focusWindow
= (wxWindowGTK
*)NULL
;
1713 // caret needs to be informed about focus change
1714 wxCaret
*caret
= win
->GetCaret();
1717 caret
->OnKillFocus();
1719 #endif // wxUSE_CARET
1721 // don't send the window a kill focus event if it thinks that it doesn't
1722 // have focus already
1723 if ( win
->m_hasFocus
)
1725 // the event handler might delete the window when it loses focus, so
1726 // check whether this is a custom window before calling it
1727 const bool has_wxwindow
= win
->m_wxwindow
!= NULL
;
1729 win
->m_hasFocus
= false;
1731 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1732 event
.SetEventObject( win
);
1734 (void)win
->GTKProcessEvent( event
);
1736 // Disable default focus handling for custom windows
1737 // since the default GTK+ handler issues a repaint
1742 // continue with normal processing
1747 wx_window_focus_callback(GtkWidget
*widget
,
1748 GtkDirectionType
WXUNUSED(direction
),
1751 // the default handler for focus signal in GtkScrolledWindow sets
1752 // focus to the window itself even if it doesn't accept focus, i.e. has no
1753 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1754 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1755 // any children which might accept focus (we know we don't accept the focus
1756 // ourselves as this signal is only connected in this case)
1757 if ( win
->GetChildren().empty() )
1758 g_signal_stop_emission_by_name(widget
, "focus");
1760 // we didn't change the focus
1764 //-----------------------------------------------------------------------------
1765 // "enter_notify_event"
1766 //-----------------------------------------------------------------------------
1769 gtk_window_enter_callback( GtkWidget
*widget
,
1770 GdkEventCrossing
*gdk_event
,
1773 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1775 // Event was emitted after a grab
1776 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1780 GdkModifierType state
= (GdkModifierType
)0;
1782 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1784 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1785 InitMouseEvent(win
, event
, gdk_event
);
1786 wxPoint pt
= win
->GetClientAreaOrigin();
1787 event
.m_x
= x
+ pt
.x
;
1788 event
.m_y
= y
+ pt
.y
;
1790 if ( !g_captureWindow
)
1792 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1793 if (win
->GTKProcessEvent( cevent
))
1795 win
->SetCursor( cevent
.GetCursor() );
1799 return win
->GTKProcessEvent(event
);
1802 //-----------------------------------------------------------------------------
1803 // "leave_notify_event"
1804 //-----------------------------------------------------------------------------
1807 gtk_window_leave_callback( GtkWidget
*widget
,
1808 GdkEventCrossing
*gdk_event
,
1811 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1813 // Event was emitted after an ungrab
1814 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1816 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1820 GdkModifierType state
= (GdkModifierType
)0;
1822 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1824 InitMouseEvent(win
, event
, gdk_event
);
1826 return win
->GTKProcessEvent(event
);
1829 //-----------------------------------------------------------------------------
1830 // "value_changed" from scrollbar
1831 //-----------------------------------------------------------------------------
1834 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
1836 wxEventType eventType
= win
->GetScrollEventType(range
);
1837 if (eventType
!= wxEVT_NULL
)
1839 // Convert scroll event type to scrollwin event type
1840 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
1842 // find the scrollbar which generated the event
1843 wxWindowGTK::ScrollDir dir
= win
->ScrollDirFromRange(range
);
1845 // generate the corresponding wx event
1846 const int orient
= wxWindow::OrientFromScrollDir(dir
);
1847 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
1848 event
.SetEventObject(win
);
1850 win
->GTKProcessEvent(event
);
1854 //-----------------------------------------------------------------------------
1855 // "button_press_event" from scrollbar
1856 //-----------------------------------------------------------------------------
1859 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
1861 g_blockEventsOnScroll
= true;
1862 win
->m_mouseButtonDown
= true;
1867 //-----------------------------------------------------------------------------
1868 // "event_after" from scrollbar
1869 //-----------------------------------------------------------------------------
1872 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
1874 if (event
->type
== GDK_BUTTON_RELEASE
)
1876 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1878 const int orient
= wxWindow::OrientFromScrollDir(
1879 win
->ScrollDirFromRange(range
));
1880 wxScrollWinEvent
evt(wxEVT_SCROLLWIN_THUMBRELEASE
,
1881 win
->GetScrollPos(orient
), orient
);
1882 evt
.SetEventObject(win
);
1883 win
->GTKProcessEvent(evt
);
1887 //-----------------------------------------------------------------------------
1888 // "button_release_event" from scrollbar
1889 //-----------------------------------------------------------------------------
1892 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
1894 g_blockEventsOnScroll
= false;
1895 win
->m_mouseButtonDown
= false;
1896 // If thumb tracking
1897 if (win
->m_isScrolling
)
1899 win
->m_isScrolling
= false;
1900 // Hook up handler to send thumb release event after this emission is finished.
1901 // To allow setting scroll position from event handler, sending event must
1902 // be deferred until after the GtkRange handler for this signal has run
1903 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1909 //-----------------------------------------------------------------------------
1910 // "realize" from m_widget
1911 //-----------------------------------------------------------------------------
1914 gtk_window_realized_callback(GtkWidget
* widget
, wxWindow
* win
)
1918 gtk_im_context_set_client_window( win
->m_imData
->context
,
1922 // We cannot set colours and fonts before the widget
1923 // been realized, so we do this directly after realization
1924 // or otherwise in idle time
1926 if (win
->m_needsStyleChange
)
1928 win
->SetBackgroundStyle(win
->GetBackgroundStyle());
1929 win
->m_needsStyleChange
= false;
1932 wxWindowCreateEvent
event( win
);
1933 event
.SetEventObject( win
);
1934 win
->GTKProcessEvent( event
);
1937 //-----------------------------------------------------------------------------
1938 // "size_allocate" from m_wxwindow or m_widget
1939 //-----------------------------------------------------------------------------
1942 size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxWindow
* win
)
1944 int w
= alloc
->width
;
1945 int h
= alloc
->height
;
1946 if (win
->m_wxwindow
)
1948 int border_x
, border_y
;
1949 WX_PIZZA(win
->m_wxwindow
)->get_border_widths(border_x
, border_y
);
1955 if (win
->m_oldClientWidth
!= w
|| win
->m_oldClientHeight
!= h
)
1957 win
->m_oldClientWidth
= w
;
1958 win
->m_oldClientHeight
= h
;
1959 // this callback can be connected to m_wxwindow,
1960 // so always get size from m_widget->allocation
1961 win
->m_width
= win
->m_widget
->allocation
.width
;
1962 win
->m_height
= win
->m_widget
->allocation
.height
;
1963 if (!win
->m_nativeSizeEvent
)
1965 wxSizeEvent
event(win
->GetSize(), win
->GetId());
1966 event
.SetEventObject(win
);
1967 win
->GTKProcessEvent(event
);
1972 //-----------------------------------------------------------------------------
1974 //-----------------------------------------------------------------------------
1976 #if GTK_CHECK_VERSION(2, 8, 0)
1978 gtk_window_grab_broken( GtkWidget
*,
1979 GdkEventGrabBroken
*event
,
1982 // Mouse capture has been lost involuntarily, notify the application
1983 if(!event
->keyboard
&& wxWindow::GetCapture() == win
)
1985 wxMouseCaptureLostEvent
evt( win
->GetId() );
1986 evt
.SetEventObject( win
);
1987 win
->HandleWindowEvent( evt
);
1993 //-----------------------------------------------------------------------------
1995 //-----------------------------------------------------------------------------
1998 void gtk_window_style_set_callback( GtkWidget
*WXUNUSED(widget
),
1999 GtkStyle
*previous_style
,
2002 if (win
&& previous_style
)
2004 wxSysColourChangedEvent event
;
2005 event
.SetEventObject(win
);
2007 win
->GTKProcessEvent( event
);
2013 // Helper to suspend colour change event event processing while we change a widget's style
2014 class wxSuspendStyleEvents
2017 wxSuspendStyleEvents(wxWindow
* win
)
2020 if (win
->m_wxwindow
&& win
->IsTopLevel())
2023 g_signal_handlers_block_by_func(
2024 m_win
->m_wxwindow
, (void*)gtk_window_style_set_callback
, m_win
);
2027 ~wxSuspendStyleEvents()
2030 g_signal_handlers_unblock_by_func(
2031 m_win
->m_wxwindow
, (void*)gtk_window_style_set_callback
, m_win
);
2037 // ----------------------------------------------------------------------------
2038 // this wxWindowBase function is implemented here (in platform-specific file)
2039 // because it is static and so couldn't be made virtual
2040 // ----------------------------------------------------------------------------
2042 wxWindow
*wxWindowBase::DoFindFocus()
2044 // the cast is necessary when we compile in wxUniversal mode
2045 return (wxWindow
*)g_focusWindow
;
2048 //-----------------------------------------------------------------------------
2049 // InsertChild for wxWindowGTK.
2050 //-----------------------------------------------------------------------------
2052 /* Callback for wxWindowGTK. This very strange beast has to be used because
2053 * C++ has no virtual methods in a constructor. We have to emulate a
2054 * virtual function here as wxNotebook requires a different way to insert
2055 * a child in it. I had opted for creating a wxNotebookPage window class
2056 * which would have made this superfluous (such in the MDI window system),
2057 * but no-one was listening to me... */
2059 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2061 /* the window might have been scrolled already, do we
2062 have to adapt the position */
2063 wxPizza
* pizza
= WX_PIZZA(parent
->m_wxwindow
);
2064 child
->m_x
+= pizza
->m_scroll_x
;
2065 child
->m_y
+= pizza
->m_scroll_y
;
2067 gtk_widget_set_size_request(
2068 child
->m_widget
, child
->m_width
, child
->m_height
);
2070 GTK_FIXED(parent
->m_wxwindow
), child
->m_widget
, child
->m_x
, child
->m_y
);
2073 //-----------------------------------------------------------------------------
2075 //-----------------------------------------------------------------------------
2077 wxWindow
*wxGetActiveWindow()
2079 return wxWindow::FindFocus();
2083 wxMouseState
wxGetMouseState()
2089 GdkModifierType mask
;
2091 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2095 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2096 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2097 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2098 ms
.SetAux1Down(mask
& GDK_BUTTON4_MASK
);
2099 ms
.SetAux2Down(mask
& GDK_BUTTON5_MASK
);
2101 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2102 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2103 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2104 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2109 //-----------------------------------------------------------------------------
2111 //-----------------------------------------------------------------------------
2113 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2115 #ifdef __WXUNIVERSAL__
2116 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2118 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2119 #endif // __WXUNIVERSAL__/__WXGTK__
2121 void wxWindowGTK::Init()
2124 m_widget
= (GtkWidget
*) NULL
;
2125 m_wxwindow
= (GtkWidget
*) NULL
;
2126 m_focusWidget
= (GtkWidget
*) NULL
;
2135 m_isBeingDeleted
= false;
2137 m_showOnIdle
= false;
2140 m_nativeSizeEvent
= false;
2142 m_hasScrolling
= false;
2143 m_isScrolling
= false;
2144 m_mouseButtonDown
= false;
2146 // initialize scrolling stuff
2147 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2149 m_scrollBar
[dir
] = NULL
;
2150 m_scrollPos
[dir
] = 0;
2154 m_oldClientHeight
= 0;
2156 m_insertCallback
= wxInsertChildInWindow
;
2160 m_clipPaintRegion
= false;
2162 m_needsStyleChange
= false;
2164 m_cursor
= *wxSTANDARD_CURSOR
;
2167 m_dirtyTabOrder
= false;
2170 wxWindowGTK::wxWindowGTK()
2175 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2180 const wxString
&name
)
2184 Create( parent
, id
, pos
, size
, style
, name
);
2187 bool wxWindowGTK::Create( wxWindow
*parent
,
2192 const wxString
&name
)
2194 // Get default border
2195 wxBorder border
= GetBorder(style
);
2196 style
&= ~wxBORDER_MASK
;
2199 if (!PreCreation( parent
, pos
, size
) ||
2200 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2202 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2207 m_wxwindow
= wxPizza::New(m_windowStyle
);
2208 if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
))
2209 m_widget
= m_wxwindow
;
2212 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2214 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2216 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2217 scroll_class
->scrollbar_spacing
= 0;
2219 // There is a conflict with default bindings at GTK+
2220 // level between scrolled windows and notebooks both of which want to use
2221 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2222 // direction and notebooks for changing pages -- we decide that if we don't
2223 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2224 // means we can get working keyboard navigation in notebooks
2225 if ( !HasFlag(wxHSCROLL
) )
2228 bindings
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
));
2231 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
);
2232 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
);
2236 if (HasFlag(wxALWAYS_SHOW_SB
))
2238 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
2240 scrolledWindow
->hscrollbar_visible
= TRUE
;
2241 scrolledWindow
->vscrollbar_visible
= TRUE
;
2245 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2248 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2249 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2250 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2251 gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE
);
2253 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2255 // connect various scroll-related events
2256 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2258 // these handlers block mouse events to any window during scrolling
2259 // such as motion events and prevent GTK and wxWidgets from fighting
2260 // over where the slider should be
2261 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2262 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2263 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2264 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2266 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2267 G_CALLBACK(gtk_scrollbar_event_after
), this);
2268 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2270 // these handlers get notified when scrollbar slider moves
2271 g_signal_connect_after(m_scrollBar
[dir
], "value_changed",
2272 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2275 gtk_widget_show( m_wxwindow
);
2279 m_parent
->DoAddChild( this );
2281 m_focusWidget
= m_wxwindow
;
2288 wxWindowGTK::~wxWindowGTK()
2292 if (g_focusWindow
== this)
2293 g_focusWindow
= NULL
;
2295 if ( g_delayedFocus
== this )
2296 g_delayedFocus
= NULL
;
2298 m_isBeingDeleted
= true;
2301 // destroy children before destroying this window itself
2304 // unhook focus handlers to prevent stray events being
2305 // propagated to this (soon to be) dead object
2306 if (m_focusWidget
!= NULL
)
2308 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2309 (gpointer
) gtk_window_focus_in_callback
,
2311 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2312 (gpointer
) gtk_window_focus_out_callback
,
2319 // delete before the widgets to avoid a crash on solaris
2322 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2324 gtk_widget_destroy( m_wxwindow
);
2325 m_wxwindow
= (GtkWidget
*) NULL
;
2330 gtk_widget_destroy( m_widget
);
2331 m_widget
= (GtkWidget
*) NULL
;
2335 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2337 if ( GTKNeedsParent() )
2339 wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") );
2342 // Use either the given size, or the default if -1 is given.
2343 // See wxWindowBase for these functions.
2344 m_width
= WidthDefault(size
.x
) ;
2345 m_height
= HeightDefault(size
.y
);
2353 void wxWindowGTK::PostCreation()
2355 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2361 // these get reported to wxWidgets -> wxPaintEvent
2363 g_signal_connect (m_wxwindow
, "expose_event",
2364 G_CALLBACK (gtk_window_expose_callback
), this);
2366 if (GetLayoutDirection() == wxLayout_LeftToRight
)
2367 gtk_widget_set_redraw_on_allocate(m_wxwindow
, HasFlag(wxFULL_REPAINT_ON_RESIZE
));
2370 // Create input method handler
2371 m_imData
= new wxGtkIMData
;
2373 // Cannot handle drawing preedited text yet
2374 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2376 g_signal_connect (m_imData
->context
, "commit",
2377 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2380 #ifndef __WXUNIVERSAL__
2381 if (HasFlag(wxPizza::BORDER_STYLES
))
2383 g_signal_connect(m_widget
, "expose_event",
2384 G_CALLBACK(expose_event_border
), this);
2391 if (!GTK_IS_WINDOW(m_widget
))
2393 if (m_focusWidget
== NULL
)
2394 m_focusWidget
= m_widget
;
2398 g_signal_connect (m_focusWidget
, "focus_in_event",
2399 G_CALLBACK (gtk_window_focus_in_callback
), this);
2400 g_signal_connect (m_focusWidget
, "focus_out_event",
2401 G_CALLBACK (gtk_window_focus_out_callback
), this);
2405 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2406 G_CALLBACK (gtk_window_focus_in_callback
), this);
2407 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2408 G_CALLBACK (gtk_window_focus_out_callback
), this);
2412 if ( !AcceptsFocusFromKeyboard() )
2416 g_signal_connect(m_widget
, "focus",
2417 G_CALLBACK(wx_window_focus_callback
), this);
2420 // connect to the various key and mouse handlers
2422 GtkWidget
*connect_widget
= GetConnectWidget();
2424 ConnectWidget( connect_widget
);
2426 /* We cannot set colours, fonts and cursors before the widget has
2427 been realized, so we do this directly after realization */
2428 g_signal_connect (connect_widget
, "realize",
2429 G_CALLBACK (gtk_window_realized_callback
), this);
2433 g_signal_connect(m_wxwindow
? m_wxwindow
: m_widget
, "size_allocate",
2434 G_CALLBACK(size_allocate
), this);
2439 #if GTK_CHECK_VERSION(2, 8, 0)
2440 if (!gtk_check_version(2,8,0))
2442 // Make sure we can notify the app when mouse capture is lost
2443 g_signal_connect (m_wxwindow
, "grab_broken_event",
2444 G_CALLBACK (gtk_window_grab_broken
), this);
2449 if ( connect_widget
!= m_wxwindow
)
2451 #if GTK_CHECK_VERSION(2, 8, 0)
2452 if (!gtk_check_version(2,8,0))
2454 // Make sure we can notify app code when mouse capture is lost
2455 g_signal_connect (connect_widget
, "grab_broken_event",
2456 G_CALLBACK (gtk_window_grab_broken
), this);
2461 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2462 if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2464 // If we connect to the "size_request" signal of a GtkFileChooserButton
2465 // then that control won't be sized properly when placed inside sizers
2466 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2467 // FIXME: what should be done here ?
2470 if ( !IsTopLevel() ) // top level windows use their own callback
2472 // This is needed if we want to add our windows into native
2473 // GTK controls, such as the toolbar. With this callback, the
2474 // toolbar gets to know the correct size (the one set by the
2475 // programmer). Sadly, it misbehaves for wxComboBox.
2476 g_signal_connect (m_widget
, "size_request",
2477 G_CALLBACK (wxgtk_window_size_request_callback
),
2481 InheritAttributes();
2485 SetLayoutDirection(wxLayout_Default
);
2487 // unless the window was created initially hidden (i.e. Hide() had been
2488 // called before Create()), we should show it at GTK+ level as well
2490 gtk_widget_show( m_widget
);
2493 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2495 g_signal_connect (widget
, "key_press_event",
2496 G_CALLBACK (gtk_window_key_press_callback
), this);
2497 g_signal_connect (widget
, "key_release_event",
2498 G_CALLBACK (gtk_window_key_release_callback
), this);
2499 g_signal_connect (widget
, "button_press_event",
2500 G_CALLBACK (gtk_window_button_press_callback
), this);
2501 g_signal_connect (widget
, "button_release_event",
2502 G_CALLBACK (gtk_window_button_release_callback
), this);
2503 g_signal_connect (widget
, "motion_notify_event",
2504 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2505 g_signal_connect (widget
, "scroll_event",
2506 G_CALLBACK (window_scroll_event
), this);
2507 g_signal_connect (widget
, "popup_menu",
2508 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2509 g_signal_connect (widget
, "enter_notify_event",
2510 G_CALLBACK (gtk_window_enter_callback
), this);
2511 g_signal_connect (widget
, "leave_notify_event",
2512 G_CALLBACK (gtk_window_leave_callback
), this);
2514 if (IsTopLevel() && m_wxwindow
)
2515 g_signal_connect (m_wxwindow
, "style_set",
2516 G_CALLBACK (gtk_window_style_set_callback
), this);
2519 bool wxWindowGTK::Destroy()
2521 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2525 return wxWindowBase::Destroy();
2528 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2530 gtk_widget_set_size_request(m_widget
, width
, height
);
2531 // inform the parent to perform the move
2532 WX_PIZZA(m_parent
->m_wxwindow
)->move(m_widget
, x
, y
);
2535 void wxWindowGTK::ConstrainSize()
2538 // GPE's window manager doesn't like size hints at all, esp. when the user
2539 // has to use the virtual keyboard, so don't constrain size there
2543 const wxSize minSize
= GetMinSize();
2544 const wxSize maxSize
= GetMaxSize();
2545 if (minSize
.x
> 0 && m_width
< minSize
.x
) m_width
= minSize
.x
;
2546 if (minSize
.y
> 0 && m_height
< minSize
.y
) m_height
= minSize
.y
;
2547 if (maxSize
.x
> 0 && m_width
> maxSize
.x
) m_width
= maxSize
.x
;
2548 if (maxSize
.y
> 0 && m_height
> maxSize
.y
) m_height
= maxSize
.y
;
2552 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2554 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2555 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2557 int currentX
, currentY
;
2558 GetPosition(¤tX
, ¤tY
);
2559 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2561 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2563 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2565 // calculate the best size if we should auto size the window
2566 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2567 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2569 const wxSize sizeBest
= GetBestSize();
2570 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2572 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2573 height
= sizeBest
.y
;
2576 const wxSize
oldSize(m_width
, m_height
);
2584 if (m_parent
->m_wxwindow
)
2586 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2587 m_x
= x
+ pizza
->m_scroll_x
;
2588 m_y
= y
+ pizza
->m_scroll_y
;
2590 int left_border
= 0;
2591 int right_border
= 0;
2593 int bottom_border
= 0;
2595 /* the default button has a border around it */
2596 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2598 GtkBorder
*default_border
= NULL
;
2599 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2602 left_border
+= default_border
->left
;
2603 right_border
+= default_border
->right
;
2604 top_border
+= default_border
->top
;
2605 bottom_border
+= default_border
->bottom
;
2606 gtk_border_free( default_border
);
2610 DoMoveWindow( m_x
- left_border
,
2612 m_width
+left_border
+right_border
,
2613 m_height
+top_border
+bottom_border
);
2616 if (m_width
!= oldSize
.x
|| m_height
!= oldSize
.y
)
2618 // update these variables to keep size_allocate handler
2619 // from sending another size event for this change
2620 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2622 gtk_widget_queue_resize(m_widget
);
2623 if (!m_nativeSizeEvent
)
2625 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2626 event
.SetEventObject( this );
2627 HandleWindowEvent( event
);
2632 bool wxWindowGTK::GtkShowFromOnIdle()
2634 if (IsShown() && m_showOnIdle
&& !GTK_WIDGET_VISIBLE (m_widget
))
2636 GtkAllocation alloc
;
2639 alloc
.width
= m_width
;
2640 alloc
.height
= m_height
;
2641 gtk_widget_size_allocate( m_widget
, &alloc
);
2642 gtk_widget_show( m_widget
);
2643 wxShowEvent
eventShow(GetId(), true);
2644 eventShow
.SetEventObject(this);
2645 HandleWindowEvent(eventShow
);
2646 m_showOnIdle
= false;
2653 void wxWindowGTK::OnInternalIdle()
2655 // Check if we have to show window now
2656 if (GtkShowFromOnIdle()) return;
2658 if ( m_dirtyTabOrder
)
2660 m_dirtyTabOrder
= false;
2664 // Update style if the window was not yet realized
2665 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2666 if (m_needsStyleChange
)
2668 SetBackgroundStyle(GetBackgroundStyle());
2669 m_needsStyleChange
= false;
2672 wxCursor cursor
= m_cursor
;
2673 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2677 /* I now set the cursor anew in every OnInternalIdle call
2678 as setting the cursor in a parent window also effects the
2679 windows above so that checking for the current cursor is
2682 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2684 GdkWindow
*window
= m_wxwindow
->window
;
2686 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2688 if (!g_globalCursor
.Ok())
2689 cursor
= *wxSTANDARD_CURSOR
;
2691 window
= m_widget
->window
;
2692 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2693 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2696 else if ( m_widget
)
2698 GdkWindow
*window
= m_widget
->window
;
2699 if ( window
&& !GTK_WIDGET_NO_WINDOW(m_widget
) )
2700 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2704 if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
2705 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2708 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2710 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2712 if (width
) (*width
) = m_width
;
2713 if (height
) (*height
) = m_height
;
2716 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2718 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2720 const wxSize size
= GetSize();
2721 const wxSize clientSize
= GetClientSize();
2722 SetSize(width
+ (size
.x
- clientSize
.x
), height
+ (size
.y
- clientSize
.y
));
2725 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2727 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2738 GetScrollbarWidth(m_widget
, dw
, dh
);
2740 int border_x
, border_y
;
2741 WX_PIZZA(m_wxwindow
)->get_border_widths(border_x
, border_y
);
2753 if (width
) *width
= w
;
2754 if (height
) *height
= h
;
2757 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2759 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2763 if (!IsTopLevel() && m_parent
&& m_parent
->m_wxwindow
)
2765 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2766 dx
= pizza
->m_scroll_x
;
2767 dy
= pizza
->m_scroll_y
;
2770 if (m_x
== -1 && m_y
== -1)
2772 GdkWindow
*source
= (GdkWindow
*) NULL
;
2774 source
= m_wxwindow
->window
;
2776 source
= m_widget
->window
;
2782 gdk_window_get_origin( source
, &org_x
, &org_y
);
2785 m_parent
->ScreenToClient(&org_x
, &org_y
);
2787 wx_const_cast(wxWindowGTK
*, this)->m_x
= org_x
;
2788 wx_const_cast(wxWindowGTK
*, this)->m_y
= org_y
;
2792 if (x
) (*x
) = m_x
- dx
;
2793 if (y
) (*y
) = m_y
- dy
;
2796 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2798 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2800 if (!m_widget
->window
) return;
2802 GdkWindow
*source
= (GdkWindow
*) NULL
;
2804 source
= m_wxwindow
->window
;
2806 source
= m_widget
->window
;
2810 gdk_window_get_origin( source
, &org_x
, &org_y
);
2814 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2816 org_x
+= m_widget
->allocation
.x
;
2817 org_y
+= m_widget
->allocation
.y
;
2824 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2825 *x
= (GetClientSize().x
- *x
) + org_x
;
2833 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
2835 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2837 if (!m_widget
->window
) return;
2839 GdkWindow
*source
= (GdkWindow
*) NULL
;
2841 source
= m_wxwindow
->window
;
2843 source
= m_widget
->window
;
2847 gdk_window_get_origin( source
, &org_x
, &org_y
);
2851 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2853 org_x
+= m_widget
->allocation
.x
;
2854 org_y
+= m_widget
->allocation
.y
;
2860 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2861 *x
= (GetClientSize().x
- *x
) - org_x
;
2868 bool wxWindowGTK::Show( bool show
)
2870 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
2872 if (!wxWindowBase::Show(show
))
2878 if (show
&& m_showOnIdle
)
2885 gtk_widget_show(m_widget
);
2887 gtk_widget_hide(m_widget
);
2888 wxShowEvent
eventShow(GetId(), show
);
2889 eventShow
.SetEventObject(this);
2890 HandleWindowEvent(eventShow
);
2896 void wxWindowGTK::DoEnable( bool enable
)
2898 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2900 gtk_widget_set_sensitive( m_widget
, enable
);
2901 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2902 gtk_widget_set_sensitive( m_wxwindow
, enable
);
2905 int wxWindowGTK::GetCharHeight() const
2907 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
2909 wxFont font
= GetFont();
2910 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
2912 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2917 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2918 PangoLayout
*layout
= pango_layout_new(context
);
2919 pango_layout_set_font_description(layout
, desc
);
2920 pango_layout_set_text(layout
, "H", 1);
2921 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2923 PangoRectangle rect
;
2924 pango_layout_line_get_extents(line
, NULL
, &rect
);
2926 g_object_unref (layout
);
2928 return (int) PANGO_PIXELS(rect
.height
);
2931 int wxWindowGTK::GetCharWidth() const
2933 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
2935 wxFont font
= GetFont();
2936 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
2938 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2943 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2944 PangoLayout
*layout
= pango_layout_new(context
);
2945 pango_layout_set_font_description(layout
, desc
);
2946 pango_layout_set_text(layout
, "g", 1);
2947 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2949 PangoRectangle rect
;
2950 pango_layout_line_get_extents(line
, NULL
, &rect
);
2952 g_object_unref (layout
);
2954 return (int) PANGO_PIXELS(rect
.width
);
2957 void wxWindowGTK::GetTextExtent( const wxString
& string
,
2961 int *externalLeading
,
2962 const wxFont
*theFont
) const
2964 wxFont fontToUse
= theFont
? *theFont
: GetFont();
2966 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
2975 PangoContext
*context
= NULL
;
2977 context
= gtk_widget_get_pango_context( m_widget
);
2986 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
2987 PangoLayout
*layout
= pango_layout_new(context
);
2988 pango_layout_set_font_description(layout
, desc
);
2990 const wxCharBuffer data
= wxGTK_CONV( string
);
2992 pango_layout_set_text(layout
, data
, strlen(data
));
2995 PangoRectangle rect
;
2996 pango_layout_get_extents(layout
, NULL
, &rect
);
2998 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
2999 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3002 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3003 int baseline
= pango_layout_iter_get_baseline(iter
);
3004 pango_layout_iter_free(iter
);
3005 *descent
= *y
- PANGO_PIXELS(baseline
);
3007 if (externalLeading
) (*externalLeading
) = 0; // ??
3009 g_object_unref (layout
);
3012 bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
3014 if ( g_delayedFocus
== this )
3016 if ( GTK_WIDGET_REALIZED(m_widget
) )
3018 gtk_widget_grab_focus(m_widget
);
3019 g_delayedFocus
= NULL
;
3028 void wxWindowGTK::SetFocus()
3030 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3033 // don't do anything if we already have focus
3039 // wxWindow::SetFocus() should really set the focus to
3040 // this control, whatever the flags are
3041 if (!GTK_WIDGET_CAN_FOCUS(m_wxwindow
))
3042 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3044 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3046 gtk_widget_grab_focus (m_wxwindow
);
3051 // wxWindow::SetFocus() should really set the focus to
3052 // this control, whatever the flags are
3053 if (!GTK_WIDGET_CAN_FOCUS(m_widget
))
3054 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3056 if (GTK_IS_CONTAINER(m_widget
))
3058 if (GTK_IS_RADIO_BUTTON(m_widget
))
3060 gtk_widget_grab_focus (m_widget
);
3064 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3067 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3070 if (!GTK_WIDGET_REALIZED(m_widget
))
3072 // we can't set the focus to the widget now so we remember that
3073 // it should be focused and will do it later, during the idle
3074 // time, as soon as we can
3075 wxLogTrace(TRACE_FOCUS
,
3076 _T("Delaying setting focus to %s(%s)"),
3077 GetClassInfo()->GetClassName(), GetLabel().c_str());
3079 g_delayedFocus
= this;
3083 wxLogTrace(TRACE_FOCUS
,
3084 _T("Setting focus to %s(%s)"),
3085 GetClassInfo()->GetClassName(), GetLabel().c_str());
3087 gtk_widget_grab_focus (m_widget
);
3092 wxLogTrace(TRACE_FOCUS
,
3093 _T("Can't set focus to %s(%s)"),
3094 GetClassInfo()->GetClassName(), GetLabel().c_str());
3099 void wxWindowGTK::SetCanFocus(bool canFocus
)
3102 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3104 GTK_WIDGET_UNSET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3106 if ( m_wxwindow
&& (m_widget
!= m_wxwindow
) )
3109 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3111 GTK_WIDGET_UNSET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3115 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3117 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3119 wxWindowGTK
*oldParent
= m_parent
,
3120 *newParent
= (wxWindowGTK
*)newParentBase
;
3122 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3124 if ( !wxWindowBase::Reparent(newParent
) )
3127 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3129 /* prevent GTK from deleting the widget arbitrarily */
3130 gtk_widget_ref( m_widget
);
3134 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3137 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3141 if (GTK_WIDGET_VISIBLE (newParent
->m_widget
))
3143 m_showOnIdle
= true;
3144 gtk_widget_hide( m_widget
);
3147 /* insert GTK representation */
3148 (*(newParent
->m_insertCallback
))(newParent
, this);
3151 /* reverse: prevent GTK from deleting the widget arbitrarily */
3152 gtk_widget_unref( m_widget
);
3154 SetLayoutDirection(wxLayout_Default
);
3159 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3161 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3162 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3167 /* insert GTK representation */
3168 (*m_insertCallback
)(this, child
);
3171 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3173 wxWindowBase::AddChild(child
);
3174 m_dirtyTabOrder
= true;
3175 wxTheApp
->WakeUpIdle();
3178 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3180 wxWindowBase::RemoveChild(child
);
3181 m_dirtyTabOrder
= true;
3182 wxTheApp
->WakeUpIdle();
3186 wxLayoutDirection
wxWindowGTK::GTKGetLayout(GtkWidget
*widget
)
3188 return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
3189 ? wxLayout_RightToLeft
3190 : wxLayout_LeftToRight
;
3194 void wxWindowGTK::GTKSetLayout(GtkWidget
*widget
, wxLayoutDirection dir
)
3196 wxASSERT_MSG( dir
!= wxLayout_Default
, _T("invalid layout direction") );
3198 gtk_widget_set_direction(widget
,
3199 dir
== wxLayout_RightToLeft
? GTK_TEXT_DIR_RTL
3200 : GTK_TEXT_DIR_LTR
);
3203 wxLayoutDirection
wxWindowGTK::GetLayoutDirection() const
3205 return GTKGetLayout(m_widget
);
3208 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
)
3210 if ( dir
== wxLayout_Default
)
3212 const wxWindow
*const parent
= GetParent();
3215 // inherit layout from parent.
3216 dir
= parent
->GetLayoutDirection();
3218 else // no parent, use global default layout
3220 dir
= wxTheApp
->GetLayoutDirection();
3224 if ( dir
== wxLayout_Default
)
3227 GTKSetLayout(m_widget
, dir
);
3229 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3230 GTKSetLayout(m_wxwindow
, dir
);
3234 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
,
3235 wxCoord
WXUNUSED(width
),
3236 wxCoord
WXUNUSED(widthTotal
)) const
3238 // We now mirror the coordinates of RTL windows in wxPizza
3242 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, WindowOrder move
)
3244 wxWindowBase::DoMoveInTabOrder(win
, move
);
3245 m_dirtyTabOrder
= true;
3246 wxTheApp
->WakeUpIdle();
3249 bool wxWindowGTK::DoNavigateIn(int flags
)
3251 if ( flags
& wxNavigationKeyEvent::WinChange
)
3253 wxFAIL_MSG( _T("not implemented") );
3257 else // navigate inside the container
3259 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3260 wxCHECK_MSG( parent
, false, _T("every window must have a TLW parent") );
3262 GtkDirectionType dir
;
3263 dir
= flags
& wxNavigationKeyEvent::IsForward
? GTK_DIR_TAB_FORWARD
3264 : GTK_DIR_TAB_BACKWARD
;
3267 g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
);
3273 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3275 // none needed by default
3279 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3281 // nothing to do by default since none is needed
3284 void wxWindowGTK::RealizeTabOrder()
3288 if ( !m_children
.empty() )
3290 // we don't only construct the correct focus chain but also use
3291 // this opportunity to update the mnemonic widgets for the widgets
3294 GList
*chain
= NULL
;
3295 wxWindowGTK
* mnemonicWindow
= NULL
;
3297 for ( wxWindowList::const_iterator i
= m_children
.begin();
3298 i
!= m_children
.end();
3301 wxWindowGTK
*win
= *i
;
3303 if ( mnemonicWindow
)
3305 if ( win
->AcceptsFocusFromKeyboard() )
3307 // wxComboBox et al. needs to focus on on a different
3308 // widget than m_widget, so if the main widget isn't
3309 // focusable try the connect widget
3310 GtkWidget
* w
= win
->m_widget
;
3311 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3313 w
= win
->GetConnectWidget();
3314 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3320 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3321 mnemonicWindow
= NULL
;
3325 else if ( win
->GTKWidgetNeedsMnemonic() )
3327 mnemonicWindow
= win
;
3330 chain
= g_list_prepend(chain
, win
->m_widget
);
3333 chain
= g_list_reverse(chain
);
3335 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3340 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3345 void wxWindowGTK::Raise()
3347 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3349 if (m_wxwindow
&& m_wxwindow
->window
)
3351 gdk_window_raise( m_wxwindow
->window
);
3353 else if (m_widget
->window
)
3355 gdk_window_raise( m_widget
->window
);
3359 void wxWindowGTK::Lower()
3361 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3363 if (m_wxwindow
&& m_wxwindow
->window
)
3365 gdk_window_lower( m_wxwindow
->window
);
3367 else if (m_widget
->window
)
3369 gdk_window_lower( m_widget
->window
);
3373 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3375 if ( !wxWindowBase::SetCursor(cursor
.Ok() ? cursor
: *wxSTANDARD_CURSOR
) )
3383 void wxWindowGTK::GTKUpdateCursor()
3385 wxCursor
cursor(g_globalCursor
.Ok() ? g_globalCursor
: GetCursor());
3388 wxArrayGdkWindows windowsThis
;
3389 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3392 gdk_window_set_cursor(winThis
, cursor
.GetCursor());
3396 const size_t count
= windowsThis
.size();
3397 for ( size_t n
= 0; n
< count
; n
++ )
3399 GdkWindow
*win
= windowsThis
[n
];
3402 wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?"));
3406 gdk_window_set_cursor(win
, cursor
.GetCursor());
3412 void wxWindowGTK::WarpPointer( int x
, int y
)
3414 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3416 // We provide this function ourselves as it is
3417 // missing in GDK (top of this file).
3419 GdkWindow
*window
= (GdkWindow
*) NULL
;
3421 window
= m_wxwindow
->window
;
3423 window
= GetConnectWidget()->window
;
3426 gdk_window_warp_pointer( window
, x
, y
);
3429 wxWindowGTK::ScrollDir
wxWindowGTK::ScrollDirFromRange(GtkRange
*range
) const
3431 // find the scrollbar which generated the event
3432 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3434 if ( range
== m_scrollBar
[dir
] )
3435 return (ScrollDir
)dir
;
3438 wxFAIL_MSG( _T("event from unknown scrollbar received") );
3440 return ScrollDir_Max
;
3443 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3445 bool changed
= false;
3446 GtkRange
* range
= m_scrollBar
[dir
];
3447 if ( range
&& units
)
3449 GtkAdjustment
* adj
= range
->adjustment
;
3450 gdouble inc
= unit
== ScrollUnit_Line
? adj
->step_increment
3451 : adj
->page_increment
;
3453 const int posOld
= int(adj
->value
+ 0.5);
3454 gtk_range_set_value(range
, posOld
+ units
*inc
);
3456 changed
= int(adj
->value
+ 0.5) != posOld
;
3462 bool wxWindowGTK::ScrollLines(int lines
)
3464 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3467 bool wxWindowGTK::ScrollPages(int pages
)
3469 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3472 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground
),
3477 if (!m_widget
->window
)
3482 if (m_wxwindow
->window
== NULL
) return;
3484 GdkRectangle gdk_rect
,
3488 gdk_rect
.x
= rect
->x
;
3489 gdk_rect
.y
= rect
->y
;
3490 gdk_rect
.width
= rect
->width
;
3491 gdk_rect
.height
= rect
->height
;
3492 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3493 gdk_rect
.x
= GetClientSize().x
- gdk_rect
.x
- gdk_rect
.width
;
3497 else // invalidate everything
3502 gdk_window_invalidate_rect(m_wxwindow
->window
, p
, true);
3506 void wxWindowGTK::Update()
3510 // when we call Update() we really want to update the window immediately on
3511 // screen, even if it means flushing the entire queue and hence slowing down
3512 // everything -- but it should still be done, it's just that Update() should
3513 // be called very rarely
3517 void wxWindowGTK::GtkUpdate()
3519 if (m_wxwindow
&& m_wxwindow
->window
)
3520 gdk_window_process_updates(m_wxwindow
->window
, false);
3521 if (m_widget
&& m_widget
->window
&& (m_wxwindow
!= m_widget
))
3522 gdk_window_process_updates( m_widget
->window
, FALSE
);
3524 // for consistency with other platforms (and also because it's convenient
3525 // to be able to update an entire TLW by calling Update() only once), we
3526 // should also update all our children here
3527 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3529 node
= node
->GetNext() )
3531 node
->GetData()->GtkUpdate();
3535 bool wxWindowGTK::DoIsExposed( int x
, int y
) const
3537 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
3541 bool wxWindowGTK::DoIsExposed( int x
, int y
, int w
, int h
) const
3543 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3544 return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
;
3546 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
3549 void wxWindowGTK::GtkSendPaintEvents()
3553 m_updateRegion
.Clear();
3557 // Clip to paint region in wxClientDC
3558 m_clipPaintRegion
= true;
3560 m_nativeUpdateRegion
= m_updateRegion
;
3562 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3564 // Transform m_updateRegion under RTL
3565 m_updateRegion
.Clear();
3568 gdk_drawable_get_size(m_wxwindow
->window
, &width
, NULL
);
3570 wxRegionIterator
upd( m_nativeUpdateRegion
);
3574 rect
.x
= upd
.GetX();
3575 rect
.y
= upd
.GetY();
3576 rect
.width
= upd
.GetWidth();
3577 rect
.height
= upd
.GetHeight();
3579 rect
.x
= width
- rect
.x
- rect
.width
;
3580 m_updateRegion
.Union( rect
);
3586 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3588 // find ancestor from which to steal background
3589 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3591 parent
= (wxWindow
*)this;
3593 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3595 wxRegionIterator
upd( m_nativeUpdateRegion
);
3599 rect
.x
= upd
.GetX();
3600 rect
.y
= upd
.GetY();
3601 rect
.width
= upd
.GetWidth();
3602 rect
.height
= upd
.GetHeight();
3604 gtk_paint_flat_box( parent
->m_widget
->style
,
3606 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3619 wxWindowDC
dc( (wxWindow
*)this );
3620 dc
.SetClippingRegion( m_updateRegion
);
3622 // Work around gtk-qt <= 0.60 bug whereby the window colour
3624 if (GetBackgroundStyle() == wxBG_STYLE_COLOUR
&& GetBackgroundColour().Ok() && wxSystemOptions::GetOptionInt(wxT("gtk.window.force-background-colour")) == 1)
3626 dc
.SetBackground(wxBrush(GetBackgroundColour()));
3630 wxEraseEvent
erase_event( GetId(), &dc
);
3631 erase_event
.SetEventObject( this );
3633 HandleWindowEvent(erase_event
);
3636 wxNcPaintEvent
nc_paint_event( GetId() );
3637 nc_paint_event
.SetEventObject( this );
3638 HandleWindowEvent( nc_paint_event
);
3640 wxPaintEvent
paint_event( GetId() );
3641 paint_event
.SetEventObject( this );
3642 HandleWindowEvent( paint_event
);
3644 m_clipPaintRegion
= false;
3646 m_updateRegion
.Clear();
3647 m_nativeUpdateRegion
.Clear();
3650 void wxWindowGTK::SetDoubleBuffered( bool on
)
3652 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3655 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3658 bool wxWindowGTK::IsDoubleBuffered() const
3660 return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow
);
3663 void wxWindowGTK::ClearBackground()
3665 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3669 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3671 wxWindowBase::DoSetToolTip(tip
);
3674 m_tooltip
->Apply( (wxWindow
*)this );
3677 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const gchar
*tip
)
3679 gtk_tooltips_set_tip(tips
, GetConnectWidget(), tip
, NULL
);
3681 #endif // wxUSE_TOOLTIPS
3683 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3685 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3687 if (!wxWindowBase::SetBackgroundColour(colour
))
3692 // We need the pixel value e.g. for background clearing.
3693 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3696 // apply style change (forceStyle=true so that new style is applied
3697 // even if the bg colour changed from valid to wxNullColour)
3698 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3699 ApplyWidgetStyle(true);
3704 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3706 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3708 if (!wxWindowBase::SetForegroundColour(colour
))
3715 // We need the pixel value e.g. for background clearing.
3716 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3719 // apply style change (forceStyle=true so that new style is applied
3720 // even if the bg colour changed from valid to wxNullColour):
3721 ApplyWidgetStyle(true);
3726 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3728 return gtk_widget_get_pango_context( m_widget
);
3731 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3733 // do we need to apply any changes at all?
3736 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3741 GtkRcStyle
*style
= gtk_rc_style_new();
3746 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3749 int flagsNormal
= 0,
3752 flagsInsensitive
= 0;
3754 if ( m_foregroundColour
.Ok() )
3756 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3758 style
->fg
[GTK_STATE_NORMAL
] =
3759 style
->text
[GTK_STATE_NORMAL
] = *fg
;
3760 flagsNormal
|= GTK_RC_FG
| GTK_RC_TEXT
;
3762 style
->fg
[GTK_STATE_PRELIGHT
] =
3763 style
->text
[GTK_STATE_PRELIGHT
] = *fg
;
3764 flagsPrelight
|= GTK_RC_FG
| GTK_RC_TEXT
;
3766 style
->fg
[GTK_STATE_ACTIVE
] =
3767 style
->text
[GTK_STATE_ACTIVE
] = *fg
;
3768 flagsActive
|= GTK_RC_FG
| GTK_RC_TEXT
;
3771 if ( m_backgroundColour
.Ok() )
3773 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3775 style
->bg
[GTK_STATE_NORMAL
] =
3776 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3777 flagsNormal
|= GTK_RC_BG
| GTK_RC_BASE
;
3779 style
->bg
[GTK_STATE_PRELIGHT
] =
3780 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3781 flagsPrelight
|= GTK_RC_BG
| GTK_RC_BASE
;
3783 style
->bg
[GTK_STATE_ACTIVE
] =
3784 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3785 flagsActive
|= GTK_RC_BG
| GTK_RC_BASE
;
3787 style
->bg
[GTK_STATE_INSENSITIVE
] =
3788 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3789 flagsInsensitive
|= GTK_RC_BG
| GTK_RC_BASE
;
3792 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
;
3793 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
;
3794 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
;
3795 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
;
3800 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3802 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3805 DoApplyWidgetStyle(style
);
3806 gtk_rc_style_unref(style
);
3809 // Style change may affect GTK+'s size calculation:
3810 InvalidateBestSize();
3813 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3815 wxSuspendStyleEvents
s(static_cast<wxWindow
*>(this));
3818 gtk_widget_modify_style(m_wxwindow
, style
);
3820 gtk_widget_modify_style(m_widget
, style
);
3823 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3825 wxWindowBase::SetBackgroundStyle(style
);
3827 if (style
== wxBG_STYLE_CUSTOM
)
3832 window
= m_wxwindow
->window
;
3836 GtkWidget
* const w
= GetConnectWidget();
3837 window
= w
? w
->window
: NULL
;
3842 // Make sure GDK/X11 doesn't refresh the window
3844 gdk_window_set_back_pixmap( window
, None
, False
);
3846 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3849 m_needsStyleChange
= false;
3851 else // window not realized yet
3853 // Do in OnIdle, because the window is not yet available
3854 m_needsStyleChange
= true;
3857 // Don't apply widget style, or we get a grey background
3861 // apply style change (forceStyle=true so that new style is applied
3862 // even if the bg colour changed from valid to wxNullColour):
3863 ApplyWidgetStyle(true);
3868 #if wxUSE_DRAG_AND_DROP
3870 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3872 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3874 GtkWidget
*dnd_widget
= GetConnectWidget();
3876 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3878 if (m_dropTarget
) delete m_dropTarget
;
3879 m_dropTarget
= dropTarget
;
3881 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3884 #endif // wxUSE_DRAG_AND_DROP
3886 GtkWidget
* wxWindowGTK::GetConnectWidget()
3888 GtkWidget
*connect_widget
= m_widget
;
3889 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3891 return connect_widget
;
3894 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow
*window
) const
3896 wxArrayGdkWindows windowsThis
;
3897 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3899 return winThis
? window
== winThis
3900 : windowsThis
.Index(window
) != wxNOT_FOUND
;
3903 GdkWindow
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
3905 return m_wxwindow
? m_wxwindow
->window
: m_widget
->window
;
3908 bool wxWindowGTK::SetFont( const wxFont
&font
)
3910 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3912 if (!wxWindowBase::SetFont(font
))
3915 // apply style change (forceStyle=true so that new style is applied
3916 // even if the font changed from valid to wxNullFont):
3917 ApplyWidgetStyle(true);
3922 void wxWindowGTK::DoCaptureMouse()
3924 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3926 GdkWindow
*window
= (GdkWindow
*) NULL
;
3928 window
= m_wxwindow
->window
;
3930 window
= GetConnectWidget()->window
;
3932 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3934 const wxCursor
* cursor
= &m_cursor
;
3936 cursor
= wxSTANDARD_CURSOR
;
3938 gdk_pointer_grab( window
, FALSE
,
3940 (GDK_BUTTON_PRESS_MASK
|
3941 GDK_BUTTON_RELEASE_MASK
|
3942 GDK_POINTER_MOTION_HINT_MASK
|
3943 GDK_POINTER_MOTION_MASK
),
3945 cursor
->GetCursor(),
3946 (guint32
)GDK_CURRENT_TIME
);
3947 g_captureWindow
= this;
3948 g_captureWindowHasMouse
= true;
3951 void wxWindowGTK::DoReleaseMouse()
3953 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3955 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3957 g_captureWindow
= (wxWindowGTK
*) NULL
;
3959 GdkWindow
*window
= (GdkWindow
*) NULL
;
3961 window
= m_wxwindow
->window
;
3963 window
= GetConnectWidget()->window
;
3968 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3971 void wxWindowGTK::GTKReleaseMouseAndNotify()
3974 wxMouseCaptureLostEvent
evt(GetId());
3975 evt
.SetEventObject( this );
3976 HandleWindowEvent( evt
);
3980 wxWindow
*wxWindowBase::GetCapture()
3982 return (wxWindow
*)g_captureWindow
;
3985 bool wxWindowGTK::IsRetained() const
3990 void wxWindowGTK::SetScrollbar(int orient
,
3994 bool WXUNUSED(update
))
3996 const int dir
= ScrollDirFromOrient(orient
);
3997 GtkRange
* const sb
= m_scrollBar
[dir
];
3998 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4002 m_hasScrolling
= true;
4006 // GtkRange requires upper > lower
4011 GtkAdjustment
* const adj
= sb
->adjustment
;
4012 adj
->step_increment
= 1;
4013 adj
->page_increment
=
4014 adj
->page_size
= thumbVisible
;
4017 g_signal_handlers_block_by_func(
4018 sb
, (void*)gtk_scrollbar_value_changed
, this);
4020 gtk_range_set_range(sb
, 0, range
);
4021 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4023 g_signal_handlers_unblock_by_func(
4024 sb
, (void*)gtk_scrollbar_value_changed
, this);
4027 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4029 const int dir
= ScrollDirFromOrient(orient
);
4030 GtkRange
* const sb
= m_scrollBar
[dir
];
4031 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4033 // This check is more than an optimization. Without it, the slider
4034 // will not move smoothly while tracking when using wxScrollHelper.
4035 if (GetScrollPos(orient
) != pos
)
4037 g_signal_handlers_block_by_func(
4038 sb
, (void*)gtk_scrollbar_value_changed
, this);
4040 gtk_range_set_value(sb
, pos
);
4041 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4043 g_signal_handlers_unblock_by_func(
4044 sb
, (void*)gtk_scrollbar_value_changed
, this);
4048 int wxWindowGTK::GetScrollThumb(int orient
) const
4050 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4051 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4053 return int(sb
->adjustment
->page_size
);
4056 int wxWindowGTK::GetScrollPos( int orient
) const
4058 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4059 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4061 return int(sb
->adjustment
->value
+ 0.5);
4064 int wxWindowGTK::GetScrollRange( int orient
) const
4066 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4067 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4069 return int(sb
->adjustment
->upper
);
4072 // Determine if increment is the same as +/-x, allowing for some small
4073 // difference due to possible inexactness in floating point arithmetic
4074 static inline bool IsScrollIncrement(double increment
, double x
)
4076 wxASSERT(increment
> 0);
4077 const double tolerance
= 1.0 / 1024;
4078 return fabs(increment
- fabs(x
)) < tolerance
;
4081 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4083 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4085 const int barIndex
= range
== m_scrollBar
[1];
4086 GtkAdjustment
* adj
= range
->adjustment
;
4088 const int value
= int(adj
->value
+ 0.5);
4090 // save previous position
4091 const double oldPos
= m_scrollPos
[barIndex
];
4092 // update current position
4093 m_scrollPos
[barIndex
] = adj
->value
;
4094 // If event should be ignored, or integral position has not changed
4095 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4100 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4103 // Difference from last change event
4104 const double diff
= adj
->value
- oldPos
;
4105 const bool isDown
= diff
> 0;
4107 if (IsScrollIncrement(adj
->step_increment
, diff
))
4109 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4111 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4113 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4115 else if (m_mouseButtonDown
)
4117 // Assume track event
4118 m_isScrolling
= true;
4124 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4126 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4128 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4130 // No scrolling requested.
4131 if ((dx
== 0) && (dy
== 0)) return;
4133 m_clipPaintRegion
= true;
4135 WX_PIZZA(m_wxwindow
)->scroll(dx
, dy
);
4137 m_clipPaintRegion
= false;
4140 bool restoreCaret
= (GetCaret() != NULL
&& GetCaret()->IsVisible());
4143 wxRect
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4145 caretRect
.width
+= dx
;
4148 caretRect
.x
+= dx
; caretRect
.width
-= dx
;
4151 caretRect
.height
+= dy
;
4154 caretRect
.y
+= dy
; caretRect
.height
-= dy
;
4157 RefreshRect(caretRect
);
4159 #endif // wxUSE_CARET
4162 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4164 //RN: Note that static controls usually have no border on gtk, so maybe
4165 //it makes sense to treat that as simply no border at the wx level
4167 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4169 GtkShadowType gtkstyle
;
4171 if(wxstyle
& wxBORDER_RAISED
)
4172 gtkstyle
= GTK_SHADOW_OUT
;
4173 else if (wxstyle
& wxBORDER_SUNKEN
)
4174 gtkstyle
= GTK_SHADOW_IN
;
4177 else if (wxstyle
& wxBORDER_DOUBLE
)
4178 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4181 gtkstyle
= GTK_SHADOW_IN
;
4183 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4188 void wxWindowGTK::SetWindowStyleFlag( long style
)
4190 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4191 wxWindowBase::SetWindowStyleFlag(style
);
4194 // Find the wxWindow at the current mouse position, also returning the mouse
4196 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4198 pt
= wxGetMousePosition();
4199 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4203 // Get the current mouse position.
4204 wxPoint
wxGetMousePosition()
4206 /* This crashes when used within wxHelpContext,
4207 so we have to use the X-specific implementation below.
4209 GdkModifierType *mask;
4210 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4212 return wxPoint(x, y);
4216 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4218 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4219 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4220 Window rootReturn
, childReturn
;
4221 int rootX
, rootY
, winX
, winY
;
4222 unsigned int maskReturn
;
4224 XQueryPointer (display
,
4228 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4229 return wxPoint(rootX
, rootY
);
4233 GdkWindow
* wxWindowGTK::GTKGetDrawingWindow() const
4235 GdkWindow
* window
= NULL
;
4237 window
= m_wxwindow
->window
;