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 //-----------------------------------------------------------------------------
262 // "size_request" of m_widget
263 //-----------------------------------------------------------------------------
265 // make it extern because wxStaticText needs to disconnect this one
267 void wxgtk_window_size_request_callback(GtkWidget
* WXUNUSED(widget
),
268 GtkRequisition
*requisition
,
272 win
->GetSize( &w
, &h
);
278 requisition
->height
= h
;
279 requisition
->width
= w
;
283 //-----------------------------------------------------------------------------
284 // "expose_event" of m_wxwindow
285 //-----------------------------------------------------------------------------
289 gtk_window_expose_callback( GtkWidget
*,
290 GdkEventExpose
*gdk_event
,
296 wxPrintf( wxT("OnExpose from ") );
297 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
298 wxPrintf( win
->GetClassInfo()->GetClassName() );
299 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
300 (int)gdk_event
->area
.y
,
301 (int)gdk_event
->area
.width
,
302 (int)gdk_event
->area
.height
);
307 win
->m_wxwindow
->style
,
311 (GdkRectangle
*) NULL
,
313 (char *)"button", // const_cast
318 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
320 win
->GtkSendPaintEvents();
322 // Let parent window draw window-less widgets
327 //-----------------------------------------------------------------------------
328 // "expose_event" from m_widget, for drawing border
329 //-----------------------------------------------------------------------------
331 #ifndef __WXUNIVERSAL__
333 GtkWidget
* GetEntryWidget();
337 expose_event_border(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxWindow
* win
)
339 // if this event is not for the GdkWindow the border is drawn on
340 if (win
->m_wxwindow
== win
->m_widget
&& gdk_event
->window
== widget
->window
)
345 // GtkScrolledWindow is GTK_NO_WINDOW
346 if (GTK_WIDGET_NO_WINDOW(widget
))
348 x
= widget
->allocation
.x
;
349 y
= widget
->allocation
.y
;
351 int w
= win
->m_wxwindow
->allocation
.width
;
352 int h
= win
->m_wxwindow
->allocation
.height
;
353 if (win
->HasFlag(wxBORDER_SIMPLE
))
355 GdkGC
* gc
= gdk_gc_new(gdk_event
->window
);
356 gdk_gc_set_foreground(gc
, &widget
->style
->black
);
357 gdk_draw_rectangle(gdk_event
->window
, gc
, false, x
, y
, w
- 1, h
- 1);
362 GtkShadowType shadow
= GTK_SHADOW_IN
;
363 if (win
->HasFlag(wxBORDER_RAISED
))
364 shadow
= GTK_SHADOW_OUT
;
366 // Style detail to use
368 if (widget
== win
->m_wxwindow
)
369 // for non-scrollable wxWindows
372 // for scrollable ones
375 GtkWidget
* styleWidget
= GetEntryWidget();
377 styleWidget
->style
, gdk_event
->window
, GTK_STATE_NORMAL
,
378 shadow
, NULL
, styleWidget
, detail
, x
, y
, w
, h
);
381 // no further painting is needed for border-only GdkWindow
382 return win
->m_wxwindow
== win
->m_widget
;
385 #endif // !__WXUNIVERSAL__
387 //-----------------------------------------------------------------------------
388 // "key_press_event" from any window
389 //-----------------------------------------------------------------------------
391 // These are used when transforming Ctrl-alpha to ascii values 1-26
392 inline bool wxIsLowerChar(int code
)
394 return (code
>= 'a' && code
<= 'z' );
397 inline bool wxIsUpperChar(int code
)
399 return (code
>= 'A' && code
<= 'Z' );
403 // set WXTRACE to this to see the key event codes on the console
404 #define TRACE_KEYS _T("keyevent")
406 // translates an X key symbol to WXK_XXX value
408 // if isChar is true it means that the value returned will be used for EVT_CHAR
409 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
410 // for example, while if it is false it means that the value is going to be
411 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
413 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
419 // Shift, Control and Alt don't generate the CHAR events at all
422 key_code
= isChar
? 0 : WXK_SHIFT
;
426 key_code
= isChar
? 0 : WXK_CONTROL
;
434 key_code
= isChar
? 0 : WXK_ALT
;
437 // neither do the toggle modifies
438 case GDK_Scroll_Lock
:
439 key_code
= isChar
? 0 : WXK_SCROLL
;
443 key_code
= isChar
? 0 : WXK_CAPITAL
;
447 key_code
= isChar
? 0 : WXK_NUMLOCK
;
451 // various other special keys
464 case GDK_ISO_Left_Tab
:
471 key_code
= WXK_RETURN
;
475 key_code
= WXK_CLEAR
;
479 key_code
= WXK_PAUSE
;
483 key_code
= WXK_SELECT
;
487 key_code
= WXK_PRINT
;
491 key_code
= WXK_EXECUTE
;
495 key_code
= WXK_ESCAPE
;
498 // cursor and other extended keyboard keys
500 key_code
= WXK_DELETE
;
516 key_code
= WXK_RIGHT
;
523 case GDK_Prior
: // == GDK_Page_Up
524 key_code
= WXK_PAGEUP
;
527 case GDK_Next
: // == GDK_Page_Down
528 key_code
= WXK_PAGEDOWN
;
540 key_code
= WXK_INSERT
;
555 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
559 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
563 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
567 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
571 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
575 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
579 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
583 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
587 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
591 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
595 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
599 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
603 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
606 case GDK_KP_Prior
: // == GDK_KP_Page_Up
607 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
610 case GDK_KP_Next
: // == GDK_KP_Page_Down
611 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
615 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
619 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
623 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
627 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
631 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
634 case GDK_KP_Multiply
:
635 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
639 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
642 case GDK_KP_Separator
:
643 // FIXME: what is this?
644 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
647 case GDK_KP_Subtract
:
648 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
652 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
656 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
673 key_code
= WXK_F1
+ keysym
- GDK_F1
;
683 static inline bool wxIsAsciiKeysym(KeySym ks
)
688 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
690 GdkEventKey
*gdk_event
)
694 GdkModifierType state
;
695 if (gdk_event
->window
)
696 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
698 event
.SetTimestamp( gdk_event
->time
);
699 event
.SetId(win
->GetId());
700 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
701 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
702 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
703 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
704 event
.m_scanCode
= gdk_event
->keyval
;
705 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
706 event
.m_rawFlags
= 0;
708 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
710 wxGetMousePosition( &x
, &y
);
711 win
->ScreenToClient( &x
, &y
);
714 event
.SetEventObject( win
);
719 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
721 GdkEventKey
*gdk_event
)
723 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
724 // but only event->keyval which is quite useless to us, so remember
725 // the last character from GDK_KEY_PRESS and reuse it as last resort
727 // NB: should be MT-safe as we're always called from the main thread only
732 } s_lastKeyPress
= { 0, 0 };
734 KeySym keysym
= gdk_event
->keyval
;
736 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
737 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
741 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
745 // do we have the translation or is it a plain ASCII character?
746 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
748 // we should use keysym if it is ASCII as X does some translations
749 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
750 // which we don't want here (but which we do use for OnChar())
751 if ( !wxIsAsciiKeysym(keysym
) )
753 keysym
= (KeySym
)gdk_event
->string
[0];
756 // we want to always get the same key code when the same key is
757 // pressed regardless of the state of the modifiers, i.e. on a
758 // standard US keyboard pressing '5' or '%' ('5' key with
759 // Shift) should result in the same key code in OnKeyDown():
760 // '5' (although OnChar() will get either '5' or '%').
762 // to do it we first translate keysym to keycode (== scan code)
763 // and then back but always using the lower register
764 Display
*dpy
= (Display
*)wxGetDisplay();
765 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
767 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
769 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
771 // use the normalized, i.e. lower register, keysym if we've
773 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
775 // as explained above, we want to have lower register key codes
776 // normally but for the letter keys we want to have the upper ones
778 // NB: don't use XConvertCase() here, we want to do it for letters
780 key_code
= toupper(key_code
);
782 else // non ASCII key, what to do?
784 // by default, ignore it
787 // but if we have cached information from the last KEY_PRESS
788 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
791 if ( keysym
== s_lastKeyPress
.keysym
)
793 key_code
= s_lastKeyPress
.keycode
;
798 if ( gdk_event
->type
== GDK_KEY_PRESS
)
800 // remember it to be reused for KEY_UP event later
801 s_lastKeyPress
.keysym
= keysym
;
802 s_lastKeyPress
.keycode
= key_code
;
806 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
808 // sending unknown key events doesn't really make sense
812 // now fill all the other fields
813 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
815 event
.m_keyCode
= key_code
;
817 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
819 event
.m_uniChar
= key_code
;
829 GtkIMContext
*context
;
830 GdkEventKey
*lastKeyEvent
;
834 context
= gtk_im_multicontext_new();
839 g_object_unref (context
);
845 gtk_window_key_press_callback( GtkWidget
*widget
,
846 GdkEventKey
*gdk_event
,
851 if (g_blockEventsOnDrag
)
854 // GTK+ sends keypress events to the focus widget and then
855 // to all its parent and grandparent widget. We only want
856 // the key events from the focus widget.
857 if (!GTK_WIDGET_HAS_FOCUS(widget
))
860 wxKeyEvent
event( wxEVT_KEY_DOWN
);
862 bool return_after_IM
= false;
864 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
866 // Emit KEY_DOWN event
867 ret
= win
->HandleWindowEvent( event
);
871 // Return after IM processing as we cannot do
872 // anything with it anyhow.
873 return_after_IM
= true;
876 if ((!ret
) && (win
->m_imData
!= NULL
))
878 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
879 // docs, if IM filter returns true, no further processing should be done.
880 // we should send the key_down event anyway.
881 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
882 win
->m_imData
->lastKeyEvent
= NULL
;
883 if (intercepted_by_IM
)
885 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
896 wxWindowGTK
*ancestor
= win
;
899 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
902 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
903 ret
= ancestor
->HandleWindowEvent( command_event
);
906 if (ancestor
->IsTopLevel())
908 ancestor
= ancestor
->GetParent();
911 #endif // wxUSE_ACCEL
913 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
914 // will only be sent if it is not in an accelerator table.
918 KeySym keysym
= gdk_event
->keyval
;
919 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
920 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
923 if ( wxIsAsciiKeysym(keysym
) )
926 key_code
= (unsigned char)keysym
;
928 // gdk_event->string is actually deprecated
929 else if ( gdk_event
->length
== 1 )
931 key_code
= (unsigned char)gdk_event
->string
[0];
937 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
939 event
.m_keyCode
= key_code
;
941 // To conform to the docs we need to translate Ctrl-alpha
942 // characters to values in the range 1-26.
943 if ( event
.ControlDown() &&
944 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
946 if ( wxIsLowerChar(key_code
) )
947 event
.m_keyCode
= key_code
- 'a' + 1;
948 if ( wxIsUpperChar(key_code
) )
949 event
.m_keyCode
= key_code
- 'A' + 1;
951 event
.m_uniChar
= event
.m_keyCode
;
955 // Implement OnCharHook by checking ancestor top level windows
956 wxWindow
*parent
= win
;
957 while (parent
&& !parent
->IsTopLevel())
958 parent
= parent
->GetParent();
961 event
.SetEventType( wxEVT_CHAR_HOOK
);
962 ret
= parent
->HandleWindowEvent( event
);
967 event
.SetEventType(wxEVT_CHAR
);
968 ret
= win
->HandleWindowEvent( event
);
979 gtk_wxwindow_commit_cb (GtkIMContext
* WXUNUSED(context
),
983 wxKeyEvent
event( wxEVT_KEY_DOWN
);
985 // take modifiers, cursor position, timestamp etc. from the last
986 // key_press_event that was fed into Input Method:
987 if (window
->m_imData
->lastKeyEvent
)
989 wxFillOtherKeyEventFields(event
,
990 window
, window
->m_imData
->lastKeyEvent
);
994 event
.SetEventObject( window
);
997 const wxString
data(wxGTK_CONV_BACK_SYS(str
));
1003 // Implement OnCharHook by checking ancestor top level windows
1004 wxWindow
*parent
= window
;
1005 while (parent
&& !parent
->IsTopLevel())
1006 parent
= parent
->GetParent();
1008 for( wxString::const_iterator pstr
= data
.begin(); pstr
!= data
.end(); ++pstr
)
1011 event
.m_uniChar
= *pstr
;
1012 // Backward compatible for ISO-8859-1
1013 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1014 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1016 event
.m_keyCode
= (char)*pstr
;
1017 #endif // wxUSE_UNICODE
1019 // To conform to the docs we need to translate Ctrl-alpha
1020 // characters to values in the range 1-26.
1021 if ( event
.ControlDown() &&
1022 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
1024 if ( wxIsLowerChar(*pstr
) )
1025 event
.m_keyCode
= *pstr
- 'a' + 1;
1026 if ( wxIsUpperChar(*pstr
) )
1027 event
.m_keyCode
= *pstr
- 'A' + 1;
1029 event
.m_keyCode
= *pstr
- 'a' + 1;
1031 event
.m_uniChar
= event
.m_keyCode
;
1037 event
.SetEventType( wxEVT_CHAR_HOOK
);
1038 ret
= parent
->HandleWindowEvent( event
);
1043 event
.SetEventType(wxEVT_CHAR
);
1044 ret
= window
->HandleWindowEvent( event
);
1051 //-----------------------------------------------------------------------------
1052 // "key_release_event" from any window
1053 //-----------------------------------------------------------------------------
1057 gtk_window_key_release_callback( GtkWidget
* WXUNUSED(widget
),
1058 GdkEventKey
*gdk_event
,
1064 if (g_blockEventsOnDrag
)
1067 wxKeyEvent
event( wxEVT_KEY_UP
);
1068 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1070 // unknown key pressed, ignore (the event would be useless anyhow)
1074 return win
->GTKProcessEvent(event
);
1078 // ============================================================================
1080 // ============================================================================
1082 // ----------------------------------------------------------------------------
1083 // mouse event processing helpers
1084 // ----------------------------------------------------------------------------
1086 // init wxMouseEvent with the info from GdkEventXXX struct
1087 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1088 wxMouseEvent
& event
,
1091 event
.SetTimestamp( gdk_event
->time
);
1092 event
.m_shiftDown
= gdk_event
->state
& GDK_SHIFT_MASK
;
1093 event
.m_controlDown
= gdk_event
->state
& GDK_CONTROL_MASK
;
1094 event
.m_altDown
= gdk_event
->state
& GDK_MOD1_MASK
;
1095 event
.m_metaDown
= gdk_event
->state
& GDK_MOD2_MASK
;
1096 event
.m_leftDown
= gdk_event
->state
& GDK_BUTTON1_MASK
;
1097 event
.m_middleDown
= gdk_event
->state
& GDK_BUTTON2_MASK
;
1098 event
.m_rightDown
= gdk_event
->state
& GDK_BUTTON3_MASK
;
1099 event
.m_aux1Down
= gdk_event
->state
& GDK_BUTTON4_MASK
;
1100 event
.m_aux2Down
= gdk_event
->state
& GDK_BUTTON5_MASK
;
1102 wxPoint pt
= win
->GetClientAreaOrigin();
1103 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1104 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1106 if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
))
1108 // origin in the upper right corner
1109 int window_width
= win
->m_wxwindow
->allocation
.width
;
1110 event
.m_x
= window_width
- event
.m_x
;
1113 event
.SetEventObject( win
);
1114 event
.SetId( win
->GetId() );
1115 event
.SetTimestamp( gdk_event
->time
);
1118 static void AdjustEventButtonState(wxMouseEvent
& event
)
1120 // GDK reports the old state of the button for a button press event, but
1121 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1122 // for a LEFT_DOWN event, not FALSE, so we will invert
1123 // left/right/middleDown for the corresponding click events
1125 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1126 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1127 (event
.GetEventType() == wxEVT_LEFT_UP
))
1129 event
.m_leftDown
= !event
.m_leftDown
;
1133 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1134 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1135 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1137 event
.m_middleDown
= !event
.m_middleDown
;
1141 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1142 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1143 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1145 event
.m_rightDown
= !event
.m_rightDown
;
1150 // find the window to send the mouse event too
1152 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1157 if (win
->m_wxwindow
)
1159 wxPizza
* pizza
= WX_PIZZA(win
->m_wxwindow
);
1160 xx
+= pizza
->m_scroll_x
;
1161 yy
+= pizza
->m_scroll_y
;
1164 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1167 wxWindowGTK
*child
= node
->GetData();
1169 node
= node
->GetNext();
1170 if (!child
->IsShown())
1173 if (child
->IsTransparentForMouse())
1175 // wxStaticBox is transparent in the box itself
1176 int xx1
= child
->m_x
;
1177 int yy1
= child
->m_y
;
1178 int xx2
= child
->m_x
+ child
->m_width
;
1179 int yy2
= child
->m_y
+ child
->m_height
;
1182 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1184 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1186 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1188 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1199 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1200 (child
->m_x
<= xx
) &&
1201 (child
->m_y
<= yy
) &&
1202 (child
->m_x
+child
->m_width
>= xx
) &&
1203 (child
->m_y
+child
->m_height
>= yy
))
1216 // ----------------------------------------------------------------------------
1217 // common event handlers helpers
1218 // ----------------------------------------------------------------------------
1220 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const
1222 // nothing special at this level
1223 return HandleWindowEvent(event
);
1226 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1230 if (g_blockEventsOnDrag
)
1232 if (g_blockEventsOnScroll
)
1235 if (!GTKIsOwnWindow(event
->window
))
1241 // overloads for all GDK event types we use here: we need to have this as
1242 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1243 // derives from it in the sense that the structs have the same layout
1244 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1245 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1247 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1250 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1251 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1252 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1254 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1256 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1257 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1261 // send the wxChildFocusEvent and wxFocusEvent, common code of
1262 // gtk_window_focus_in_callback() and SetFocus()
1263 static bool DoSendFocusEvents(wxWindow
*win
)
1265 // Notify the parent keeping track of focus for the kbd navigation
1266 // purposes that we got it.
1267 wxChildFocusEvent
eventChildFocus(win
);
1268 (void)win
->HandleWindowEvent(eventChildFocus
);
1270 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1271 eventFocus
.SetEventObject(win
);
1273 return win
->HandleWindowEvent(eventFocus
);
1276 // all event handlers must have C linkage as they're called from GTK+ C code
1280 //-----------------------------------------------------------------------------
1281 // "button_press_event"
1282 //-----------------------------------------------------------------------------
1285 gtk_window_button_press_callback( GtkWidget
*widget
,
1286 GdkEventButton
*gdk_event
,
1289 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1291 g_lastButtonNumber
= gdk_event
->button
;
1293 // GDK sends surplus button down events
1294 // before a double click event. We
1295 // need to filter these out.
1296 if ((gdk_event
->type
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
))
1298 GdkEvent
*peek_event
= gdk_event_peek();
1301 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1302 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1304 gdk_event_free( peek_event
);
1309 gdk_event_free( peek_event
);
1314 wxEventType event_type
= wxEVT_NULL
;
1316 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1317 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1319 // Reset GDK internal timestamp variables in order to disable GDK
1320 // triple click events. GDK will then next time believe no button has
1321 // been clicked just before, and send a normal button click event.
1322 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1323 display
->button_click_time
[1] = 0;
1324 display
->button_click_time
[0] = 0;
1327 if (gdk_event
->button
== 1)
1329 // note that GDK generates triple click events which are not supported
1330 // by wxWidgets but still have to be passed to the app as otherwise
1331 // clicks would simply go missing
1332 switch (gdk_event
->type
)
1334 // we shouldn't get triple clicks at all for GTK2 because we
1335 // suppress them artificially using the code above but we still
1336 // should map them to something for GTK1 and not just ignore them
1337 // as this would lose clicks
1338 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1339 case GDK_BUTTON_PRESS
:
1340 event_type
= wxEVT_LEFT_DOWN
;
1343 case GDK_2BUTTON_PRESS
:
1344 event_type
= wxEVT_LEFT_DCLICK
;
1348 // just to silence gcc warnings
1352 else if (gdk_event
->button
== 2)
1354 switch (gdk_event
->type
)
1356 case GDK_3BUTTON_PRESS
:
1357 case GDK_BUTTON_PRESS
:
1358 event_type
= wxEVT_MIDDLE_DOWN
;
1361 case GDK_2BUTTON_PRESS
:
1362 event_type
= wxEVT_MIDDLE_DCLICK
;
1369 else if (gdk_event
->button
== 3)
1371 switch (gdk_event
->type
)
1373 case GDK_3BUTTON_PRESS
:
1374 case GDK_BUTTON_PRESS
:
1375 event_type
= wxEVT_RIGHT_DOWN
;
1378 case GDK_2BUTTON_PRESS
:
1379 event_type
= wxEVT_RIGHT_DCLICK
;
1387 if ( event_type
== wxEVT_NULL
)
1389 // unknown mouse button or click type
1393 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1395 wxMouseEvent
event( event_type
);
1396 InitMouseEvent( win
, event
, gdk_event
);
1398 AdjustEventButtonState(event
);
1400 // wxListBox actually gets mouse events from the item, so we need to give it
1401 // a chance to correct this
1402 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1404 // find the correct window to send the event to: it may be a different one
1405 // from the one which got it at GTK+ level because some controls don't have
1406 // their own X window and thus cannot get any events.
1407 if ( !g_captureWindow
)
1408 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1410 // reset the event object and id in case win changed.
1411 event
.SetEventObject( win
);
1412 event
.SetId( win
->GetId() );
1414 bool ret
= win
->GTKProcessEvent( event
);
1415 g_lastMouseEvent
= NULL
;
1419 if ((event_type
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&
1420 (g_focusWindow
!= win
) /* && win->IsFocusable() */)
1425 if (event_type
== wxEVT_RIGHT_DOWN
)
1427 // generate a "context menu" event: this is similar to right mouse
1428 // click under many GUIs except that it is generated differently
1429 // (right up under MSW, ctrl-click under Mac, right down here) and
1431 // (a) it's a command event and so is propagated to the parent
1432 // (b) under some ports it can be generated from kbd too
1433 // (c) it uses screen coords (because of (a))
1434 wxContextMenuEvent
evtCtx(
1437 win
->ClientToScreen(event
.GetPosition()));
1438 evtCtx
.SetEventObject(win
);
1439 return win
->GTKProcessEvent(evtCtx
);
1445 //-----------------------------------------------------------------------------
1446 // "button_release_event"
1447 //-----------------------------------------------------------------------------
1450 gtk_window_button_release_callback( GtkWidget
*widget
,
1451 GdkEventButton
*gdk_event
,
1454 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1456 g_lastButtonNumber
= 0;
1458 wxEventType event_type
= wxEVT_NULL
;
1460 switch (gdk_event
->button
)
1463 event_type
= wxEVT_LEFT_UP
;
1467 event_type
= wxEVT_MIDDLE_UP
;
1471 event_type
= wxEVT_RIGHT_UP
;
1475 // unknown button, don't process
1479 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1481 wxMouseEvent
event( event_type
);
1482 InitMouseEvent( win
, event
, gdk_event
);
1484 AdjustEventButtonState(event
);
1486 // same wxListBox hack as above
1487 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1489 if ( !g_captureWindow
)
1490 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1492 // reset the event object and id in case win changed.
1493 event
.SetEventObject( win
);
1494 event
.SetId( win
->GetId() );
1496 bool ret
= win
->GTKProcessEvent(event
);
1498 g_lastMouseEvent
= NULL
;
1503 //-----------------------------------------------------------------------------
1504 // "motion_notify_event"
1505 //-----------------------------------------------------------------------------
1508 gtk_window_motion_notify_callback( GtkWidget
* WXUNUSED(widget
),
1509 GdkEventMotion
*gdk_event
,
1512 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1514 if (gdk_event
->is_hint
)
1518 GdkModifierType state
;
1519 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1524 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1526 wxMouseEvent
event( wxEVT_MOTION
);
1527 InitMouseEvent(win
, event
, gdk_event
);
1529 if ( g_captureWindow
)
1531 // synthesise a mouse enter or leave event if needed
1532 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1533 // This seems to be necessary and actually been added to
1534 // GDK itself in version 2.0.X
1537 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1538 if ( hasMouse
!= g_captureWindowHasMouse
)
1540 // the mouse changed window
1541 g_captureWindowHasMouse
= hasMouse
;
1543 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1544 : wxEVT_LEAVE_WINDOW
);
1545 InitMouseEvent(win
, eventM
, gdk_event
);
1546 eventM
.SetEventObject(win
);
1547 win
->GTKProcessEvent(eventM
);
1552 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1554 // reset the event object and id in case win changed.
1555 event
.SetEventObject( win
);
1556 event
.SetId( win
->GetId() );
1559 if ( !g_captureWindow
)
1561 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1562 if (win
->GTKProcessEvent( cevent
))
1564 win
->SetCursor( cevent
.GetCursor() );
1568 bool ret
= win
->GTKProcessEvent(event
);
1570 g_lastMouseEvent
= NULL
;
1575 //-----------------------------------------------------------------------------
1576 // "scroll_event" (mouse wheel event)
1577 //-----------------------------------------------------------------------------
1580 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1582 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1583 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1588 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1589 InitMouseEvent(win
, event
, gdk_event
);
1591 // FIXME: Get these values from GTK or GDK
1592 event
.m_linesPerAction
= 3;
1593 event
.m_wheelDelta
= 120;
1594 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1595 event
.m_wheelRotation
= 120;
1597 event
.m_wheelRotation
= -120;
1599 return win
->GTKProcessEvent(event
);
1602 //-----------------------------------------------------------------------------
1604 //-----------------------------------------------------------------------------
1606 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1608 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1609 event
.SetEventObject(win
);
1610 return win
->GTKProcessEvent(event
);
1613 //-----------------------------------------------------------------------------
1615 //-----------------------------------------------------------------------------
1618 gtk_window_focus_in_callback( GtkWidget
* WXUNUSED(widget
),
1619 GdkEventFocus
*WXUNUSED(event
),
1623 gtk_im_context_focus_in(win
->m_imData
->context
);
1626 g_focusWindow
= win
;
1628 wxLogTrace(TRACE_FOCUS
,
1629 _T("%s: focus in"), win
->GetName().c_str());
1632 // caret needs to be informed about focus change
1633 wxCaret
*caret
= win
->GetCaret();
1636 caret
->OnSetFocus();
1638 #endif // wxUSE_CARET
1640 gboolean ret
= FALSE
;
1642 // does the window itself think that it has the focus?
1643 if ( !win
->m_hasFocus
)
1645 // not yet, notify it
1646 win
->m_hasFocus
= true;
1648 (void)DoSendFocusEvents(win
);
1653 // Disable default focus handling for custom windows
1654 // since the default GTK+ handler issues a repaint
1655 if (win
->m_wxwindow
)
1661 //-----------------------------------------------------------------------------
1662 // "focus_out_event"
1663 //-----------------------------------------------------------------------------
1666 gtk_window_focus_out_callback( GtkWidget
* WXUNUSED(widget
),
1667 GdkEventFocus
* WXUNUSED(gdk_event
),
1671 gtk_im_context_focus_out(win
->m_imData
->context
);
1673 wxLogTrace( TRACE_FOCUS
,
1674 _T("%s: focus out"), win
->GetName().c_str() );
1677 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1681 g_focusWindow
= (wxWindowGTK
*)NULL
;
1684 // caret needs to be informed about focus change
1685 wxCaret
*caret
= win
->GetCaret();
1688 caret
->OnKillFocus();
1690 #endif // wxUSE_CARET
1692 // don't send the window a kill focus event if it thinks that it doesn't
1693 // have focus already
1694 if ( win
->m_hasFocus
)
1696 // the event handler might delete the window when it loses focus, so
1697 // check whether this is a custom window before calling it
1698 const bool has_wxwindow
= win
->m_wxwindow
!= NULL
;
1700 win
->m_hasFocus
= false;
1702 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1703 event
.SetEventObject( win
);
1705 (void)win
->GTKProcessEvent( event
);
1707 // Disable default focus handling for custom windows
1708 // since the default GTK+ handler issues a repaint
1713 // continue with normal processing
1718 wx_window_focus_callback(GtkWidget
*widget
,
1719 GtkDirectionType
WXUNUSED(direction
),
1722 // the default handler for focus signal in GtkScrolledWindow sets
1723 // focus to the window itself even if it doesn't accept focus, i.e. has no
1724 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1725 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1726 // any children which might accept focus (we know we don't accept the focus
1727 // ourselves as this signal is only connected in this case)
1728 if ( win
->GetChildren().empty() )
1729 g_signal_stop_emission_by_name(widget
, "focus");
1731 // we didn't change the focus
1735 //-----------------------------------------------------------------------------
1736 // "enter_notify_event"
1737 //-----------------------------------------------------------------------------
1740 gtk_window_enter_callback( GtkWidget
*widget
,
1741 GdkEventCrossing
*gdk_event
,
1744 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1746 // Event was emitted after a grab
1747 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1751 GdkModifierType state
= (GdkModifierType
)0;
1753 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1755 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1756 InitMouseEvent(win
, event
, gdk_event
);
1757 wxPoint pt
= win
->GetClientAreaOrigin();
1758 event
.m_x
= x
+ pt
.x
;
1759 event
.m_y
= y
+ pt
.y
;
1761 if ( !g_captureWindow
)
1763 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1764 if (win
->GTKProcessEvent( cevent
))
1766 win
->SetCursor( cevent
.GetCursor() );
1770 return win
->GTKProcessEvent(event
);
1773 //-----------------------------------------------------------------------------
1774 // "leave_notify_event"
1775 //-----------------------------------------------------------------------------
1778 gtk_window_leave_callback( GtkWidget
*widget
,
1779 GdkEventCrossing
*gdk_event
,
1782 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1784 // Event was emitted after an ungrab
1785 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1787 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1791 GdkModifierType state
= (GdkModifierType
)0;
1793 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1795 InitMouseEvent(win
, event
, gdk_event
);
1797 return win
->GTKProcessEvent(event
);
1800 //-----------------------------------------------------------------------------
1801 // "value_changed" from scrollbar
1802 //-----------------------------------------------------------------------------
1805 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
1807 wxEventType eventType
= win
->GetScrollEventType(range
);
1808 if (eventType
!= wxEVT_NULL
)
1810 // Convert scroll event type to scrollwin event type
1811 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
1813 // find the scrollbar which generated the event
1814 wxWindowGTK::ScrollDir dir
= win
->ScrollDirFromRange(range
);
1816 // generate the corresponding wx event
1817 const int orient
= wxWindow::OrientFromScrollDir(dir
);
1818 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
1819 event
.SetEventObject(win
);
1821 win
->GTKProcessEvent(event
);
1825 //-----------------------------------------------------------------------------
1826 // "button_press_event" from scrollbar
1827 //-----------------------------------------------------------------------------
1830 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
1832 g_blockEventsOnScroll
= true;
1833 win
->m_mouseButtonDown
= true;
1838 //-----------------------------------------------------------------------------
1839 // "event_after" from scrollbar
1840 //-----------------------------------------------------------------------------
1843 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
1845 if (event
->type
== GDK_BUTTON_RELEASE
)
1847 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1849 const int orient
= wxWindow::OrientFromScrollDir(
1850 win
->ScrollDirFromRange(range
));
1851 wxScrollWinEvent
evt(wxEVT_SCROLLWIN_THUMBRELEASE
,
1852 win
->GetScrollPos(orient
), orient
);
1853 evt
.SetEventObject(win
);
1854 win
->GTKProcessEvent(evt
);
1858 //-----------------------------------------------------------------------------
1859 // "button_release_event" from scrollbar
1860 //-----------------------------------------------------------------------------
1863 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
1865 g_blockEventsOnScroll
= false;
1866 win
->m_mouseButtonDown
= false;
1867 // If thumb tracking
1868 if (win
->m_isScrolling
)
1870 win
->m_isScrolling
= false;
1871 // Hook up handler to send thumb release event after this emission is finished.
1872 // To allow setting scroll position from event handler, sending event must
1873 // be deferred until after the GtkRange handler for this signal has run
1874 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1880 //-----------------------------------------------------------------------------
1881 // "realize" from m_widget
1882 //-----------------------------------------------------------------------------
1885 gtk_window_realized_callback(GtkWidget
* widget
, wxWindow
* win
)
1889 gtk_im_context_set_client_window( win
->m_imData
->context
,
1893 // We cannot set colours and fonts before the widget
1894 // been realized, so we do this directly after realization
1895 // or otherwise in idle time
1897 if (win
->m_needsStyleChange
)
1899 win
->SetBackgroundStyle(win
->GetBackgroundStyle());
1900 win
->m_needsStyleChange
= false;
1903 wxWindowCreateEvent
event( win
);
1904 event
.SetEventObject( win
);
1905 win
->GTKProcessEvent( event
);
1908 //-----------------------------------------------------------------------------
1909 // "size_allocate" from m_wxwindow or m_widget
1910 //-----------------------------------------------------------------------------
1913 size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxWindow
* win
)
1915 int w
= alloc
->width
;
1916 int h
= alloc
->height
;
1917 if (win
->m_wxwindow
)
1919 int border_x
, border_y
;
1920 WX_PIZZA(win
->m_wxwindow
)->get_border_widths(border_x
, border_y
);
1926 if (win
->m_oldClientWidth
!= w
|| win
->m_oldClientHeight
!= h
)
1928 win
->m_oldClientWidth
= w
;
1929 win
->m_oldClientHeight
= h
;
1930 // this callback can be connected to m_wxwindow,
1931 // so always get size from m_widget->allocation
1932 win
->m_width
= win
->m_widget
->allocation
.width
;
1933 win
->m_height
= win
->m_widget
->allocation
.height
;
1934 if (!win
->m_nativeSizeEvent
)
1936 wxSizeEvent
event(win
->GetSize(), win
->GetId());
1937 event
.SetEventObject(win
);
1938 win
->GTKProcessEvent(event
);
1943 //-----------------------------------------------------------------------------
1945 //-----------------------------------------------------------------------------
1947 #if GTK_CHECK_VERSION(2, 8, 0)
1949 gtk_window_grab_broken( GtkWidget
*,
1950 GdkEventGrabBroken
*event
,
1953 // Mouse capture has been lost involuntarily, notify the application
1954 if(!event
->keyboard
&& wxWindow::GetCapture() == win
)
1956 wxMouseCaptureLostEvent
evt( win
->GetId() );
1957 evt
.SetEventObject( win
);
1958 win
->HandleWindowEvent( evt
);
1964 //-----------------------------------------------------------------------------
1966 //-----------------------------------------------------------------------------
1969 void gtk_window_style_set_callback( GtkWidget
*WXUNUSED(widget
),
1970 GtkStyle
*previous_style
,
1973 if (win
&& previous_style
)
1975 wxSysColourChangedEvent event
;
1976 event
.SetEventObject(win
);
1978 win
->GTKProcessEvent( event
);
1984 // Helper to suspend colour change event event processing while we change a widget's style
1985 class wxSuspendStyleEvents
1988 wxSuspendStyleEvents(wxWindow
* win
)
1991 if (win
->m_wxwindow
&& win
->IsTopLevel())
1994 g_signal_handlers_block_by_func(
1995 m_win
->m_wxwindow
, (void*)gtk_window_style_set_callback
, m_win
);
1998 ~wxSuspendStyleEvents()
2001 g_signal_handlers_unblock_by_func(
2002 m_win
->m_wxwindow
, (void*)gtk_window_style_set_callback
, m_win
);
2008 // ----------------------------------------------------------------------------
2009 // this wxWindowBase function is implemented here (in platform-specific file)
2010 // because it is static and so couldn't be made virtual
2011 // ----------------------------------------------------------------------------
2013 wxWindow
*wxWindowBase::DoFindFocus()
2015 // the cast is necessary when we compile in wxUniversal mode
2016 return (wxWindow
*)g_focusWindow
;
2019 //-----------------------------------------------------------------------------
2020 // InsertChild for wxWindowGTK.
2021 //-----------------------------------------------------------------------------
2023 /* Callback for wxWindowGTK. This very strange beast has to be used because
2024 * C++ has no virtual methods in a constructor. We have to emulate a
2025 * virtual function here as wxNotebook requires a different way to insert
2026 * a child in it. I had opted for creating a wxNotebookPage window class
2027 * which would have made this superfluous (such in the MDI window system),
2028 * but no-one was listening to me... */
2030 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2032 /* the window might have been scrolled already, do we
2033 have to adapt the position */
2034 wxPizza
* pizza
= WX_PIZZA(parent
->m_wxwindow
);
2035 child
->m_x
+= pizza
->m_scroll_x
;
2036 child
->m_y
+= pizza
->m_scroll_y
;
2038 gtk_widget_set_size_request(
2039 child
->m_widget
, child
->m_width
, child
->m_height
);
2041 GTK_FIXED(parent
->m_wxwindow
), child
->m_widget
, child
->m_x
, child
->m_y
);
2044 //-----------------------------------------------------------------------------
2046 //-----------------------------------------------------------------------------
2048 wxWindow
*wxGetActiveWindow()
2050 return wxWindow::FindFocus();
2054 wxMouseState
wxGetMouseState()
2060 GdkModifierType mask
;
2062 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2066 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2067 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2068 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2069 ms
.SetAux1Down(mask
& GDK_BUTTON4_MASK
);
2070 ms
.SetAux2Down(mask
& GDK_BUTTON5_MASK
);
2072 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2073 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2074 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2075 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2080 //-----------------------------------------------------------------------------
2082 //-----------------------------------------------------------------------------
2084 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2086 #ifdef __WXUNIVERSAL__
2087 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2089 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2090 #endif // __WXUNIVERSAL__/__WXGTK__
2092 void wxWindowGTK::Init()
2095 m_widget
= (GtkWidget
*) NULL
;
2096 m_wxwindow
= (GtkWidget
*) NULL
;
2097 m_focusWidget
= (GtkWidget
*) NULL
;
2106 m_isBeingDeleted
= false;
2108 m_showOnIdle
= false;
2111 m_nativeSizeEvent
= false;
2113 m_isScrolling
= false;
2114 m_mouseButtonDown
= false;
2116 // initialize scrolling stuff
2117 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2119 m_scrollBar
[dir
] = NULL
;
2120 m_scrollPos
[dir
] = 0;
2124 m_oldClientHeight
= 0;
2126 m_insertCallback
= wxInsertChildInWindow
;
2130 m_clipPaintRegion
= false;
2132 m_needsStyleChange
= false;
2134 m_cursor
= *wxSTANDARD_CURSOR
;
2137 m_dirtyTabOrder
= false;
2140 wxWindowGTK::wxWindowGTK()
2145 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2150 const wxString
&name
)
2154 Create( parent
, id
, pos
, size
, style
, name
);
2157 bool wxWindowGTK::Create( wxWindow
*parent
,
2162 const wxString
&name
)
2164 // Get default border
2165 wxBorder border
= GetBorder(style
);
2166 style
&= ~wxBORDER_MASK
;
2169 if (!PreCreation( parent
, pos
, size
) ||
2170 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2172 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2177 m_wxwindow
= wxPizza::New(m_windowStyle
);
2178 if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
))
2179 m_widget
= m_wxwindow
;
2182 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2184 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2186 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2187 scroll_class
->scrollbar_spacing
= 0;
2189 // There is a conflict with default bindings at GTK+
2190 // level between scrolled windows and notebooks both of which want to use
2191 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2192 // direction and notebooks for changing pages -- we decide that if we don't
2193 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2194 // means we can get working keyboard navigation in notebooks
2195 if ( !HasFlag(wxHSCROLL
) )
2198 bindings
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
));
2201 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
);
2202 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
);
2206 if (HasFlag(wxALWAYS_SHOW_SB
))
2208 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
2210 scrolledWindow
->hscrollbar_visible
= TRUE
;
2211 scrolledWindow
->vscrollbar_visible
= TRUE
;
2215 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2218 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2219 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2220 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2221 gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE
);
2223 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2225 // connect various scroll-related events
2226 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2228 // these handlers block mouse events to any window during scrolling
2229 // such as motion events and prevent GTK and wxWidgets from fighting
2230 // over where the slider should be
2231 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2232 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2233 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2234 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2236 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2237 G_CALLBACK(gtk_scrollbar_event_after
), this);
2238 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2240 // these handlers get notified when scrollbar slider moves
2241 g_signal_connect_after(m_scrollBar
[dir
], "value_changed",
2242 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2245 gtk_widget_show( m_wxwindow
);
2249 m_parent
->DoAddChild( this );
2251 m_focusWidget
= m_wxwindow
;
2258 wxWindowGTK::~wxWindowGTK()
2262 if (g_focusWindow
== this)
2263 g_focusWindow
= NULL
;
2265 if ( g_delayedFocus
== this )
2266 g_delayedFocus
= NULL
;
2268 m_isBeingDeleted
= true;
2271 // destroy children before destroying this window itself
2274 // unhook focus handlers to prevent stray events being
2275 // propagated to this (soon to be) dead object
2276 if (m_focusWidget
!= NULL
)
2278 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2279 (gpointer
) gtk_window_focus_in_callback
,
2281 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2282 (gpointer
) gtk_window_focus_out_callback
,
2289 // delete before the widgets to avoid a crash on solaris
2292 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2294 gtk_widget_destroy( m_wxwindow
);
2295 m_wxwindow
= (GtkWidget
*) NULL
;
2300 gtk_widget_destroy( m_widget
);
2301 m_widget
= (GtkWidget
*) NULL
;
2305 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2307 if ( GTKNeedsParent() )
2309 wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") );
2312 // Use either the given size, or the default if -1 is given.
2313 // See wxWindowBase for these functions.
2314 m_width
= WidthDefault(size
.x
) ;
2315 m_height
= HeightDefault(size
.y
);
2323 void wxWindowGTK::PostCreation()
2325 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2331 // these get reported to wxWidgets -> wxPaintEvent
2333 g_signal_connect (m_wxwindow
, "expose_event",
2334 G_CALLBACK (gtk_window_expose_callback
), this);
2336 if (GetLayoutDirection() == wxLayout_LeftToRight
)
2337 gtk_widget_set_redraw_on_allocate(m_wxwindow
, HasFlag(wxFULL_REPAINT_ON_RESIZE
));
2340 // Create input method handler
2341 m_imData
= new wxGtkIMData
;
2343 // Cannot handle drawing preedited text yet
2344 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2346 g_signal_connect (m_imData
->context
, "commit",
2347 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2350 #ifndef __WXUNIVERSAL__
2351 if (HasFlag(wxPizza::BORDER_STYLES
))
2353 g_signal_connect(m_widget
, "expose_event",
2354 G_CALLBACK(expose_event_border
), this);
2361 if (!GTK_IS_WINDOW(m_widget
))
2363 if (m_focusWidget
== NULL
)
2364 m_focusWidget
= m_widget
;
2368 g_signal_connect (m_focusWidget
, "focus_in_event",
2369 G_CALLBACK (gtk_window_focus_in_callback
), this);
2370 g_signal_connect (m_focusWidget
, "focus_out_event",
2371 G_CALLBACK (gtk_window_focus_out_callback
), this);
2375 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2376 G_CALLBACK (gtk_window_focus_in_callback
), this);
2377 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2378 G_CALLBACK (gtk_window_focus_out_callback
), this);
2382 if ( !AcceptsFocusFromKeyboard() )
2386 g_signal_connect(m_widget
, "focus",
2387 G_CALLBACK(wx_window_focus_callback
), this);
2390 // connect to the various key and mouse handlers
2392 GtkWidget
*connect_widget
= GetConnectWidget();
2394 ConnectWidget( connect_widget
);
2396 /* We cannot set colours, fonts and cursors before the widget has
2397 been realized, so we do this directly after realization */
2398 g_signal_connect (connect_widget
, "realize",
2399 G_CALLBACK (gtk_window_realized_callback
), this);
2403 g_signal_connect(m_wxwindow
? m_wxwindow
: m_widget
, "size_allocate",
2404 G_CALLBACK(size_allocate
), this);
2409 #if GTK_CHECK_VERSION(2, 8, 0)
2410 if (!gtk_check_version(2,8,0))
2412 // Make sure we can notify the app when mouse capture is lost
2413 g_signal_connect (m_wxwindow
, "grab_broken_event",
2414 G_CALLBACK (gtk_window_grab_broken
), this);
2419 if ( connect_widget
!= m_wxwindow
)
2421 #if GTK_CHECK_VERSION(2, 8, 0)
2422 if (!gtk_check_version(2,8,0))
2424 // Make sure we can notify app code when mouse capture is lost
2425 g_signal_connect (connect_widget
, "grab_broken_event",
2426 G_CALLBACK (gtk_window_grab_broken
), this);
2431 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2432 if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2434 // If we connect to the "size_request" signal of a GtkFileChooserButton
2435 // then that control won't be sized properly when placed inside sizers
2436 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2437 // FIXME: what should be done here ?
2440 if ( !IsTopLevel() ) // top level windows use their own callback
2442 // This is needed if we want to add our windows into native
2443 // GTK controls, such as the toolbar. With this callback, the
2444 // toolbar gets to know the correct size (the one set by the
2445 // programmer). Sadly, it misbehaves for wxComboBox.
2446 g_signal_connect (m_widget
, "size_request",
2447 G_CALLBACK (wxgtk_window_size_request_callback
),
2451 InheritAttributes();
2455 SetLayoutDirection(wxLayout_Default
);
2457 // unless the window was created initially hidden (i.e. Hide() had been
2458 // called before Create()), we should show it at GTK+ level as well
2460 gtk_widget_show( m_widget
);
2463 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2465 g_signal_connect (widget
, "key_press_event",
2466 G_CALLBACK (gtk_window_key_press_callback
), this);
2467 g_signal_connect (widget
, "key_release_event",
2468 G_CALLBACK (gtk_window_key_release_callback
), this);
2469 g_signal_connect (widget
, "button_press_event",
2470 G_CALLBACK (gtk_window_button_press_callback
), this);
2471 g_signal_connect (widget
, "button_release_event",
2472 G_CALLBACK (gtk_window_button_release_callback
), this);
2473 g_signal_connect (widget
, "motion_notify_event",
2474 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2475 g_signal_connect (widget
, "scroll_event",
2476 G_CALLBACK (window_scroll_event
), this);
2477 g_signal_connect (widget
, "popup_menu",
2478 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2479 g_signal_connect (widget
, "enter_notify_event",
2480 G_CALLBACK (gtk_window_enter_callback
), this);
2481 g_signal_connect (widget
, "leave_notify_event",
2482 G_CALLBACK (gtk_window_leave_callback
), this);
2484 if (IsTopLevel() && m_wxwindow
)
2485 g_signal_connect (m_wxwindow
, "style_set",
2486 G_CALLBACK (gtk_window_style_set_callback
), this);
2489 bool wxWindowGTK::Destroy()
2491 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2495 return wxWindowBase::Destroy();
2498 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2500 gtk_widget_set_size_request(m_widget
, width
, height
);
2501 // inform the parent to perform the move
2502 WX_PIZZA(m_parent
->m_wxwindow
)->move(m_widget
, x
, y
);
2505 void wxWindowGTK::ConstrainSize()
2508 // GPE's window manager doesn't like size hints at all, esp. when the user
2509 // has to use the virtual keyboard, so don't constrain size there
2513 const wxSize minSize
= GetMinSize();
2514 const wxSize maxSize
= GetMaxSize();
2515 if (minSize
.x
> 0 && m_width
< minSize
.x
) m_width
= minSize
.x
;
2516 if (minSize
.y
> 0 && m_height
< minSize
.y
) m_height
= minSize
.y
;
2517 if (maxSize
.x
> 0 && m_width
> maxSize
.x
) m_width
= maxSize
.x
;
2518 if (maxSize
.y
> 0 && m_height
> maxSize
.y
) m_height
= maxSize
.y
;
2522 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2524 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2525 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2527 int currentX
, currentY
;
2528 GetPosition(¤tX
, ¤tY
);
2529 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2531 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2533 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2535 // calculate the best size if we should auto size the window
2536 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2537 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2539 const wxSize sizeBest
= GetBestSize();
2540 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2542 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2543 height
= sizeBest
.y
;
2546 const wxSize
oldSize(m_width
, m_height
);
2554 if (m_parent
->m_wxwindow
)
2556 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2557 m_x
= x
+ pizza
->m_scroll_x
;
2558 m_y
= y
+ pizza
->m_scroll_y
;
2560 int left_border
= 0;
2561 int right_border
= 0;
2563 int bottom_border
= 0;
2565 /* the default button has a border around it */
2566 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2568 GtkBorder
*default_border
= NULL
;
2569 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2572 left_border
+= default_border
->left
;
2573 right_border
+= default_border
->right
;
2574 top_border
+= default_border
->top
;
2575 bottom_border
+= default_border
->bottom
;
2576 gtk_border_free( default_border
);
2580 DoMoveWindow( m_x
- left_border
,
2582 m_width
+left_border
+right_border
,
2583 m_height
+top_border
+bottom_border
);
2586 if (m_width
!= oldSize
.x
|| m_height
!= oldSize
.y
)
2588 // update these variables to keep size_allocate handler
2589 // from sending another size event for this change
2590 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2592 gtk_widget_queue_resize(m_widget
);
2593 if (!m_nativeSizeEvent
)
2595 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2596 event
.SetEventObject( this );
2597 HandleWindowEvent( event
);
2602 bool wxWindowGTK::GtkShowFromOnIdle()
2604 if (IsShown() && m_showOnIdle
&& !GTK_WIDGET_VISIBLE (m_widget
))
2606 GtkAllocation alloc
;
2609 alloc
.width
= m_width
;
2610 alloc
.height
= m_height
;
2611 gtk_widget_size_allocate( m_widget
, &alloc
);
2612 gtk_widget_show( m_widget
);
2613 wxShowEvent
eventShow(GetId(), true);
2614 eventShow
.SetEventObject(this);
2615 HandleWindowEvent(eventShow
);
2616 m_showOnIdle
= false;
2623 void wxWindowGTK::OnInternalIdle()
2625 // Check if we have to show window now
2626 if (GtkShowFromOnIdle()) return;
2628 if ( m_dirtyTabOrder
)
2630 m_dirtyTabOrder
= false;
2634 // Update style if the window was not yet realized
2635 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2636 if (m_needsStyleChange
)
2638 SetBackgroundStyle(GetBackgroundStyle());
2639 m_needsStyleChange
= false;
2642 wxCursor cursor
= m_cursor
;
2643 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2647 /* I now set the cursor anew in every OnInternalIdle call
2648 as setting the cursor in a parent window also effects the
2649 windows above so that checking for the current cursor is
2652 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2654 GdkWindow
*window
= m_wxwindow
->window
;
2656 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2658 if (!g_globalCursor
.Ok())
2659 cursor
= *wxSTANDARD_CURSOR
;
2661 window
= m_widget
->window
;
2662 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2663 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2666 else if ( m_widget
)
2668 GdkWindow
*window
= m_widget
->window
;
2669 if ( window
&& !GTK_WIDGET_NO_WINDOW(m_widget
) )
2670 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2674 if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
2675 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2678 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2680 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2682 if (width
) (*width
) = m_width
;
2683 if (height
) (*height
) = m_height
;
2686 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2688 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2690 const wxSize size
= GetSize();
2691 const wxSize clientSize
= GetClientSize();
2692 SetSize(width
+ (size
.x
- clientSize
.x
), height
+ (size
.y
- clientSize
.y
));
2695 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2697 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2704 // if window is scrollable, account for scrollbars
2705 for (int i
= 0; i
< 2 && m_scrollBar
[i
]; i
++)
2708 GtkAdjustment
* adj
= gtk_range_get_adjustment(m_scrollBar
[i
]);
2709 // if scrollbar enabled
2710 if (adj
->upper
> adj
->page_size
)
2712 gtk_widget_size_request(GTK_WIDGET(m_scrollBar
[i
]), &req
);
2713 if (i
== ScrollDir_Horz
)
2720 int border_x
, border_y
;
2721 WX_PIZZA(m_wxwindow
)->get_border_widths(border_x
, border_y
);
2731 if (width
) *width
= w
;
2732 if (height
) *height
= h
;
2735 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2737 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2741 if (!IsTopLevel() && m_parent
&& m_parent
->m_wxwindow
)
2743 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2744 dx
= pizza
->m_scroll_x
;
2745 dy
= pizza
->m_scroll_y
;
2748 if (m_x
== -1 && m_y
== -1)
2750 GdkWindow
*source
= (GdkWindow
*) NULL
;
2752 source
= m_wxwindow
->window
;
2754 source
= m_widget
->window
;
2760 gdk_window_get_origin( source
, &org_x
, &org_y
);
2763 m_parent
->ScreenToClient(&org_x
, &org_y
);
2765 wx_const_cast(wxWindowGTK
*, this)->m_x
= org_x
;
2766 wx_const_cast(wxWindowGTK
*, this)->m_y
= org_y
;
2770 if (x
) (*x
) = m_x
- dx
;
2771 if (y
) (*y
) = m_y
- dy
;
2774 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2776 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2778 if (!m_widget
->window
) return;
2780 GdkWindow
*source
= (GdkWindow
*) NULL
;
2782 source
= m_wxwindow
->window
;
2784 source
= m_widget
->window
;
2788 gdk_window_get_origin( source
, &org_x
, &org_y
);
2792 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2794 org_x
+= m_widget
->allocation
.x
;
2795 org_y
+= m_widget
->allocation
.y
;
2802 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2803 *x
= (GetClientSize().x
- *x
) + org_x
;
2811 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
2813 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2815 if (!m_widget
->window
) return;
2817 GdkWindow
*source
= (GdkWindow
*) NULL
;
2819 source
= m_wxwindow
->window
;
2821 source
= m_widget
->window
;
2825 gdk_window_get_origin( source
, &org_x
, &org_y
);
2829 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2831 org_x
+= m_widget
->allocation
.x
;
2832 org_y
+= m_widget
->allocation
.y
;
2838 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2839 *x
= (GetClientSize().x
- *x
) - org_x
;
2846 bool wxWindowGTK::Show( bool show
)
2848 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
2850 if (!wxWindowBase::Show(show
))
2856 if (show
&& m_showOnIdle
)
2863 gtk_widget_show(m_widget
);
2865 gtk_widget_hide(m_widget
);
2866 wxShowEvent
eventShow(GetId(), show
);
2867 eventShow
.SetEventObject(this);
2868 HandleWindowEvent(eventShow
);
2874 void wxWindowGTK::DoEnable( bool enable
)
2876 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2878 gtk_widget_set_sensitive( m_widget
, enable
);
2879 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2880 gtk_widget_set_sensitive( m_wxwindow
, enable
);
2883 int wxWindowGTK::GetCharHeight() const
2885 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
2887 wxFont font
= GetFont();
2888 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
2890 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2895 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2896 PangoLayout
*layout
= pango_layout_new(context
);
2897 pango_layout_set_font_description(layout
, desc
);
2898 pango_layout_set_text(layout
, "H", 1);
2899 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2901 PangoRectangle rect
;
2902 pango_layout_line_get_extents(line
, NULL
, &rect
);
2904 g_object_unref (layout
);
2906 return (int) PANGO_PIXELS(rect
.height
);
2909 int wxWindowGTK::GetCharWidth() const
2911 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
2913 wxFont font
= GetFont();
2914 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
2916 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2921 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2922 PangoLayout
*layout
= pango_layout_new(context
);
2923 pango_layout_set_font_description(layout
, desc
);
2924 pango_layout_set_text(layout
, "g", 1);
2925 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2927 PangoRectangle rect
;
2928 pango_layout_line_get_extents(line
, NULL
, &rect
);
2930 g_object_unref (layout
);
2932 return (int) PANGO_PIXELS(rect
.width
);
2935 void wxWindowGTK::GetTextExtent( const wxString
& string
,
2939 int *externalLeading
,
2940 const wxFont
*theFont
) const
2942 wxFont fontToUse
= theFont
? *theFont
: GetFont();
2944 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
2953 PangoContext
*context
= NULL
;
2955 context
= gtk_widget_get_pango_context( m_widget
);
2964 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
2965 PangoLayout
*layout
= pango_layout_new(context
);
2966 pango_layout_set_font_description(layout
, desc
);
2968 const wxCharBuffer data
= wxGTK_CONV( string
);
2970 pango_layout_set_text(layout
, data
, strlen(data
));
2973 PangoRectangle rect
;
2974 pango_layout_get_extents(layout
, NULL
, &rect
);
2976 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
2977 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
2980 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
2981 int baseline
= pango_layout_iter_get_baseline(iter
);
2982 pango_layout_iter_free(iter
);
2983 *descent
= *y
- PANGO_PIXELS(baseline
);
2985 if (externalLeading
) (*externalLeading
) = 0; // ??
2987 g_object_unref (layout
);
2990 bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
2992 if ( g_delayedFocus
== this )
2994 if ( GTK_WIDGET_REALIZED(m_widget
) )
2996 gtk_widget_grab_focus(m_widget
);
2997 g_delayedFocus
= NULL
;
3006 void wxWindowGTK::SetFocus()
3008 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3011 // don't do anything if we already have focus
3017 // wxWindow::SetFocus() should really set the focus to
3018 // this control, whatever the flags are
3019 if (!GTK_WIDGET_CAN_FOCUS(m_wxwindow
))
3020 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3022 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3024 gtk_widget_grab_focus (m_wxwindow
);
3029 // wxWindow::SetFocus() should really set the focus to
3030 // this control, whatever the flags are
3031 if (!GTK_WIDGET_CAN_FOCUS(m_widget
))
3032 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3034 if (GTK_IS_CONTAINER(m_widget
))
3036 if (GTK_IS_RADIO_BUTTON(m_widget
))
3038 gtk_widget_grab_focus (m_widget
);
3042 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3045 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3048 if (!GTK_WIDGET_REALIZED(m_widget
))
3050 // we can't set the focus to the widget now so we remember that
3051 // it should be focused and will do it later, during the idle
3052 // time, as soon as we can
3053 wxLogTrace(TRACE_FOCUS
,
3054 _T("Delaying setting focus to %s(%s)"),
3055 GetClassInfo()->GetClassName(), GetLabel().c_str());
3057 g_delayedFocus
= this;
3061 wxLogTrace(TRACE_FOCUS
,
3062 _T("Setting focus to %s(%s)"),
3063 GetClassInfo()->GetClassName(), GetLabel().c_str());
3065 gtk_widget_grab_focus (m_widget
);
3070 wxLogTrace(TRACE_FOCUS
,
3071 _T("Can't set focus to %s(%s)"),
3072 GetClassInfo()->GetClassName(), GetLabel().c_str());
3077 void wxWindowGTK::SetCanFocus(bool canFocus
)
3080 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3082 GTK_WIDGET_UNSET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3084 if ( m_wxwindow
&& (m_widget
!= m_wxwindow
) )
3087 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3089 GTK_WIDGET_UNSET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3093 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3095 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3097 wxWindowGTK
*oldParent
= m_parent
,
3098 *newParent
= (wxWindowGTK
*)newParentBase
;
3100 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3102 if ( !wxWindowBase::Reparent(newParent
) )
3105 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3107 /* prevent GTK from deleting the widget arbitrarily */
3108 gtk_widget_ref( m_widget
);
3112 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3115 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3119 if (GTK_WIDGET_VISIBLE (newParent
->m_widget
))
3121 m_showOnIdle
= true;
3122 gtk_widget_hide( m_widget
);
3125 /* insert GTK representation */
3126 (*(newParent
->m_insertCallback
))(newParent
, this);
3129 /* reverse: prevent GTK from deleting the widget arbitrarily */
3130 gtk_widget_unref( m_widget
);
3132 SetLayoutDirection(wxLayout_Default
);
3137 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3139 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3140 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3145 /* insert GTK representation */
3146 (*m_insertCallback
)(this, child
);
3149 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3151 wxWindowBase::AddChild(child
);
3152 m_dirtyTabOrder
= true;
3153 wxTheApp
->WakeUpIdle();
3156 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3158 wxWindowBase::RemoveChild(child
);
3159 m_dirtyTabOrder
= true;
3160 wxTheApp
->WakeUpIdle();
3164 wxLayoutDirection
wxWindowGTK::GTKGetLayout(GtkWidget
*widget
)
3166 return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
3167 ? wxLayout_RightToLeft
3168 : wxLayout_LeftToRight
;
3172 void wxWindowGTK::GTKSetLayout(GtkWidget
*widget
, wxLayoutDirection dir
)
3174 wxASSERT_MSG( dir
!= wxLayout_Default
, _T("invalid layout direction") );
3176 gtk_widget_set_direction(widget
,
3177 dir
== wxLayout_RightToLeft
? GTK_TEXT_DIR_RTL
3178 : GTK_TEXT_DIR_LTR
);
3181 wxLayoutDirection
wxWindowGTK::GetLayoutDirection() const
3183 return GTKGetLayout(m_widget
);
3186 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
)
3188 if ( dir
== wxLayout_Default
)
3190 const wxWindow
*const parent
= GetParent();
3193 // inherit layout from parent.
3194 dir
= parent
->GetLayoutDirection();
3196 else // no parent, use global default layout
3198 dir
= wxTheApp
->GetLayoutDirection();
3202 if ( dir
== wxLayout_Default
)
3205 GTKSetLayout(m_widget
, dir
);
3207 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3208 GTKSetLayout(m_wxwindow
, dir
);
3212 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
,
3213 wxCoord
WXUNUSED(width
),
3214 wxCoord
WXUNUSED(widthTotal
)) const
3216 // We now mirror the coordinates of RTL windows in wxPizza
3220 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, WindowOrder move
)
3222 wxWindowBase::DoMoveInTabOrder(win
, move
);
3223 m_dirtyTabOrder
= true;
3224 wxTheApp
->WakeUpIdle();
3227 bool wxWindowGTK::DoNavigateIn(int flags
)
3229 if ( flags
& wxNavigationKeyEvent::WinChange
)
3231 wxFAIL_MSG( _T("not implemented") );
3235 else // navigate inside the container
3237 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3238 wxCHECK_MSG( parent
, false, _T("every window must have a TLW parent") );
3240 GtkDirectionType dir
;
3241 dir
= flags
& wxNavigationKeyEvent::IsForward
? GTK_DIR_TAB_FORWARD
3242 : GTK_DIR_TAB_BACKWARD
;
3245 g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
);
3251 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3253 // none needed by default
3257 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3259 // nothing to do by default since none is needed
3262 void wxWindowGTK::RealizeTabOrder()
3266 if ( !m_children
.empty() )
3268 // we don't only construct the correct focus chain but also use
3269 // this opportunity to update the mnemonic widgets for the widgets
3272 GList
*chain
= NULL
;
3273 wxWindowGTK
* mnemonicWindow
= NULL
;
3275 for ( wxWindowList::const_iterator i
= m_children
.begin();
3276 i
!= m_children
.end();
3279 wxWindowGTK
*win
= *i
;
3281 if ( mnemonicWindow
)
3283 if ( win
->AcceptsFocusFromKeyboard() )
3285 // wxComboBox et al. needs to focus on on a different
3286 // widget than m_widget, so if the main widget isn't
3287 // focusable try the connect widget
3288 GtkWidget
* w
= win
->m_widget
;
3289 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3291 w
= win
->GetConnectWidget();
3292 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3298 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3299 mnemonicWindow
= NULL
;
3303 else if ( win
->GTKWidgetNeedsMnemonic() )
3305 mnemonicWindow
= win
;
3308 chain
= g_list_prepend(chain
, win
->m_widget
);
3311 chain
= g_list_reverse(chain
);
3313 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3318 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3323 void wxWindowGTK::Raise()
3325 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3327 if (m_wxwindow
&& m_wxwindow
->window
)
3329 gdk_window_raise( m_wxwindow
->window
);
3331 else if (m_widget
->window
)
3333 gdk_window_raise( m_widget
->window
);
3337 void wxWindowGTK::Lower()
3339 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3341 if (m_wxwindow
&& m_wxwindow
->window
)
3343 gdk_window_lower( m_wxwindow
->window
);
3345 else if (m_widget
->window
)
3347 gdk_window_lower( m_widget
->window
);
3351 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3353 if ( !wxWindowBase::SetCursor(cursor
.Ok() ? cursor
: *wxSTANDARD_CURSOR
) )
3361 void wxWindowGTK::GTKUpdateCursor()
3363 wxCursor
cursor(g_globalCursor
.Ok() ? g_globalCursor
: GetCursor());
3366 wxArrayGdkWindows windowsThis
;
3367 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3370 gdk_window_set_cursor(winThis
, cursor
.GetCursor());
3374 const size_t count
= windowsThis
.size();
3375 for ( size_t n
= 0; n
< count
; n
++ )
3377 GdkWindow
*win
= windowsThis
[n
];
3380 wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?"));
3384 gdk_window_set_cursor(win
, cursor
.GetCursor());
3390 void wxWindowGTK::WarpPointer( int x
, int y
)
3392 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3394 // We provide this function ourselves as it is
3395 // missing in GDK (top of this file).
3397 GdkWindow
*window
= (GdkWindow
*) NULL
;
3399 window
= m_wxwindow
->window
;
3401 window
= GetConnectWidget()->window
;
3404 gdk_window_warp_pointer( window
, x
, y
);
3407 wxWindowGTK::ScrollDir
wxWindowGTK::ScrollDirFromRange(GtkRange
*range
) const
3409 // find the scrollbar which generated the event
3410 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3412 if ( range
== m_scrollBar
[dir
] )
3413 return (ScrollDir
)dir
;
3416 wxFAIL_MSG( _T("event from unknown scrollbar received") );
3418 return ScrollDir_Max
;
3421 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3423 bool changed
= false;
3424 GtkRange
* range
= m_scrollBar
[dir
];
3425 if ( range
&& units
)
3427 GtkAdjustment
* adj
= range
->adjustment
;
3428 gdouble inc
= unit
== ScrollUnit_Line
? adj
->step_increment
3429 : adj
->page_increment
;
3431 const int posOld
= int(adj
->value
+ 0.5);
3432 gtk_range_set_value(range
, posOld
+ units
*inc
);
3434 changed
= int(adj
->value
+ 0.5) != posOld
;
3440 bool wxWindowGTK::ScrollLines(int lines
)
3442 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3445 bool wxWindowGTK::ScrollPages(int pages
)
3447 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3450 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground
),
3455 if (!m_widget
->window
)
3460 if (m_wxwindow
->window
== NULL
) return;
3462 GdkRectangle gdk_rect
,
3466 gdk_rect
.x
= rect
->x
;
3467 gdk_rect
.y
= rect
->y
;
3468 gdk_rect
.width
= rect
->width
;
3469 gdk_rect
.height
= rect
->height
;
3470 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3471 gdk_rect
.x
= GetClientSize().x
- gdk_rect
.x
- gdk_rect
.width
;
3475 else // invalidate everything
3480 gdk_window_invalidate_rect(m_wxwindow
->window
, p
, true);
3484 void wxWindowGTK::Update()
3488 // when we call Update() we really want to update the window immediately on
3489 // screen, even if it means flushing the entire queue and hence slowing down
3490 // everything -- but it should still be done, it's just that Update() should
3491 // be called very rarely
3495 void wxWindowGTK::GtkUpdate()
3497 if (m_wxwindow
&& m_wxwindow
->window
)
3498 gdk_window_process_updates(m_wxwindow
->window
, false);
3499 if (m_widget
&& m_widget
->window
&& (m_wxwindow
!= m_widget
))
3500 gdk_window_process_updates( m_widget
->window
, FALSE
);
3502 // for consistency with other platforms (and also because it's convenient
3503 // to be able to update an entire TLW by calling Update() only once), we
3504 // should also update all our children here
3505 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3507 node
= node
->GetNext() )
3509 node
->GetData()->GtkUpdate();
3513 bool wxWindowGTK::DoIsExposed( int x
, int y
) const
3515 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
3519 bool wxWindowGTK::DoIsExposed( int x
, int y
, int w
, int h
) const
3521 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3522 return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
;
3524 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
3527 void wxWindowGTK::GtkSendPaintEvents()
3531 m_updateRegion
.Clear();
3535 // Clip to paint region in wxClientDC
3536 m_clipPaintRegion
= true;
3538 m_nativeUpdateRegion
= m_updateRegion
;
3540 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3542 // Transform m_updateRegion under RTL
3543 m_updateRegion
.Clear();
3546 gdk_drawable_get_size(m_wxwindow
->window
, &width
, NULL
);
3548 wxRegionIterator
upd( m_nativeUpdateRegion
);
3552 rect
.x
= upd
.GetX();
3553 rect
.y
= upd
.GetY();
3554 rect
.width
= upd
.GetWidth();
3555 rect
.height
= upd
.GetHeight();
3557 rect
.x
= width
- rect
.x
- rect
.width
;
3558 m_updateRegion
.Union( rect
);
3564 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3566 // find ancestor from which to steal background
3567 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3569 parent
= (wxWindow
*)this;
3571 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3573 wxRegionIterator
upd( m_nativeUpdateRegion
);
3577 rect
.x
= upd
.GetX();
3578 rect
.y
= upd
.GetY();
3579 rect
.width
= upd
.GetWidth();
3580 rect
.height
= upd
.GetHeight();
3582 gtk_paint_flat_box( parent
->m_widget
->style
,
3584 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3597 wxWindowDC
dc( (wxWindow
*)this );
3598 dc
.SetClippingRegion( m_updateRegion
);
3600 // Work around gtk-qt <= 0.60 bug whereby the window colour
3602 if (GetBackgroundStyle() == wxBG_STYLE_COLOUR
&& GetBackgroundColour().Ok() && wxSystemOptions::GetOptionInt(wxT("gtk.window.force-background-colour")) == 1)
3604 dc
.SetBackground(wxBrush(GetBackgroundColour()));
3608 wxEraseEvent
erase_event( GetId(), &dc
);
3609 erase_event
.SetEventObject( this );
3611 HandleWindowEvent(erase_event
);
3614 wxNcPaintEvent
nc_paint_event( GetId() );
3615 nc_paint_event
.SetEventObject( this );
3616 HandleWindowEvent( nc_paint_event
);
3618 wxPaintEvent
paint_event( GetId() );
3619 paint_event
.SetEventObject( this );
3620 HandleWindowEvent( paint_event
);
3622 m_clipPaintRegion
= false;
3624 m_updateRegion
.Clear();
3625 m_nativeUpdateRegion
.Clear();
3628 void wxWindowGTK::SetDoubleBuffered( bool on
)
3630 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3633 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3636 bool wxWindowGTK::IsDoubleBuffered() const
3638 return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow
);
3641 void wxWindowGTK::ClearBackground()
3643 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3647 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3649 wxWindowBase::DoSetToolTip(tip
);
3652 m_tooltip
->Apply( (wxWindow
*)this );
3655 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const gchar
*tip
)
3657 gtk_tooltips_set_tip(tips
, GetConnectWidget(), tip
, NULL
);
3659 #endif // wxUSE_TOOLTIPS
3661 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3663 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3665 if (!wxWindowBase::SetBackgroundColour(colour
))
3670 // We need the pixel value e.g. for background clearing.
3671 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3674 // apply style change (forceStyle=true so that new style is applied
3675 // even if the bg colour changed from valid to wxNullColour)
3676 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3677 ApplyWidgetStyle(true);
3682 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3684 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3686 if (!wxWindowBase::SetForegroundColour(colour
))
3693 // We need the pixel value e.g. for background clearing.
3694 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3697 // apply style change (forceStyle=true so that new style is applied
3698 // even if the bg colour changed from valid to wxNullColour):
3699 ApplyWidgetStyle(true);
3704 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3706 return gtk_widget_get_pango_context( m_widget
);
3709 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3711 // do we need to apply any changes at all?
3714 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3719 GtkRcStyle
*style
= gtk_rc_style_new();
3724 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3727 int flagsNormal
= 0,
3730 flagsInsensitive
= 0;
3732 if ( m_foregroundColour
.Ok() )
3734 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3736 style
->fg
[GTK_STATE_NORMAL
] =
3737 style
->text
[GTK_STATE_NORMAL
] = *fg
;
3738 flagsNormal
|= GTK_RC_FG
| GTK_RC_TEXT
;
3740 style
->fg
[GTK_STATE_PRELIGHT
] =
3741 style
->text
[GTK_STATE_PRELIGHT
] = *fg
;
3742 flagsPrelight
|= GTK_RC_FG
| GTK_RC_TEXT
;
3744 style
->fg
[GTK_STATE_ACTIVE
] =
3745 style
->text
[GTK_STATE_ACTIVE
] = *fg
;
3746 flagsActive
|= GTK_RC_FG
| GTK_RC_TEXT
;
3749 if ( m_backgroundColour
.Ok() )
3751 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3753 style
->bg
[GTK_STATE_NORMAL
] =
3754 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3755 flagsNormal
|= GTK_RC_BG
| GTK_RC_BASE
;
3757 style
->bg
[GTK_STATE_PRELIGHT
] =
3758 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3759 flagsPrelight
|= GTK_RC_BG
| GTK_RC_BASE
;
3761 style
->bg
[GTK_STATE_ACTIVE
] =
3762 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3763 flagsActive
|= GTK_RC_BG
| GTK_RC_BASE
;
3765 style
->bg
[GTK_STATE_INSENSITIVE
] =
3766 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3767 flagsInsensitive
|= GTK_RC_BG
| GTK_RC_BASE
;
3770 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
;
3771 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
;
3772 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
;
3773 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
;
3778 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3780 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3783 DoApplyWidgetStyle(style
);
3784 gtk_rc_style_unref(style
);
3787 // Style change may affect GTK+'s size calculation:
3788 InvalidateBestSize();
3791 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3793 wxSuspendStyleEvents
s(static_cast<wxWindow
*>(this));
3796 gtk_widget_modify_style(m_wxwindow
, style
);
3798 gtk_widget_modify_style(m_widget
, style
);
3801 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3803 wxWindowBase::SetBackgroundStyle(style
);
3805 if (style
== wxBG_STYLE_CUSTOM
)
3810 window
= m_wxwindow
->window
;
3814 GtkWidget
* const w
= GetConnectWidget();
3815 window
= w
? w
->window
: NULL
;
3820 // Make sure GDK/X11 doesn't refresh the window
3822 gdk_window_set_back_pixmap( window
, None
, False
);
3824 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3827 m_needsStyleChange
= false;
3829 else // window not realized yet
3831 // Do in OnIdle, because the window is not yet available
3832 m_needsStyleChange
= true;
3835 // Don't apply widget style, or we get a grey background
3839 // apply style change (forceStyle=true so that new style is applied
3840 // even if the bg colour changed from valid to wxNullColour):
3841 ApplyWidgetStyle(true);
3846 #if wxUSE_DRAG_AND_DROP
3848 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3850 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3852 GtkWidget
*dnd_widget
= GetConnectWidget();
3854 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3856 if (m_dropTarget
) delete m_dropTarget
;
3857 m_dropTarget
= dropTarget
;
3859 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3862 #endif // wxUSE_DRAG_AND_DROP
3864 GtkWidget
* wxWindowGTK::GetConnectWidget()
3866 GtkWidget
*connect_widget
= m_widget
;
3867 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3869 return connect_widget
;
3872 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow
*window
) const
3874 wxArrayGdkWindows windowsThis
;
3875 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3877 return winThis
? window
== winThis
3878 : windowsThis
.Index(window
) != wxNOT_FOUND
;
3881 GdkWindow
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
3883 return m_wxwindow
? m_wxwindow
->window
: m_widget
->window
;
3886 bool wxWindowGTK::SetFont( const wxFont
&font
)
3888 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3890 if (!wxWindowBase::SetFont(font
))
3893 // apply style change (forceStyle=true so that new style is applied
3894 // even if the font changed from valid to wxNullFont):
3895 ApplyWidgetStyle(true);
3900 void wxWindowGTK::DoCaptureMouse()
3902 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3904 GdkWindow
*window
= (GdkWindow
*) NULL
;
3906 window
= m_wxwindow
->window
;
3908 window
= GetConnectWidget()->window
;
3910 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3912 const wxCursor
* cursor
= &m_cursor
;
3914 cursor
= wxSTANDARD_CURSOR
;
3916 gdk_pointer_grab( window
, FALSE
,
3918 (GDK_BUTTON_PRESS_MASK
|
3919 GDK_BUTTON_RELEASE_MASK
|
3920 GDK_POINTER_MOTION_HINT_MASK
|
3921 GDK_POINTER_MOTION_MASK
),
3923 cursor
->GetCursor(),
3924 (guint32
)GDK_CURRENT_TIME
);
3925 g_captureWindow
= this;
3926 g_captureWindowHasMouse
= true;
3929 void wxWindowGTK::DoReleaseMouse()
3931 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3933 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3935 g_captureWindow
= (wxWindowGTK
*) NULL
;
3937 GdkWindow
*window
= (GdkWindow
*) NULL
;
3939 window
= m_wxwindow
->window
;
3941 window
= GetConnectWidget()->window
;
3946 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3949 void wxWindowGTK::GTKReleaseMouseAndNotify()
3952 wxMouseCaptureLostEvent
evt(GetId());
3953 evt
.SetEventObject( this );
3954 HandleWindowEvent( evt
);
3958 wxWindow
*wxWindowBase::GetCapture()
3960 return (wxWindow
*)g_captureWindow
;
3963 bool wxWindowGTK::IsRetained() const
3968 void wxWindowGTK::SetScrollbar(int orient
,
3972 bool WXUNUSED(update
))
3974 const int dir
= ScrollDirFromOrient(orient
);
3975 GtkRange
* const sb
= m_scrollBar
[dir
];
3976 wxCHECK_RET( sb
, _T("this window is not scrollable") );
3980 // GtkRange requires upper > lower
3985 GtkAdjustment
* const adj
= sb
->adjustment
;
3986 adj
->step_increment
= 1;
3987 adj
->page_increment
=
3988 adj
->page_size
= thumbVisible
;
3991 g_signal_handlers_block_by_func(
3992 sb
, (void*)gtk_scrollbar_value_changed
, this);
3994 gtk_range_set_range(sb
, 0, range
);
3995 m_scrollPos
[dir
] = sb
->adjustment
->value
;
3997 g_signal_handlers_unblock_by_func(
3998 sb
, (void*)gtk_scrollbar_value_changed
, this);
4001 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4003 const int dir
= ScrollDirFromOrient(orient
);
4004 GtkRange
* const sb
= m_scrollBar
[dir
];
4005 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4007 // This check is more than an optimization. Without it, the slider
4008 // will not move smoothly while tracking when using wxScrollHelper.
4009 if (GetScrollPos(orient
) != pos
)
4011 g_signal_handlers_block_by_func(
4012 sb
, (void*)gtk_scrollbar_value_changed
, this);
4014 gtk_range_set_value(sb
, pos
);
4015 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4017 g_signal_handlers_unblock_by_func(
4018 sb
, (void*)gtk_scrollbar_value_changed
, this);
4022 int wxWindowGTK::GetScrollThumb(int orient
) const
4024 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4025 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4027 return int(sb
->adjustment
->page_size
);
4030 int wxWindowGTK::GetScrollPos( int orient
) const
4032 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4033 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4035 return int(sb
->adjustment
->value
+ 0.5);
4038 int wxWindowGTK::GetScrollRange( int orient
) const
4040 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4041 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4043 return int(sb
->adjustment
->upper
);
4046 // Determine if increment is the same as +/-x, allowing for some small
4047 // difference due to possible inexactness in floating point arithmetic
4048 static inline bool IsScrollIncrement(double increment
, double x
)
4050 wxASSERT(increment
> 0);
4051 const double tolerance
= 1.0 / 1024;
4052 return fabs(increment
- fabs(x
)) < tolerance
;
4055 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4057 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4059 const int barIndex
= range
== m_scrollBar
[1];
4060 GtkAdjustment
* adj
= range
->adjustment
;
4062 const int value
= int(adj
->value
+ 0.5);
4064 // save previous position
4065 const double oldPos
= m_scrollPos
[barIndex
];
4066 // update current position
4067 m_scrollPos
[barIndex
] = adj
->value
;
4068 // If event should be ignored, or integral position has not changed
4069 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4074 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4077 // Difference from last change event
4078 const double diff
= adj
->value
- oldPos
;
4079 const bool isDown
= diff
> 0;
4081 if (IsScrollIncrement(adj
->step_increment
, diff
))
4083 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4085 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4087 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4089 else if (m_mouseButtonDown
)
4091 // Assume track event
4092 m_isScrolling
= true;
4098 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4100 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4102 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4104 // No scrolling requested.
4105 if ((dx
== 0) && (dy
== 0)) return;
4107 m_clipPaintRegion
= true;
4109 WX_PIZZA(m_wxwindow
)->scroll(dx
, dy
);
4111 m_clipPaintRegion
= false;
4114 bool restoreCaret
= (GetCaret() != NULL
&& GetCaret()->IsVisible());
4117 wxRect
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4119 caretRect
.width
+= dx
;
4122 caretRect
.x
+= dx
; caretRect
.width
-= dx
;
4125 caretRect
.height
+= dy
;
4128 caretRect
.y
+= dy
; caretRect
.height
-= dy
;
4131 RefreshRect(caretRect
);
4133 #endif // wxUSE_CARET
4136 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4138 //RN: Note that static controls usually have no border on gtk, so maybe
4139 //it makes sense to treat that as simply no border at the wx level
4141 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4143 GtkShadowType gtkstyle
;
4145 if(wxstyle
& wxBORDER_RAISED
)
4146 gtkstyle
= GTK_SHADOW_OUT
;
4147 else if (wxstyle
& wxBORDER_SUNKEN
)
4148 gtkstyle
= GTK_SHADOW_IN
;
4151 else if (wxstyle
& wxBORDER_DOUBLE
)
4152 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4155 gtkstyle
= GTK_SHADOW_IN
;
4157 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4162 void wxWindowGTK::SetWindowStyleFlag( long style
)
4164 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4165 wxWindowBase::SetWindowStyleFlag(style
);
4168 // Find the wxWindow at the current mouse position, also returning the mouse
4170 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4172 pt
= wxGetMousePosition();
4173 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4177 // Get the current mouse position.
4178 wxPoint
wxGetMousePosition()
4180 /* This crashes when used within wxHelpContext,
4181 so we have to use the X-specific implementation below.
4183 GdkModifierType *mask;
4184 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4186 return wxPoint(x, y);
4190 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4192 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4193 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4194 Window rootReturn
, childReturn
;
4195 int rootX
, rootY
, winX
, winY
;
4196 unsigned int maskReturn
;
4198 XQueryPointer (display
,
4202 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4203 return wxPoint(rootX
, rootY
);
4207 GdkWindow
* wxWindowGTK::GTKGetDrawingWindow() const
4209 GdkWindow
* window
= NULL
;
4211 window
= m_wxwindow
->window
;