1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
22 #include "wx/toplevel.h"
23 #include "wx/dcclient.h"
25 #include "wx/settings.h"
26 #include "wx/msgdlg.h"
31 #include "wx/tooltip.h"
33 #include "wx/fontutil.h"
34 #include "wx/sysopt.h"
38 #include "wx/gtk/private.h"
39 #include "wx/gtk/private/win_gtk.h"
40 #include <gdk/gdkkeysyms.h>
43 //-----------------------------------------------------------------------------
44 // documentation on internals
45 //-----------------------------------------------------------------------------
48 I have been asked several times about writing some documentation about
49 the GTK port of wxWidgets, especially its internal structures. Obviously,
50 you cannot understand wxGTK without knowing a little about the GTK, but
51 some more information about what the wxWindow, which is the base class
52 for all other window classes, does seems required as well.
56 What does wxWindow do? It contains the common interface for the following
57 jobs of its descendants:
59 1) Define the rudimentary behaviour common to all window classes, such as
60 resizing, intercepting user input (so as to make it possible to use these
61 events for special purposes in a derived class), window names etc.
63 2) Provide the possibility to contain and manage children, if the derived
64 class is allowed to contain children, which holds true for those window
65 classes which do not display a native GTK widget. To name them, these
66 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
67 work classes are a special case and are handled a bit differently from
68 the rest. The same holds true for the wxNotebook class.
70 3) Provide the possibility to draw into a client area of a window. This,
71 too, only holds true for classes that do not display a native GTK widget
74 4) Provide the entire mechanism for scrolling widgets. This actual inter-
75 face for this is usually in wxScrolledWindow, but the GTK implementation
78 5) A multitude of helper or extra methods for special purposes, such as
79 Drag'n'Drop, managing validators etc.
81 6) Display a border (sunken, raised, simple or none).
83 Normally one might expect, that one wxWidgets window would always correspond
84 to one GTK widget. Under GTK, there is no such all-round widget that has all
85 the functionality. Moreover, the GTK defines a client area as a different
86 widget from the actual widget you are handling. Last but not least some
87 special classes (e.g. wxFrame) handle different categories of widgets and
88 still have the possibility to draw something in the client area.
89 It was therefore required to write a special purpose GTK widget, that would
90 represent a client area in the sense of wxWidgets capable to do the jobs
91 2), 3) and 4). I have written this class and it resides in win_gtk.c of
94 All windows must have a widget, with which they interact with other under-
95 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
96 the wxWindow class has a member variable called m_widget which holds a
97 pointer to this widget. When the window class represents a GTK native widget,
98 this is (in most cases) the only GTK widget the class manages. E.g. the
99 wxStaticText class handles only a GtkLabel widget a pointer to which you
100 can find in m_widget (defined in wxWindow)
102 When the class has a client area for drawing into and for containing children
103 it has to handle the client area widget (of the type wxPizza, defined in
104 win_gtk.cpp), but there could be any number of widgets, handled by a class.
105 The common rule for all windows is only, that the widget that interacts with
106 the rest of GTK must be referenced in m_widget and all other widgets must be
107 children of this widget on the GTK level. The top-most widget, which also
108 represents the client area, must be in the m_wxwindow field and must be of
111 As I said, the window classes that display a GTK native widget only have
112 one widget, so in the case of e.g. the wxButton class m_widget holds a
113 pointer to a GtkButton widget. But windows with client areas (for drawing
114 and children) have a m_widget field that is a pointer to a GtkScrolled-
115 Window and a m_wxwindow field that is pointer to a wxPizza and this
116 one is (in the GTK sense) a child of the GtkScrolledWindow.
118 If the m_wxwindow field is set, then all input to this widget is inter-
119 cepted and sent to the wxWidgets class. If not, all input to the widget
120 that gets pointed to by m_widget gets intercepted and sent to the class.
124 The design of scrolling in wxWidgets is markedly different from that offered
125 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
126 clicking on a scrollbar belonging to scrolled window will inevitably move
127 the window. In wxWidgets, the scrollbar will only emit an event, send this
128 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
129 which actually moves the window and its sub-windows. Note that wxPizza
130 memorizes how much it has been scrolled but that wxWidgets forgets this
131 so that the two coordinates systems have to be kept in synch. This is done
132 in various places using the pizza->m_scroll_x and pizza->m_scroll_y values.
136 Singularly the most broken code in GTK is the code that is supposed to
137 inform subwindows (child windows) about new positions. Very often, duplicate
138 events are sent without changes in size or position, equally often no
139 events are sent at all (All this is due to a bug in the GtkContainer code
140 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
141 GTK's own system and it simply waits for size events for toplevel windows
142 and then iterates down the respective size events to all window. This has
143 the disadvantage that windows might get size events before the GTK widget
144 actually has the reported size. This doesn't normally pose any problem, but
145 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
146 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
147 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
148 window that is used for OpenGL output really has that size (as reported by
153 If someone at some point of time feels the immense desire to have a look at,
154 change or attempt to optimise the Refresh() logic, this person will need an
155 intimate understanding of what "draw" and "expose" events are and what
156 they are used for, in particular when used in connection with GTK's
157 own windowless widgets. Beware.
161 Cursors, too, have been a constant source of pleasure. The main difficulty
162 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
163 for the parent. To prevent this from doing too much harm, I use idle time
164 to set the cursor over and over again, starting from the toplevel windows
165 and ending with the youngest generation (speaking of parent and child windows).
166 Also don't forget that cursors (like much else) are connected to GdkWindows,
167 not GtkWidgets and that the "window" field of a GtkWidget might very well
168 point to the GdkWindow of the parent widget (-> "window-less widget") and
169 that the two obviously have very different meanings.
173 //-----------------------------------------------------------------------------
175 //-----------------------------------------------------------------------------
177 // Don't allow event propagation during drag
178 bool g_blockEventsOnDrag
;
179 // Don't allow mouse event propagation during scroll
180 bool g_blockEventsOnScroll
;
181 extern wxCursor g_globalCursor
;
183 // mouse capture state: the window which has it and if the mouse is currently
185 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
186 static bool g_captureWindowHasMouse
= false;
188 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
190 // If a window get the focus set but has not been realized
191 // yet, defer setting the focus to idle time.
192 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
194 // global variables because GTK+ DnD want to have the
195 // mouse event that caused it
196 GdkEvent
*g_lastMouseEvent
= (GdkEvent
*) NULL
;
197 int g_lastButtonNumber
= 0;
199 //-----------------------------------------------------------------------------
201 //-----------------------------------------------------------------------------
203 // the trace mask used for the focus debugging messages
204 #define TRACE_FOCUS _T("focus")
206 //-----------------------------------------------------------------------------
207 // missing gdk functions
208 //-----------------------------------------------------------------------------
211 gdk_window_warp_pointer (GdkWindow
*window
,
216 window
= gdk_get_default_root_window();
218 if (!GDK_WINDOW_DESTROYED(window
))
220 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
221 None
, /* not source window -> move from anywhere */
222 GDK_WINDOW_XID(window
), /* dest window */
223 0, 0, 0, 0, /* not source window -> move from anywhere */
228 //-----------------------------------------------------------------------------
229 // local code (see below)
230 //-----------------------------------------------------------------------------
232 // returns the child of win which currently has focus or NULL if not found
233 static wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
235 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
237 return (wxWindow
*)NULL
;
239 if ( winFocus
== win
)
240 return (wxWindow
*)win
;
242 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
244 node
= node
->GetNext() )
246 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
251 return (wxWindow
*)NULL
;
254 //-----------------------------------------------------------------------------
255 // "size_request" of m_widget
256 //-----------------------------------------------------------------------------
258 // make it extern because wxStaticText needs to disconnect this one
260 void wxgtk_window_size_request_callback(GtkWidget
* WXUNUSED(widget
),
261 GtkRequisition
*requisition
,
265 win
->GetSize( &w
, &h
);
271 requisition
->height
= h
;
272 requisition
->width
= w
;
276 //-----------------------------------------------------------------------------
277 // "expose_event" of m_wxwindow
278 //-----------------------------------------------------------------------------
282 gtk_window_expose_callback( GtkWidget
*,
283 GdkEventExpose
*gdk_event
,
289 wxPrintf( wxT("OnExpose from ") );
290 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
291 wxPrintf( win
->GetClassInfo()->GetClassName() );
292 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
293 (int)gdk_event
->area
.y
,
294 (int)gdk_event
->area
.width
,
295 (int)gdk_event
->area
.height
);
300 win
->m_wxwindow
->style
,
304 (GdkRectangle
*) NULL
,
306 (char *)"button", // const_cast
311 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
313 win
->GtkSendPaintEvents();
315 // Let parent window draw window-less widgets
320 //-----------------------------------------------------------------------------
321 // "expose_event" from m_widget, for drawing border
322 //-----------------------------------------------------------------------------
324 #ifndef __WXUNIVERSAL__
326 GtkWidget
* GetEntryWidget();
330 expose_event_border(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxWindow
* win
)
332 // if this event is not for the GdkWindow the border is drawn on
333 if (win
->m_wxwindow
== win
->m_widget
&& gdk_event
->window
== widget
->window
)
338 // GtkScrolledWindow is GTK_NO_WINDOW
339 if (GTK_WIDGET_NO_WINDOW(widget
))
341 x
= widget
->allocation
.x
;
342 y
= widget
->allocation
.y
;
344 int w
= win
->m_wxwindow
->allocation
.width
;
345 int h
= win
->m_wxwindow
->allocation
.height
;
346 if (win
->HasFlag(wxBORDER_SIMPLE
))
348 GdkGC
* gc
= gdk_gc_new(gdk_event
->window
);
349 gdk_gc_set_foreground(gc
, &widget
->style
->black
);
350 gdk_draw_rectangle(gdk_event
->window
, gc
, false, x
, y
, w
- 1, h
- 1);
355 GtkShadowType shadow
= GTK_SHADOW_IN
;
356 if (win
->HasFlag(wxBORDER_RAISED
))
357 shadow
= GTK_SHADOW_OUT
;
359 // Style detail to use
361 if (widget
== win
->m_wxwindow
)
362 // for non-scrollable wxWindows
365 // for scrollable ones
368 GtkWidget
* styleWidget
= GetEntryWidget();
370 styleWidget
->style
, gdk_event
->window
, GTK_STATE_NORMAL
,
371 shadow
, NULL
, styleWidget
, detail
, x
, y
, w
, h
);
374 // no further painting is needed for border-only GdkWindow
375 return win
->m_wxwindow
== win
->m_widget
;
378 #endif // !__WXUNIVERSAL__
380 //-----------------------------------------------------------------------------
381 // "key_press_event" from any window
382 //-----------------------------------------------------------------------------
384 // These are used when transforming Ctrl-alpha to ascii values 1-26
385 inline bool wxIsLowerChar(int code
)
387 return (code
>= 'a' && code
<= 'z' );
390 inline bool wxIsUpperChar(int code
)
392 return (code
>= 'A' && code
<= 'Z' );
396 // set WXTRACE to this to see the key event codes on the console
397 #define TRACE_KEYS _T("keyevent")
399 // translates an X key symbol to WXK_XXX value
401 // if isChar is true it means that the value returned will be used for EVT_CHAR
402 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
403 // for example, while if it is false it means that the value is going to be
404 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
406 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
412 // Shift, Control and Alt don't generate the CHAR events at all
415 key_code
= isChar
? 0 : WXK_SHIFT
;
419 key_code
= isChar
? 0 : WXK_CONTROL
;
427 key_code
= isChar
? 0 : WXK_ALT
;
430 // neither do the toggle modifies
431 case GDK_Scroll_Lock
:
432 key_code
= isChar
? 0 : WXK_SCROLL
;
436 key_code
= isChar
? 0 : WXK_CAPITAL
;
440 key_code
= isChar
? 0 : WXK_NUMLOCK
;
444 // various other special keys
457 case GDK_ISO_Left_Tab
:
464 key_code
= WXK_RETURN
;
468 key_code
= WXK_CLEAR
;
472 key_code
= WXK_PAUSE
;
476 key_code
= WXK_SELECT
;
480 key_code
= WXK_PRINT
;
484 key_code
= WXK_EXECUTE
;
488 key_code
= WXK_ESCAPE
;
491 // cursor and other extended keyboard keys
493 key_code
= WXK_DELETE
;
509 key_code
= WXK_RIGHT
;
516 case GDK_Prior
: // == GDK_Page_Up
517 key_code
= WXK_PAGEUP
;
520 case GDK_Next
: // == GDK_Page_Down
521 key_code
= WXK_PAGEDOWN
;
533 key_code
= WXK_INSERT
;
548 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
552 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
556 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
560 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
564 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
568 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
572 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
576 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
580 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
584 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
588 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
592 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
596 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
599 case GDK_KP_Prior
: // == GDK_KP_Page_Up
600 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
603 case GDK_KP_Next
: // == GDK_KP_Page_Down
604 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
608 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
612 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
616 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
620 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
624 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
627 case GDK_KP_Multiply
:
628 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
632 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
635 case GDK_KP_Separator
:
636 // FIXME: what is this?
637 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
640 case GDK_KP_Subtract
:
641 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
645 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
649 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
666 key_code
= WXK_F1
+ keysym
- GDK_F1
;
676 static inline bool wxIsAsciiKeysym(KeySym ks
)
681 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
683 GdkEventKey
*gdk_event
)
687 GdkModifierType state
;
688 if (gdk_event
->window
)
689 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
691 event
.SetTimestamp( gdk_event
->time
);
692 event
.SetId(win
->GetId());
693 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
694 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
695 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
696 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
697 event
.m_scanCode
= gdk_event
->keyval
;
698 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
699 event
.m_rawFlags
= 0;
701 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
703 wxGetMousePosition( &x
, &y
);
704 win
->ScreenToClient( &x
, &y
);
707 event
.SetEventObject( win
);
712 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
714 GdkEventKey
*gdk_event
)
716 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
717 // but only event->keyval which is quite useless to us, so remember
718 // the last character from GDK_KEY_PRESS and reuse it as last resort
720 // NB: should be MT-safe as we're always called from the main thread only
725 } s_lastKeyPress
= { 0, 0 };
727 KeySym keysym
= gdk_event
->keyval
;
729 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
730 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
734 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
738 // do we have the translation or is it a plain ASCII character?
739 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
741 // we should use keysym if it is ASCII as X does some translations
742 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
743 // which we don't want here (but which we do use for OnChar())
744 if ( !wxIsAsciiKeysym(keysym
) )
746 keysym
= (KeySym
)gdk_event
->string
[0];
749 // we want to always get the same key code when the same key is
750 // pressed regardless of the state of the modifiers, i.e. on a
751 // standard US keyboard pressing '5' or '%' ('5' key with
752 // Shift) should result in the same key code in OnKeyDown():
753 // '5' (although OnChar() will get either '5' or '%').
755 // to do it we first translate keysym to keycode (== scan code)
756 // and then back but always using the lower register
757 Display
*dpy
= (Display
*)wxGetDisplay();
758 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
760 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
762 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
764 // use the normalized, i.e. lower register, keysym if we've
766 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
768 // as explained above, we want to have lower register key codes
769 // normally but for the letter keys we want to have the upper ones
771 // NB: don't use XConvertCase() here, we want to do it for letters
773 key_code
= toupper(key_code
);
775 else // non ASCII key, what to do?
777 // by default, ignore it
780 // but if we have cached information from the last KEY_PRESS
781 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
784 if ( keysym
== s_lastKeyPress
.keysym
)
786 key_code
= s_lastKeyPress
.keycode
;
791 if ( gdk_event
->type
== GDK_KEY_PRESS
)
793 // remember it to be reused for KEY_UP event later
794 s_lastKeyPress
.keysym
= keysym
;
795 s_lastKeyPress
.keycode
= key_code
;
799 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
801 // sending unknown key events doesn't really make sense
805 // now fill all the other fields
806 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
808 event
.m_keyCode
= key_code
;
810 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
812 event
.m_uniChar
= key_code
;
822 GtkIMContext
*context
;
823 GdkEventKey
*lastKeyEvent
;
827 context
= gtk_im_multicontext_new();
832 g_object_unref (context
);
838 gtk_window_key_press_callback( GtkWidget
*widget
,
839 GdkEventKey
*gdk_event
,
844 if (g_blockEventsOnDrag
)
847 // GTK+ sends keypress events to the focus widget and then
848 // to all its parent and grandparent widget. We only want
849 // the key events from the focus widget.
850 if (!GTK_WIDGET_HAS_FOCUS(widget
))
853 wxKeyEvent
event( wxEVT_KEY_DOWN
);
855 bool return_after_IM
= false;
857 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
859 // Emit KEY_DOWN event
860 ret
= win
->HandleWindowEvent( event
);
864 // Return after IM processing as we cannot do
865 // anything with it anyhow.
866 return_after_IM
= true;
869 if ((!ret
) && (win
->m_imData
!= NULL
))
871 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
872 // docs, if IM filter returns true, no further processing should be done.
873 // we should send the key_down event anyway.
874 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
875 win
->m_imData
->lastKeyEvent
= NULL
;
876 if (intercepted_by_IM
)
878 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
889 wxWindowGTK
*ancestor
= win
;
892 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
895 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
896 ret
= ancestor
->HandleWindowEvent( command_event
);
899 if (ancestor
->IsTopLevel())
901 ancestor
= ancestor
->GetParent();
904 #endif // wxUSE_ACCEL
906 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
907 // will only be sent if it is not in an accelerator table.
911 KeySym keysym
= gdk_event
->keyval
;
912 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
913 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
916 if ( wxIsAsciiKeysym(keysym
) )
919 key_code
= (unsigned char)keysym
;
921 // gdk_event->string is actually deprecated
922 else if ( gdk_event
->length
== 1 )
924 key_code
= (unsigned char)gdk_event
->string
[0];
930 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
932 event
.m_keyCode
= key_code
;
934 // To conform to the docs we need to translate Ctrl-alpha
935 // characters to values in the range 1-26.
936 if ( event
.ControlDown() &&
937 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
939 if ( wxIsLowerChar(key_code
) )
940 event
.m_keyCode
= key_code
- 'a' + 1;
941 if ( wxIsUpperChar(key_code
) )
942 event
.m_keyCode
= key_code
- 'A' + 1;
944 event
.m_uniChar
= event
.m_keyCode
;
948 // Implement OnCharHook by checking ancestor top level windows
949 wxWindow
*parent
= win
;
950 while (parent
&& !parent
->IsTopLevel())
951 parent
= parent
->GetParent();
954 event
.SetEventType( wxEVT_CHAR_HOOK
);
955 ret
= parent
->HandleWindowEvent( event
);
960 event
.SetEventType(wxEVT_CHAR
);
961 ret
= win
->HandleWindowEvent( event
);
972 gtk_wxwindow_commit_cb (GtkIMContext
* WXUNUSED(context
),
976 wxKeyEvent
event( wxEVT_KEY_DOWN
);
978 // take modifiers, cursor position, timestamp etc. from the last
979 // key_press_event that was fed into Input Method:
980 if (window
->m_imData
->lastKeyEvent
)
982 wxFillOtherKeyEventFields(event
,
983 window
, window
->m_imData
->lastKeyEvent
);
987 event
.SetEventObject( window
);
990 const wxString
data(wxGTK_CONV_BACK_SYS(str
));
996 // Implement OnCharHook by checking ancestor top level windows
997 wxWindow
*parent
= window
;
998 while (parent
&& !parent
->IsTopLevel())
999 parent
= parent
->GetParent();
1001 for( wxString::const_iterator pstr
= data
.begin(); pstr
!= data
.end(); ++pstr
)
1004 event
.m_uniChar
= *pstr
;
1005 // Backward compatible for ISO-8859-1
1006 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1007 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1009 event
.m_keyCode
= (char)*pstr
;
1010 #endif // wxUSE_UNICODE
1012 // To conform to the docs we need to translate Ctrl-alpha
1013 // characters to values in the range 1-26.
1014 if ( event
.ControlDown() &&
1015 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
1017 if ( wxIsLowerChar(*pstr
) )
1018 event
.m_keyCode
= *pstr
- 'a' + 1;
1019 if ( wxIsUpperChar(*pstr
) )
1020 event
.m_keyCode
= *pstr
- 'A' + 1;
1022 event
.m_keyCode
= *pstr
- 'a' + 1;
1024 event
.m_uniChar
= event
.m_keyCode
;
1030 event
.SetEventType( wxEVT_CHAR_HOOK
);
1031 ret
= parent
->HandleWindowEvent( event
);
1036 event
.SetEventType(wxEVT_CHAR
);
1037 ret
= window
->HandleWindowEvent( event
);
1044 //-----------------------------------------------------------------------------
1045 // "key_release_event" from any window
1046 //-----------------------------------------------------------------------------
1050 gtk_window_key_release_callback( GtkWidget
* WXUNUSED(widget
),
1051 GdkEventKey
*gdk_event
,
1057 if (g_blockEventsOnDrag
)
1060 wxKeyEvent
event( wxEVT_KEY_UP
);
1061 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1063 // unknown key pressed, ignore (the event would be useless anyhow)
1067 return win
->GTKProcessEvent(event
);
1071 // ============================================================================
1073 // ============================================================================
1075 // ----------------------------------------------------------------------------
1076 // mouse event processing helpers
1077 // ----------------------------------------------------------------------------
1079 // init wxMouseEvent with the info from GdkEventXXX struct
1080 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1081 wxMouseEvent
& event
,
1084 event
.SetTimestamp( gdk_event
->time
);
1085 event
.m_shiftDown
= gdk_event
->state
& GDK_SHIFT_MASK
;
1086 event
.m_controlDown
= gdk_event
->state
& GDK_CONTROL_MASK
;
1087 event
.m_altDown
= gdk_event
->state
& GDK_MOD1_MASK
;
1088 event
.m_metaDown
= gdk_event
->state
& GDK_MOD2_MASK
;
1089 event
.m_leftDown
= gdk_event
->state
& GDK_BUTTON1_MASK
;
1090 event
.m_middleDown
= gdk_event
->state
& GDK_BUTTON2_MASK
;
1091 event
.m_rightDown
= gdk_event
->state
& GDK_BUTTON3_MASK
;
1092 event
.m_aux1Down
= gdk_event
->state
& GDK_BUTTON4_MASK
;
1093 event
.m_aux2Down
= gdk_event
->state
& GDK_BUTTON5_MASK
;
1095 wxPoint pt
= win
->GetClientAreaOrigin();
1096 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1097 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1099 if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
))
1101 // origin in the upper right corner
1102 int window_width
= win
->m_wxwindow
->allocation
.width
;
1103 event
.m_x
= window_width
- event
.m_x
;
1106 event
.SetEventObject( win
);
1107 event
.SetId( win
->GetId() );
1108 event
.SetTimestamp( gdk_event
->time
);
1111 static void AdjustEventButtonState(wxMouseEvent
& event
)
1113 // GDK reports the old state of the button for a button press event, but
1114 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1115 // for a LEFT_DOWN event, not FALSE, so we will invert
1116 // left/right/middleDown for the corresponding click events
1118 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1119 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1120 (event
.GetEventType() == wxEVT_LEFT_UP
))
1122 event
.m_leftDown
= !event
.m_leftDown
;
1126 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1127 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1128 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1130 event
.m_middleDown
= !event
.m_middleDown
;
1134 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1135 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1136 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1138 event
.m_rightDown
= !event
.m_rightDown
;
1143 // find the window to send the mouse event too
1145 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1150 if (win
->m_wxwindow
)
1152 wxPizza
* pizza
= WX_PIZZA(win
->m_wxwindow
);
1153 xx
+= pizza
->m_scroll_x
;
1154 yy
+= pizza
->m_scroll_y
;
1157 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1160 wxWindowGTK
*child
= node
->GetData();
1162 node
= node
->GetNext();
1163 if (!child
->IsShown())
1166 if (child
->IsTransparentForMouse())
1168 // wxStaticBox is transparent in the box itself
1169 int xx1
= child
->m_x
;
1170 int yy1
= child
->m_y
;
1171 int xx2
= child
->m_x
+ child
->m_width
;
1172 int yy2
= child
->m_y
+ child
->m_height
;
1175 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1177 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1179 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1181 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1192 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1193 (child
->m_x
<= xx
) &&
1194 (child
->m_y
<= yy
) &&
1195 (child
->m_x
+child
->m_width
>= xx
) &&
1196 (child
->m_y
+child
->m_height
>= yy
))
1209 // ----------------------------------------------------------------------------
1210 // common event handlers helpers
1211 // ----------------------------------------------------------------------------
1213 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const
1215 // nothing special at this level
1216 return HandleWindowEvent(event
);
1219 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1223 if (g_blockEventsOnDrag
)
1225 if (g_blockEventsOnScroll
)
1228 if (!GTKIsOwnWindow(event
->window
))
1234 // overloads for all GDK event types we use here: we need to have this as
1235 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1236 // derives from it in the sense that the structs have the same layout
1237 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1238 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1240 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1243 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1244 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1245 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1247 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1249 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1250 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1254 // send the wxChildFocusEvent and wxFocusEvent, common code of
1255 // gtk_window_focus_in_callback() and SetFocus()
1256 static bool DoSendFocusEvents(wxWindow
*win
)
1258 // Notify the parent keeping track of focus for the kbd navigation
1259 // purposes that we got it.
1260 wxChildFocusEvent
eventChildFocus(win
);
1261 (void)win
->HandleWindowEvent(eventChildFocus
);
1263 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1264 eventFocus
.SetEventObject(win
);
1266 return win
->HandleWindowEvent(eventFocus
);
1269 // all event handlers must have C linkage as they're called from GTK+ C code
1273 //-----------------------------------------------------------------------------
1274 // "button_press_event"
1275 //-----------------------------------------------------------------------------
1278 gtk_window_button_press_callback( GtkWidget
*widget
,
1279 GdkEventButton
*gdk_event
,
1282 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1284 g_lastButtonNumber
= gdk_event
->button
;
1286 // GDK sends surplus button down events
1287 // before a double click event. We
1288 // need to filter these out.
1289 if ((gdk_event
->type
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
))
1291 GdkEvent
*peek_event
= gdk_event_peek();
1294 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1295 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1297 gdk_event_free( peek_event
);
1302 gdk_event_free( peek_event
);
1307 wxEventType event_type
= wxEVT_NULL
;
1309 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1310 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1312 // Reset GDK internal timestamp variables in order to disable GDK
1313 // triple click events. GDK will then next time believe no button has
1314 // been clicked just before, and send a normal button click event.
1315 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1316 display
->button_click_time
[1] = 0;
1317 display
->button_click_time
[0] = 0;
1320 if (gdk_event
->button
== 1)
1322 // note that GDK generates triple click events which are not supported
1323 // by wxWidgets but still have to be passed to the app as otherwise
1324 // clicks would simply go missing
1325 switch (gdk_event
->type
)
1327 // we shouldn't get triple clicks at all for GTK2 because we
1328 // suppress them artificially using the code above but we still
1329 // should map them to something for GTK1 and not just ignore them
1330 // as this would lose clicks
1331 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1332 case GDK_BUTTON_PRESS
:
1333 event_type
= wxEVT_LEFT_DOWN
;
1336 case GDK_2BUTTON_PRESS
:
1337 event_type
= wxEVT_LEFT_DCLICK
;
1341 // just to silence gcc warnings
1345 else if (gdk_event
->button
== 2)
1347 switch (gdk_event
->type
)
1349 case GDK_3BUTTON_PRESS
:
1350 case GDK_BUTTON_PRESS
:
1351 event_type
= wxEVT_MIDDLE_DOWN
;
1354 case GDK_2BUTTON_PRESS
:
1355 event_type
= wxEVT_MIDDLE_DCLICK
;
1362 else if (gdk_event
->button
== 3)
1364 switch (gdk_event
->type
)
1366 case GDK_3BUTTON_PRESS
:
1367 case GDK_BUTTON_PRESS
:
1368 event_type
= wxEVT_RIGHT_DOWN
;
1371 case GDK_2BUTTON_PRESS
:
1372 event_type
= wxEVT_RIGHT_DCLICK
;
1380 if ( event_type
== wxEVT_NULL
)
1382 // unknown mouse button or click type
1386 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1388 wxMouseEvent
event( event_type
);
1389 InitMouseEvent( win
, event
, gdk_event
);
1391 AdjustEventButtonState(event
);
1393 // wxListBox actually gets mouse events from the item, so we need to give it
1394 // a chance to correct this
1395 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1397 // find the correct window to send the event to: it may be a different one
1398 // from the one which got it at GTK+ level because some controls don't have
1399 // their own X window and thus cannot get any events.
1400 if ( !g_captureWindow
)
1401 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1403 // reset the event object and id in case win changed.
1404 event
.SetEventObject( win
);
1405 event
.SetId( win
->GetId() );
1407 bool ret
= win
->GTKProcessEvent( event
);
1408 g_lastMouseEvent
= NULL
;
1412 if ((event_type
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&
1413 (g_focusWindow
!= win
) /* && win->IsFocusable() */)
1418 if (event_type
== wxEVT_RIGHT_DOWN
)
1420 // generate a "context menu" event: this is similar to right mouse
1421 // click under many GUIs except that it is generated differently
1422 // (right up under MSW, ctrl-click under Mac, right down here) and
1424 // (a) it's a command event and so is propagated to the parent
1425 // (b) under some ports it can be generated from kbd too
1426 // (c) it uses screen coords (because of (a))
1427 wxContextMenuEvent
evtCtx(
1430 win
->ClientToScreen(event
.GetPosition()));
1431 evtCtx
.SetEventObject(win
);
1432 return win
->GTKProcessEvent(evtCtx
);
1438 //-----------------------------------------------------------------------------
1439 // "button_release_event"
1440 //-----------------------------------------------------------------------------
1443 gtk_window_button_release_callback( GtkWidget
*widget
,
1444 GdkEventButton
*gdk_event
,
1447 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1449 g_lastButtonNumber
= 0;
1451 wxEventType event_type
= wxEVT_NULL
;
1453 switch (gdk_event
->button
)
1456 event_type
= wxEVT_LEFT_UP
;
1460 event_type
= wxEVT_MIDDLE_UP
;
1464 event_type
= wxEVT_RIGHT_UP
;
1468 // unknown button, don't process
1472 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1474 wxMouseEvent
event( event_type
);
1475 InitMouseEvent( win
, event
, gdk_event
);
1477 AdjustEventButtonState(event
);
1479 // same wxListBox hack as above
1480 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1482 if ( !g_captureWindow
)
1483 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1485 // reset the event object and id in case win changed.
1486 event
.SetEventObject( win
);
1487 event
.SetId( win
->GetId() );
1489 bool ret
= win
->GTKProcessEvent(event
);
1491 g_lastMouseEvent
= NULL
;
1496 //-----------------------------------------------------------------------------
1497 // "motion_notify_event"
1498 //-----------------------------------------------------------------------------
1501 gtk_window_motion_notify_callback( GtkWidget
* WXUNUSED(widget
),
1502 GdkEventMotion
*gdk_event
,
1505 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1507 if (gdk_event
->is_hint
)
1511 GdkModifierType state
;
1512 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1517 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1519 wxMouseEvent
event( wxEVT_MOTION
);
1520 InitMouseEvent(win
, event
, gdk_event
);
1522 if ( g_captureWindow
)
1524 // synthesise a mouse enter or leave event if needed
1525 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1526 // This seems to be necessary and actually been added to
1527 // GDK itself in version 2.0.X
1530 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1531 if ( hasMouse
!= g_captureWindowHasMouse
)
1533 // the mouse changed window
1534 g_captureWindowHasMouse
= hasMouse
;
1536 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1537 : wxEVT_LEAVE_WINDOW
);
1538 InitMouseEvent(win
, eventM
, gdk_event
);
1539 eventM
.SetEventObject(win
);
1540 win
->GTKProcessEvent(eventM
);
1545 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1547 // reset the event object and id in case win changed.
1548 event
.SetEventObject( win
);
1549 event
.SetId( win
->GetId() );
1552 if ( !g_captureWindow
)
1554 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1555 if (win
->GTKProcessEvent( cevent
))
1557 win
->SetCursor( cevent
.GetCursor() );
1561 bool ret
= win
->GTKProcessEvent(event
);
1563 g_lastMouseEvent
= NULL
;
1568 //-----------------------------------------------------------------------------
1569 // "scroll_event" (mouse wheel event)
1570 //-----------------------------------------------------------------------------
1573 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1575 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1576 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1581 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1582 InitMouseEvent(win
, event
, gdk_event
);
1584 // FIXME: Get these values from GTK or GDK
1585 event
.m_linesPerAction
= 3;
1586 event
.m_wheelDelta
= 120;
1587 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1588 event
.m_wheelRotation
= 120;
1590 event
.m_wheelRotation
= -120;
1592 return win
->GTKProcessEvent(event
);
1595 //-----------------------------------------------------------------------------
1597 //-----------------------------------------------------------------------------
1599 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1601 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1602 event
.SetEventObject(win
);
1603 return win
->GTKProcessEvent(event
);
1606 //-----------------------------------------------------------------------------
1608 //-----------------------------------------------------------------------------
1611 gtk_window_focus_in_callback( GtkWidget
* WXUNUSED(widget
),
1612 GdkEventFocus
*WXUNUSED(event
),
1616 gtk_im_context_focus_in(win
->m_imData
->context
);
1618 g_focusWindow
= win
;
1620 wxLogTrace(TRACE_FOCUS
,
1621 _T("%s: focus in"), win
->GetName().c_str());
1624 // caret needs to be informed about focus change
1625 wxCaret
*caret
= win
->GetCaret();
1628 caret
->OnSetFocus();
1630 #endif // wxUSE_CARET
1632 gboolean ret
= FALSE
;
1634 // does the window itself think that it has the focus?
1635 if ( !win
->m_hasFocus
)
1637 // not yet, notify it
1638 win
->m_hasFocus
= true;
1640 (void)DoSendFocusEvents(win
);
1645 // Disable default focus handling for custom windows
1646 // since the default GTK+ handler issues a repaint
1647 if (win
->m_wxwindow
)
1653 //-----------------------------------------------------------------------------
1654 // "focus_out_event"
1655 //-----------------------------------------------------------------------------
1658 gtk_window_focus_out_callback( GtkWidget
* WXUNUSED(widget
),
1659 GdkEventFocus
* WXUNUSED(gdk_event
),
1663 gtk_im_context_focus_out(win
->m_imData
->context
);
1665 wxLogTrace( TRACE_FOCUS
,
1666 _T("%s: focus out"), win
->GetName().c_str() );
1669 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1673 g_focusWindow
= (wxWindowGTK
*)NULL
;
1676 // caret needs to be informed about focus change
1677 wxCaret
*caret
= win
->GetCaret();
1680 caret
->OnKillFocus();
1682 #endif // wxUSE_CARET
1684 // don't send the window a kill focus event if it thinks that it doesn't
1685 // have focus already
1686 if ( win
->m_hasFocus
)
1688 // the event handler might delete the window when it loses focus, so
1689 // check whether this is a custom window before calling it
1690 const bool has_wxwindow
= win
->m_wxwindow
!= NULL
;
1692 win
->m_hasFocus
= false;
1694 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1695 event
.SetEventObject( win
);
1697 (void)win
->GTKProcessEvent( event
);
1699 // Disable default focus handling for custom windows
1700 // since the default GTK+ handler issues a repaint
1705 // continue with normal processing
1710 wx_window_focus_callback(GtkWidget
*widget
,
1711 GtkDirectionType
WXUNUSED(direction
),
1714 // the default handler for focus signal in GtkScrolledWindow sets
1715 // focus to the window itself even if it doesn't accept focus, i.e. has no
1716 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1717 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1718 // any children which might accept focus (we know we don't accept the focus
1719 // ourselves as this signal is only connected in this case)
1720 if ( win
->GetChildren().empty() )
1721 g_signal_stop_emission_by_name(widget
, "focus");
1723 // we didn't change the focus
1727 //-----------------------------------------------------------------------------
1728 // "enter_notify_event"
1729 //-----------------------------------------------------------------------------
1732 gtk_window_enter_callback( GtkWidget
*widget
,
1733 GdkEventCrossing
*gdk_event
,
1736 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1738 // Event was emitted after a grab
1739 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1743 GdkModifierType state
= (GdkModifierType
)0;
1745 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1747 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1748 InitMouseEvent(win
, event
, gdk_event
);
1749 wxPoint pt
= win
->GetClientAreaOrigin();
1750 event
.m_x
= x
+ pt
.x
;
1751 event
.m_y
= y
+ pt
.y
;
1753 if ( !g_captureWindow
)
1755 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1756 if (win
->GTKProcessEvent( cevent
))
1758 win
->SetCursor( cevent
.GetCursor() );
1762 return win
->GTKProcessEvent(event
);
1765 //-----------------------------------------------------------------------------
1766 // "leave_notify_event"
1767 //-----------------------------------------------------------------------------
1770 gtk_window_leave_callback( GtkWidget
*widget
,
1771 GdkEventCrossing
*gdk_event
,
1774 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1776 // Event was emitted after an ungrab
1777 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1779 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1783 GdkModifierType state
= (GdkModifierType
)0;
1785 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1787 InitMouseEvent(win
, event
, gdk_event
);
1789 return win
->GTKProcessEvent(event
);
1792 //-----------------------------------------------------------------------------
1793 // "value_changed" from scrollbar
1794 //-----------------------------------------------------------------------------
1797 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
1799 wxEventType eventType
= win
->GetScrollEventType(range
);
1800 if (eventType
!= wxEVT_NULL
)
1802 // Convert scroll event type to scrollwin event type
1803 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
1805 // find the scrollbar which generated the event
1806 wxWindowGTK::ScrollDir dir
= win
->ScrollDirFromRange(range
);
1808 // generate the corresponding wx event
1809 const int orient
= wxWindow::OrientFromScrollDir(dir
);
1810 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
1811 event
.SetEventObject(win
);
1813 win
->GTKProcessEvent(event
);
1817 //-----------------------------------------------------------------------------
1818 // "button_press_event" from scrollbar
1819 //-----------------------------------------------------------------------------
1822 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
1824 g_blockEventsOnScroll
= true;
1825 win
->m_mouseButtonDown
= true;
1830 //-----------------------------------------------------------------------------
1831 // "event_after" from scrollbar
1832 //-----------------------------------------------------------------------------
1835 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
1837 if (event
->type
== GDK_BUTTON_RELEASE
)
1839 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1841 const int orient
= wxWindow::OrientFromScrollDir(
1842 win
->ScrollDirFromRange(range
));
1843 wxScrollWinEvent
evt(wxEVT_SCROLLWIN_THUMBRELEASE
,
1844 win
->GetScrollPos(orient
), orient
);
1845 evt
.SetEventObject(win
);
1846 win
->GTKProcessEvent(evt
);
1850 //-----------------------------------------------------------------------------
1851 // "button_release_event" from scrollbar
1852 //-----------------------------------------------------------------------------
1855 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
1857 g_blockEventsOnScroll
= false;
1858 win
->m_mouseButtonDown
= false;
1859 // If thumb tracking
1860 if (win
->m_isScrolling
)
1862 win
->m_isScrolling
= false;
1863 // Hook up handler to send thumb release event after this emission is finished.
1864 // To allow setting scroll position from event handler, sending event must
1865 // be deferred until after the GtkRange handler for this signal has run
1866 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1872 //-----------------------------------------------------------------------------
1873 // "realize" from m_widget
1874 //-----------------------------------------------------------------------------
1877 gtk_window_realized_callback(GtkWidget
* widget
, wxWindow
* win
)
1881 gtk_im_context_set_client_window( win
->m_imData
->context
,
1885 // We cannot set colours and fonts before the widget
1886 // been realized, so we do this directly after realization
1887 // or otherwise in idle time
1889 if (win
->m_needsStyleChange
)
1891 win
->SetBackgroundStyle(win
->GetBackgroundStyle());
1892 win
->m_needsStyleChange
= false;
1895 wxWindowCreateEvent
event( win
);
1896 event
.SetEventObject( win
);
1897 win
->GTKProcessEvent( event
);
1900 //-----------------------------------------------------------------------------
1901 // "size_allocate" from m_wxwindow or m_widget
1902 //-----------------------------------------------------------------------------
1905 size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxWindow
* win
)
1907 int w
= alloc
->width
;
1908 int h
= alloc
->height
;
1909 if (win
->m_wxwindow
)
1911 int border_x
, border_y
;
1912 WX_PIZZA(win
->m_wxwindow
)->get_border_widths(border_x
, border_y
);
1918 if (win
->m_oldClientWidth
!= w
|| win
->m_oldClientHeight
!= h
)
1920 win
->m_oldClientWidth
= w
;
1921 win
->m_oldClientHeight
= h
;
1922 // this callback can be connected to m_wxwindow,
1923 // so always get size from m_widget->allocation
1924 win
->m_width
= win
->m_widget
->allocation
.width
;
1925 win
->m_height
= win
->m_widget
->allocation
.height
;
1926 if (!win
->m_nativeSizeEvent
)
1928 wxSizeEvent
event(win
->GetSize(), win
->GetId());
1929 event
.SetEventObject(win
);
1930 win
->GTKProcessEvent(event
);
1935 //-----------------------------------------------------------------------------
1937 //-----------------------------------------------------------------------------
1939 #if GTK_CHECK_VERSION(2, 8, 0)
1941 gtk_window_grab_broken( GtkWidget
*,
1942 GdkEventGrabBroken
*event
,
1945 // Mouse capture has been lost involuntarily, notify the application
1946 if(!event
->keyboard
&& wxWindow::GetCapture() == win
)
1948 wxMouseCaptureLostEvent
evt( win
->GetId() );
1949 evt
.SetEventObject( win
);
1950 win
->HandleWindowEvent( evt
);
1956 //-----------------------------------------------------------------------------
1958 //-----------------------------------------------------------------------------
1961 void gtk_window_style_set_callback( GtkWidget
*WXUNUSED(widget
),
1962 GtkStyle
*previous_style
,
1965 if (win
&& previous_style
)
1967 wxSysColourChangedEvent event
;
1968 event
.SetEventObject(win
);
1970 win
->GTKProcessEvent( event
);
1976 // Helper to suspend colour change event event processing while we change a widget's style
1977 class wxSuspendStyleEvents
1980 wxSuspendStyleEvents(wxWindow
* win
)
1983 if (win
->m_wxwindow
&& win
->IsTopLevel())
1986 g_signal_handlers_block_by_func(
1987 m_win
->m_wxwindow
, (void*)gtk_window_style_set_callback
, m_win
);
1990 ~wxSuspendStyleEvents()
1993 g_signal_handlers_unblock_by_func(
1994 m_win
->m_wxwindow
, (void*)gtk_window_style_set_callback
, m_win
);
2000 // ----------------------------------------------------------------------------
2001 // this wxWindowBase function is implemented here (in platform-specific file)
2002 // because it is static and so couldn't be made virtual
2003 // ----------------------------------------------------------------------------
2005 wxWindow
*wxWindowBase::DoFindFocus()
2007 // the cast is necessary when we compile in wxUniversal mode
2008 return (wxWindow
*)g_focusWindow
;
2011 //-----------------------------------------------------------------------------
2012 // InsertChild for wxWindowGTK.
2013 //-----------------------------------------------------------------------------
2015 /* Callback for wxWindowGTK. This very strange beast has to be used because
2016 * C++ has no virtual methods in a constructor. We have to emulate a
2017 * virtual function here as wxNotebook requires a different way to insert
2018 * a child in it. I had opted for creating a wxNotebookPage window class
2019 * which would have made this superfluous (such in the MDI window system),
2020 * but no-one was listening to me... */
2022 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2024 /* the window might have been scrolled already, do we
2025 have to adapt the position */
2026 wxPizza
* pizza
= WX_PIZZA(parent
->m_wxwindow
);
2027 child
->m_x
+= pizza
->m_scroll_x
;
2028 child
->m_y
+= pizza
->m_scroll_y
;
2030 gtk_widget_set_size_request(
2031 child
->m_widget
, child
->m_width
, child
->m_height
);
2033 GTK_FIXED(parent
->m_wxwindow
), child
->m_widget
, child
->m_x
, child
->m_y
);
2036 //-----------------------------------------------------------------------------
2038 //-----------------------------------------------------------------------------
2040 wxWindow
*wxGetActiveWindow()
2042 return wxWindow::FindFocus();
2046 wxMouseState
wxGetMouseState()
2052 GdkModifierType mask
;
2054 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2058 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2059 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2060 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2061 ms
.SetAux1Down(mask
& GDK_BUTTON4_MASK
);
2062 ms
.SetAux2Down(mask
& GDK_BUTTON5_MASK
);
2064 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2065 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2066 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2067 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2072 //-----------------------------------------------------------------------------
2074 //-----------------------------------------------------------------------------
2076 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2078 #ifdef __WXUNIVERSAL__
2079 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2081 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2082 #endif // __WXUNIVERSAL__/__WXGTK__
2084 void wxWindowGTK::Init()
2087 m_widget
= (GtkWidget
*) NULL
;
2088 m_wxwindow
= (GtkWidget
*) NULL
;
2089 m_focusWidget
= (GtkWidget
*) NULL
;
2098 m_isBeingDeleted
= false;
2100 m_showOnIdle
= false;
2103 m_nativeSizeEvent
= false;
2105 m_isScrolling
= false;
2106 m_mouseButtonDown
= false;
2108 // initialize scrolling stuff
2109 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2111 m_scrollBar
[dir
] = NULL
;
2112 m_scrollPos
[dir
] = 0;
2116 m_oldClientHeight
= 0;
2118 m_insertCallback
= wxInsertChildInWindow
;
2122 m_clipPaintRegion
= false;
2124 m_needsStyleChange
= false;
2126 m_cursor
= *wxSTANDARD_CURSOR
;
2129 m_dirtyTabOrder
= false;
2132 wxWindowGTK::wxWindowGTK()
2137 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2142 const wxString
&name
)
2146 Create( parent
, id
, pos
, size
, style
, name
);
2149 bool wxWindowGTK::Create( wxWindow
*parent
,
2154 const wxString
&name
)
2156 // Get default border
2157 wxBorder border
= GetBorder(style
);
2158 style
&= ~wxBORDER_MASK
;
2161 if (!PreCreation( parent
, pos
, size
) ||
2162 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2164 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2169 m_wxwindow
= wxPizza::New(m_windowStyle
);
2170 if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
))
2171 m_widget
= m_wxwindow
;
2174 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2176 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2178 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2179 scroll_class
->scrollbar_spacing
= 0;
2181 // There is a conflict with default bindings at GTK+
2182 // level between scrolled windows and notebooks both of which want to use
2183 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2184 // direction and notebooks for changing pages -- we decide that if we don't
2185 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2186 // means we can get working keyboard navigation in notebooks
2187 if ( !HasFlag(wxHSCROLL
) )
2190 bindings
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
));
2193 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
);
2194 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
);
2198 if (HasFlag(wxALWAYS_SHOW_SB
))
2200 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
2202 scrolledWindow
->hscrollbar_visible
= TRUE
;
2203 scrolledWindow
->vscrollbar_visible
= TRUE
;
2207 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2210 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2211 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2212 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2213 gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE
);
2215 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2217 // connect various scroll-related events
2218 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2220 // these handlers block mouse events to any window during scrolling
2221 // such as motion events and prevent GTK and wxWidgets from fighting
2222 // over where the slider should be
2223 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2224 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2225 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2226 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2228 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2229 G_CALLBACK(gtk_scrollbar_event_after
), this);
2230 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2232 // these handlers get notified when scrollbar slider moves
2233 g_signal_connect_after(m_scrollBar
[dir
], "value_changed",
2234 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2237 gtk_widget_show( m_wxwindow
);
2241 m_parent
->DoAddChild( this );
2243 m_focusWidget
= m_wxwindow
;
2250 wxWindowGTK::~wxWindowGTK()
2254 if (g_focusWindow
== this)
2255 g_focusWindow
= NULL
;
2257 if ( g_delayedFocus
== this )
2258 g_delayedFocus
= NULL
;
2260 m_isBeingDeleted
= true;
2263 // destroy children before destroying this window itself
2266 // unhook focus handlers to prevent stray events being
2267 // propagated to this (soon to be) dead object
2268 if (m_focusWidget
!= NULL
)
2270 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2271 (gpointer
) gtk_window_focus_in_callback
,
2273 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2274 (gpointer
) gtk_window_focus_out_callback
,
2281 // delete before the widgets to avoid a crash on solaris
2284 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2286 gtk_widget_destroy( m_wxwindow
);
2287 m_wxwindow
= (GtkWidget
*) NULL
;
2292 gtk_widget_destroy( m_widget
);
2293 m_widget
= (GtkWidget
*) NULL
;
2297 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2299 if ( GTKNeedsParent() )
2301 wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") );
2304 // Use either the given size, or the default if -1 is given.
2305 // See wxWindowBase for these functions.
2306 m_width
= WidthDefault(size
.x
) ;
2307 m_height
= HeightDefault(size
.y
);
2315 void wxWindowGTK::PostCreation()
2317 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2323 // these get reported to wxWidgets -> wxPaintEvent
2325 g_signal_connect (m_wxwindow
, "expose_event",
2326 G_CALLBACK (gtk_window_expose_callback
), this);
2328 if (GetLayoutDirection() == wxLayout_LeftToRight
)
2329 gtk_widget_set_redraw_on_allocate(m_wxwindow
, HasFlag(wxFULL_REPAINT_ON_RESIZE
));
2332 // Create input method handler
2333 m_imData
= new wxGtkIMData
;
2335 // Cannot handle drawing preedited text yet
2336 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2338 g_signal_connect (m_imData
->context
, "commit",
2339 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2342 #ifndef __WXUNIVERSAL__
2343 if (HasFlag(wxPizza::BORDER_STYLES
))
2345 g_signal_connect(m_widget
, "expose_event",
2346 G_CALLBACK(expose_event_border
), this);
2353 if (!GTK_IS_WINDOW(m_widget
))
2355 if (m_focusWidget
== NULL
)
2356 m_focusWidget
= m_widget
;
2360 g_signal_connect (m_focusWidget
, "focus_in_event",
2361 G_CALLBACK (gtk_window_focus_in_callback
), this);
2362 g_signal_connect (m_focusWidget
, "focus_out_event",
2363 G_CALLBACK (gtk_window_focus_out_callback
), this);
2367 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2368 G_CALLBACK (gtk_window_focus_in_callback
), this);
2369 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2370 G_CALLBACK (gtk_window_focus_out_callback
), this);
2374 if ( !AcceptsFocusFromKeyboard() )
2378 g_signal_connect(m_widget
, "focus",
2379 G_CALLBACK(wx_window_focus_callback
), this);
2382 // connect to the various key and mouse handlers
2384 GtkWidget
*connect_widget
= GetConnectWidget();
2386 ConnectWidget( connect_widget
);
2388 /* We cannot set colours, fonts and cursors before the widget has
2389 been realized, so we do this directly after realization */
2390 g_signal_connect (connect_widget
, "realize",
2391 G_CALLBACK (gtk_window_realized_callback
), this);
2395 g_signal_connect(m_wxwindow
? m_wxwindow
: m_widget
, "size_allocate",
2396 G_CALLBACK(size_allocate
), this);
2401 #if GTK_CHECK_VERSION(2, 8, 0)
2402 if (!gtk_check_version(2,8,0))
2404 // Make sure we can notify the app when mouse capture is lost
2405 g_signal_connect (m_wxwindow
, "grab_broken_event",
2406 G_CALLBACK (gtk_window_grab_broken
), this);
2411 if ( connect_widget
!= m_wxwindow
)
2413 #if GTK_CHECK_VERSION(2, 8, 0)
2414 if (!gtk_check_version(2,8,0))
2416 // Make sure we can notify app code when mouse capture is lost
2417 g_signal_connect (connect_widget
, "grab_broken_event",
2418 G_CALLBACK (gtk_window_grab_broken
), this);
2423 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2424 if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2426 // If we connect to the "size_request" signal of a GtkFileChooserButton
2427 // then that control won't be sized properly when placed inside sizers
2428 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2429 // FIXME: what should be done here ?
2432 if ( !IsTopLevel() ) // top level windows use their own callback
2434 // This is needed if we want to add our windows into native
2435 // GTK controls, such as the toolbar. With this callback, the
2436 // toolbar gets to know the correct size (the one set by the
2437 // programmer). Sadly, it misbehaves for wxComboBox.
2438 g_signal_connect (m_widget
, "size_request",
2439 G_CALLBACK (wxgtk_window_size_request_callback
),
2443 InheritAttributes();
2447 SetLayoutDirection(wxLayout_Default
);
2449 // unless the window was created initially hidden (i.e. Hide() had been
2450 // called before Create()), we should show it at GTK+ level as well
2452 gtk_widget_show( m_widget
);
2455 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2457 g_signal_connect (widget
, "key_press_event",
2458 G_CALLBACK (gtk_window_key_press_callback
), this);
2459 g_signal_connect (widget
, "key_release_event",
2460 G_CALLBACK (gtk_window_key_release_callback
), this);
2461 g_signal_connect (widget
, "button_press_event",
2462 G_CALLBACK (gtk_window_button_press_callback
), this);
2463 g_signal_connect (widget
, "button_release_event",
2464 G_CALLBACK (gtk_window_button_release_callback
), this);
2465 g_signal_connect (widget
, "motion_notify_event",
2466 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2467 g_signal_connect (widget
, "scroll_event",
2468 G_CALLBACK (window_scroll_event
), this);
2469 g_signal_connect (widget
, "popup_menu",
2470 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2471 g_signal_connect (widget
, "enter_notify_event",
2472 G_CALLBACK (gtk_window_enter_callback
), this);
2473 g_signal_connect (widget
, "leave_notify_event",
2474 G_CALLBACK (gtk_window_leave_callback
), this);
2476 if (IsTopLevel() && m_wxwindow
)
2477 g_signal_connect (m_wxwindow
, "style_set",
2478 G_CALLBACK (gtk_window_style_set_callback
), this);
2481 bool wxWindowGTK::Destroy()
2483 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2487 return wxWindowBase::Destroy();
2490 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2492 gtk_widget_set_size_request(m_widget
, width
, height
);
2493 // inform the parent to perform the move
2494 WX_PIZZA(m_parent
->m_wxwindow
)->move(m_widget
, x
, y
);
2497 void wxWindowGTK::ConstrainSize()
2500 // GPE's window manager doesn't like size hints at all, esp. when the user
2501 // has to use the virtual keyboard, so don't constrain size there
2505 const wxSize minSize
= GetMinSize();
2506 const wxSize maxSize
= GetMaxSize();
2507 if (minSize
.x
> 0 && m_width
< minSize
.x
) m_width
= minSize
.x
;
2508 if (minSize
.y
> 0 && m_height
< minSize
.y
) m_height
= minSize
.y
;
2509 if (maxSize
.x
> 0 && m_width
> maxSize
.x
) m_width
= maxSize
.x
;
2510 if (maxSize
.y
> 0 && m_height
> maxSize
.y
) m_height
= maxSize
.y
;
2514 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2516 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2517 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2519 int currentX
, currentY
;
2520 GetPosition(¤tX
, ¤tY
);
2521 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2523 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2525 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2527 // calculate the best size if we should auto size the window
2528 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2529 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2531 const wxSize sizeBest
= GetBestSize();
2532 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2534 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2535 height
= sizeBest
.y
;
2538 const wxSize
oldSize(m_width
, m_height
);
2546 if (m_parent
->m_wxwindow
)
2548 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2549 m_x
= x
+ pizza
->m_scroll_x
;
2550 m_y
= y
+ pizza
->m_scroll_y
;
2552 int left_border
= 0;
2553 int right_border
= 0;
2555 int bottom_border
= 0;
2557 /* the default button has a border around it */
2558 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2560 GtkBorder
*default_border
= NULL
;
2561 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2564 left_border
+= default_border
->left
;
2565 right_border
+= default_border
->right
;
2566 top_border
+= default_border
->top
;
2567 bottom_border
+= default_border
->bottom
;
2568 gtk_border_free( default_border
);
2572 DoMoveWindow( m_x
- left_border
,
2574 m_width
+left_border
+right_border
,
2575 m_height
+top_border
+bottom_border
);
2578 if (m_width
!= oldSize
.x
|| m_height
!= oldSize
.y
)
2580 // update these variables to keep size_allocate handler
2581 // from sending another size event for this change
2582 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2584 gtk_widget_queue_resize(m_widget
);
2585 if (!m_nativeSizeEvent
)
2587 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2588 event
.SetEventObject( this );
2589 HandleWindowEvent( event
);
2594 bool wxWindowGTK::GtkShowFromOnIdle()
2596 if (IsShown() && m_showOnIdle
&& !GTK_WIDGET_VISIBLE (m_widget
))
2598 GtkAllocation alloc
;
2601 alloc
.width
= m_width
;
2602 alloc
.height
= m_height
;
2603 gtk_widget_size_allocate( m_widget
, &alloc
);
2604 gtk_widget_show( m_widget
);
2605 wxShowEvent
eventShow(GetId(), true);
2606 eventShow
.SetEventObject(this);
2607 HandleWindowEvent(eventShow
);
2608 m_showOnIdle
= false;
2615 void wxWindowGTK::OnInternalIdle()
2617 // Check if we have to show window now
2618 if (GtkShowFromOnIdle()) return;
2620 if ( m_dirtyTabOrder
)
2622 m_dirtyTabOrder
= false;
2626 // Update style if the window was not yet realized
2627 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2628 if (m_needsStyleChange
)
2630 SetBackgroundStyle(GetBackgroundStyle());
2631 m_needsStyleChange
= false;
2634 wxCursor cursor
= m_cursor
;
2635 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2639 /* I now set the cursor anew in every OnInternalIdle call
2640 as setting the cursor in a parent window also effects the
2641 windows above so that checking for the current cursor is
2644 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2646 GdkWindow
*window
= m_wxwindow
->window
;
2648 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2650 if (!g_globalCursor
.Ok())
2651 cursor
= *wxSTANDARD_CURSOR
;
2653 window
= m_widget
->window
;
2654 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2655 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2658 else if ( m_widget
)
2660 GdkWindow
*window
= m_widget
->window
;
2661 if ( window
&& !GTK_WIDGET_NO_WINDOW(m_widget
) )
2662 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2666 if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
2667 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2670 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2672 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2674 if (width
) (*width
) = m_width
;
2675 if (height
) (*height
) = m_height
;
2678 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2680 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2682 const wxSize size
= GetSize();
2683 const wxSize clientSize
= GetClientSize();
2684 SetSize(width
+ (size
.x
- clientSize
.x
), height
+ (size
.y
- clientSize
.y
));
2687 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2689 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2696 // if window is scrollable, account for scrollbars
2697 for (int i
= 0; i
< 2 && m_scrollBar
[i
]; i
++)
2700 GtkAdjustment
* adj
= gtk_range_get_adjustment(m_scrollBar
[i
]);
2701 // if scrollbar enabled
2702 if (adj
->upper
> adj
->page_size
)
2704 gtk_widget_size_request(GTK_WIDGET(m_scrollBar
[i
]), &req
);
2705 if (i
== ScrollDir_Horz
)
2712 int border_x
, border_y
;
2713 WX_PIZZA(m_wxwindow
)->get_border_widths(border_x
, border_y
);
2723 if (width
) *width
= w
;
2724 if (height
) *height
= h
;
2727 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2729 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2733 if (!IsTopLevel() && m_parent
&& m_parent
->m_wxwindow
)
2735 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2736 dx
= pizza
->m_scroll_x
;
2737 dy
= pizza
->m_scroll_y
;
2740 if (m_x
== -1 && m_y
== -1)
2742 GdkWindow
*source
= (GdkWindow
*) NULL
;
2744 source
= m_wxwindow
->window
;
2746 source
= m_widget
->window
;
2752 gdk_window_get_origin( source
, &org_x
, &org_y
);
2755 m_parent
->ScreenToClient(&org_x
, &org_y
);
2757 wx_const_cast(wxWindowGTK
*, this)->m_x
= org_x
;
2758 wx_const_cast(wxWindowGTK
*, this)->m_y
= org_y
;
2762 if (x
) (*x
) = m_x
- dx
;
2763 if (y
) (*y
) = m_y
- dy
;
2766 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2768 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2770 if (!m_widget
->window
) return;
2772 GdkWindow
*source
= (GdkWindow
*) NULL
;
2774 source
= m_wxwindow
->window
;
2776 source
= m_widget
->window
;
2780 gdk_window_get_origin( source
, &org_x
, &org_y
);
2784 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2786 org_x
+= m_widget
->allocation
.x
;
2787 org_y
+= m_widget
->allocation
.y
;
2794 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2795 *x
= (GetClientSize().x
- *x
) + org_x
;
2803 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
2805 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2807 if (!m_widget
->window
) return;
2809 GdkWindow
*source
= (GdkWindow
*) NULL
;
2811 source
= m_wxwindow
->window
;
2813 source
= m_widget
->window
;
2817 gdk_window_get_origin( source
, &org_x
, &org_y
);
2821 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2823 org_x
+= m_widget
->allocation
.x
;
2824 org_y
+= m_widget
->allocation
.y
;
2830 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2831 *x
= (GetClientSize().x
- *x
) - org_x
;
2838 bool wxWindowGTK::Show( bool show
)
2840 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
2842 if (!wxWindowBase::Show(show
))
2848 if (show
&& m_showOnIdle
)
2855 gtk_widget_show(m_widget
);
2857 gtk_widget_hide(m_widget
);
2858 wxShowEvent
eventShow(GetId(), show
);
2859 eventShow
.SetEventObject(this);
2860 HandleWindowEvent(eventShow
);
2866 void wxWindowGTK::DoEnable( bool enable
)
2868 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2870 gtk_widget_set_sensitive( m_widget
, enable
);
2871 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2872 gtk_widget_set_sensitive( m_wxwindow
, enable
);
2875 int wxWindowGTK::GetCharHeight() const
2877 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
2879 wxFont font
= GetFont();
2880 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
2882 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2887 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2888 PangoLayout
*layout
= pango_layout_new(context
);
2889 pango_layout_set_font_description(layout
, desc
);
2890 pango_layout_set_text(layout
, "H", 1);
2891 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2893 PangoRectangle rect
;
2894 pango_layout_line_get_extents(line
, NULL
, &rect
);
2896 g_object_unref (layout
);
2898 return (int) PANGO_PIXELS(rect
.height
);
2901 int wxWindowGTK::GetCharWidth() const
2903 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
2905 wxFont font
= GetFont();
2906 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
2908 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
2913 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
2914 PangoLayout
*layout
= pango_layout_new(context
);
2915 pango_layout_set_font_description(layout
, desc
);
2916 pango_layout_set_text(layout
, "g", 1);
2917 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
2919 PangoRectangle rect
;
2920 pango_layout_line_get_extents(line
, NULL
, &rect
);
2922 g_object_unref (layout
);
2924 return (int) PANGO_PIXELS(rect
.width
);
2927 void wxWindowGTK::GetTextExtent( const wxString
& string
,
2931 int *externalLeading
,
2932 const wxFont
*theFont
) const
2934 wxFont fontToUse
= theFont
? *theFont
: GetFont();
2936 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
2945 PangoContext
*context
= NULL
;
2947 context
= gtk_widget_get_pango_context( m_widget
);
2956 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
2957 PangoLayout
*layout
= pango_layout_new(context
);
2958 pango_layout_set_font_description(layout
, desc
);
2960 const wxCharBuffer data
= wxGTK_CONV( string
);
2962 pango_layout_set_text(layout
, data
, strlen(data
));
2965 PangoRectangle rect
;
2966 pango_layout_get_extents(layout
, NULL
, &rect
);
2968 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
2969 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
2972 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
2973 int baseline
= pango_layout_iter_get_baseline(iter
);
2974 pango_layout_iter_free(iter
);
2975 *descent
= *y
- PANGO_PIXELS(baseline
);
2977 if (externalLeading
) (*externalLeading
) = 0; // ??
2979 g_object_unref (layout
);
2982 bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
2984 if ( g_delayedFocus
== this )
2986 if ( GTK_WIDGET_REALIZED(m_widget
) )
2988 gtk_widget_grab_focus(m_widget
);
2989 g_delayedFocus
= NULL
;
2998 void wxWindowGTK::SetFocus()
3000 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3003 // don't do anything if we already have focus
3009 // wxWindow::SetFocus() should really set the focus to
3010 // this control, whatever the flags are
3011 if (!GTK_WIDGET_CAN_FOCUS(m_wxwindow
))
3012 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3014 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3016 gtk_widget_grab_focus (m_wxwindow
);
3021 // wxWindow::SetFocus() should really set the focus to
3022 // this control, whatever the flags are
3023 if (!GTK_WIDGET_CAN_FOCUS(m_widget
))
3024 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3026 if (GTK_IS_CONTAINER(m_widget
))
3028 if (GTK_IS_RADIO_BUTTON(m_widget
))
3030 gtk_widget_grab_focus (m_widget
);
3034 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3037 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3040 if (!GTK_WIDGET_REALIZED(m_widget
))
3042 // we can't set the focus to the widget now so we remember that
3043 // it should be focused and will do it later, during the idle
3044 // time, as soon as we can
3045 wxLogTrace(TRACE_FOCUS
,
3046 _T("Delaying setting focus to %s(%s)"),
3047 GetClassInfo()->GetClassName(), GetLabel().c_str());
3049 g_delayedFocus
= this;
3053 wxLogTrace(TRACE_FOCUS
,
3054 _T("Setting focus to %s(%s)"),
3055 GetClassInfo()->GetClassName(), GetLabel().c_str());
3057 gtk_widget_grab_focus (m_widget
);
3062 wxLogTrace(TRACE_FOCUS
,
3063 _T("Can't set focus to %s(%s)"),
3064 GetClassInfo()->GetClassName(), GetLabel().c_str());
3069 void wxWindowGTK::SetCanFocus(bool canFocus
)
3072 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3074 GTK_WIDGET_UNSET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3076 if ( m_wxwindow
&& (m_widget
!= m_wxwindow
) )
3079 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3081 GTK_WIDGET_UNSET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3085 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3087 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3089 wxWindowGTK
*oldParent
= m_parent
,
3090 *newParent
= (wxWindowGTK
*)newParentBase
;
3092 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3094 if ( !wxWindowBase::Reparent(newParent
) )
3097 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3099 /* prevent GTK from deleting the widget arbitrarily */
3100 gtk_widget_ref( m_widget
);
3104 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3107 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3111 if (GTK_WIDGET_VISIBLE (newParent
->m_widget
))
3113 m_showOnIdle
= true;
3114 gtk_widget_hide( m_widget
);
3117 /* insert GTK representation */
3118 (*(newParent
->m_insertCallback
))(newParent
, this);
3121 /* reverse: prevent GTK from deleting the widget arbitrarily */
3122 gtk_widget_unref( m_widget
);
3124 SetLayoutDirection(wxLayout_Default
);
3129 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3131 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3132 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3137 /* insert GTK representation */
3138 (*m_insertCallback
)(this, child
);
3141 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3143 wxWindowBase::AddChild(child
);
3144 m_dirtyTabOrder
= true;
3145 wxTheApp
->WakeUpIdle();
3148 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3150 wxWindowBase::RemoveChild(child
);
3151 m_dirtyTabOrder
= true;
3152 wxTheApp
->WakeUpIdle();
3156 wxLayoutDirection
wxWindowGTK::GTKGetLayout(GtkWidget
*widget
)
3158 return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
3159 ? wxLayout_RightToLeft
3160 : wxLayout_LeftToRight
;
3164 void wxWindowGTK::GTKSetLayout(GtkWidget
*widget
, wxLayoutDirection dir
)
3166 wxASSERT_MSG( dir
!= wxLayout_Default
, _T("invalid layout direction") );
3168 gtk_widget_set_direction(widget
,
3169 dir
== wxLayout_RightToLeft
? GTK_TEXT_DIR_RTL
3170 : GTK_TEXT_DIR_LTR
);
3173 wxLayoutDirection
wxWindowGTK::GetLayoutDirection() const
3175 return GTKGetLayout(m_widget
);
3178 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
)
3180 if ( dir
== wxLayout_Default
)
3182 const wxWindow
*const parent
= GetParent();
3185 // inherit layout from parent.
3186 dir
= parent
->GetLayoutDirection();
3188 else // no parent, use global default layout
3190 dir
= wxTheApp
->GetLayoutDirection();
3194 if ( dir
== wxLayout_Default
)
3197 GTKSetLayout(m_widget
, dir
);
3199 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3200 GTKSetLayout(m_wxwindow
, dir
);
3204 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
,
3205 wxCoord
WXUNUSED(width
),
3206 wxCoord
WXUNUSED(widthTotal
)) const
3208 // We now mirror the coordinates of RTL windows in wxPizza
3212 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, WindowOrder move
)
3214 wxWindowBase::DoMoveInTabOrder(win
, move
);
3215 m_dirtyTabOrder
= true;
3216 wxTheApp
->WakeUpIdle();
3219 bool wxWindowGTK::DoNavigateIn(int flags
)
3221 if ( flags
& wxNavigationKeyEvent::WinChange
)
3223 wxFAIL_MSG( _T("not implemented") );
3227 else // navigate inside the container
3229 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3230 wxCHECK_MSG( parent
, false, _T("every window must have a TLW parent") );
3232 GtkDirectionType dir
;
3233 dir
= flags
& wxNavigationKeyEvent::IsForward
? GTK_DIR_TAB_FORWARD
3234 : GTK_DIR_TAB_BACKWARD
;
3237 g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
);
3243 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3245 // none needed by default
3249 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3251 // nothing to do by default since none is needed
3254 void wxWindowGTK::RealizeTabOrder()
3258 if ( !m_children
.empty() )
3260 // we don't only construct the correct focus chain but also use
3261 // this opportunity to update the mnemonic widgets for the widgets
3264 GList
*chain
= NULL
;
3265 wxWindowGTK
* mnemonicWindow
= NULL
;
3267 for ( wxWindowList::const_iterator i
= m_children
.begin();
3268 i
!= m_children
.end();
3271 wxWindowGTK
*win
= *i
;
3273 if ( mnemonicWindow
)
3275 if ( win
->AcceptsFocusFromKeyboard() )
3277 // wxComboBox et al. needs to focus on on a different
3278 // widget than m_widget, so if the main widget isn't
3279 // focusable try the connect widget
3280 GtkWidget
* w
= win
->m_widget
;
3281 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3283 w
= win
->GetConnectWidget();
3284 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3290 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3291 mnemonicWindow
= NULL
;
3295 else if ( win
->GTKWidgetNeedsMnemonic() )
3297 mnemonicWindow
= win
;
3300 chain
= g_list_prepend(chain
, win
->m_widget
);
3303 chain
= g_list_reverse(chain
);
3305 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3310 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3315 void wxWindowGTK::Raise()
3317 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3319 if (m_wxwindow
&& m_wxwindow
->window
)
3321 gdk_window_raise( m_wxwindow
->window
);
3323 else if (m_widget
->window
)
3325 gdk_window_raise( m_widget
->window
);
3329 void wxWindowGTK::Lower()
3331 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3333 if (m_wxwindow
&& m_wxwindow
->window
)
3335 gdk_window_lower( m_wxwindow
->window
);
3337 else if (m_widget
->window
)
3339 gdk_window_lower( m_widget
->window
);
3343 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3345 if ( !wxWindowBase::SetCursor(cursor
.Ok() ? cursor
: *wxSTANDARD_CURSOR
) )
3353 void wxWindowGTK::GTKUpdateCursor()
3355 wxCursor
cursor(g_globalCursor
.Ok() ? g_globalCursor
: GetCursor());
3358 wxArrayGdkWindows windowsThis
;
3359 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3362 gdk_window_set_cursor(winThis
, cursor
.GetCursor());
3366 const size_t count
= windowsThis
.size();
3367 for ( size_t n
= 0; n
< count
; n
++ )
3369 GdkWindow
*win
= windowsThis
[n
];
3372 wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?"));
3376 gdk_window_set_cursor(win
, cursor
.GetCursor());
3382 void wxWindowGTK::WarpPointer( int x
, int y
)
3384 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3386 // We provide this function ourselves as it is
3387 // missing in GDK (top of this file).
3389 GdkWindow
*window
= (GdkWindow
*) NULL
;
3391 window
= m_wxwindow
->window
;
3393 window
= GetConnectWidget()->window
;
3396 gdk_window_warp_pointer( window
, x
, y
);
3399 wxWindowGTK::ScrollDir
wxWindowGTK::ScrollDirFromRange(GtkRange
*range
) const
3401 // find the scrollbar which generated the event
3402 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3404 if ( range
== m_scrollBar
[dir
] )
3405 return (ScrollDir
)dir
;
3408 wxFAIL_MSG( _T("event from unknown scrollbar received") );
3410 return ScrollDir_Max
;
3413 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3415 bool changed
= false;
3416 GtkRange
* range
= m_scrollBar
[dir
];
3417 if ( range
&& units
)
3419 GtkAdjustment
* adj
= range
->adjustment
;
3420 gdouble inc
= unit
== ScrollUnit_Line
? adj
->step_increment
3421 : adj
->page_increment
;
3423 const int posOld
= int(adj
->value
+ 0.5);
3424 gtk_range_set_value(range
, posOld
+ units
*inc
);
3426 changed
= int(adj
->value
+ 0.5) != posOld
;
3432 bool wxWindowGTK::ScrollLines(int lines
)
3434 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3437 bool wxWindowGTK::ScrollPages(int pages
)
3439 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3442 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground
),
3447 if (!m_widget
->window
)
3452 if (m_wxwindow
->window
== NULL
) return;
3454 GdkRectangle gdk_rect
,
3458 gdk_rect
.x
= rect
->x
;
3459 gdk_rect
.y
= rect
->y
;
3460 gdk_rect
.width
= rect
->width
;
3461 gdk_rect
.height
= rect
->height
;
3462 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3463 gdk_rect
.x
= GetClientSize().x
- gdk_rect
.x
- gdk_rect
.width
;
3467 else // invalidate everything
3472 gdk_window_invalidate_rect(m_wxwindow
->window
, p
, true);
3476 void wxWindowGTK::Update()
3480 // when we call Update() we really want to update the window immediately on
3481 // screen, even if it means flushing the entire queue and hence slowing down
3482 // everything -- but it should still be done, it's just that Update() should
3483 // be called very rarely
3487 void wxWindowGTK::GtkUpdate()
3489 if (m_wxwindow
&& m_wxwindow
->window
)
3490 gdk_window_process_updates(m_wxwindow
->window
, false);
3491 if (m_widget
&& m_widget
->window
&& (m_wxwindow
!= m_widget
))
3492 gdk_window_process_updates( m_widget
->window
, FALSE
);
3494 // for consistency with other platforms (and also because it's convenient
3495 // to be able to update an entire TLW by calling Update() only once), we
3496 // should also update all our children here
3497 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3499 node
= node
->GetNext() )
3501 node
->GetData()->GtkUpdate();
3505 bool wxWindowGTK::DoIsExposed( int x
, int y
) const
3507 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
3511 bool wxWindowGTK::DoIsExposed( int x
, int y
, int w
, int h
) const
3513 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3514 return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
;
3516 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
3519 void wxWindowGTK::GtkSendPaintEvents()
3523 m_updateRegion
.Clear();
3527 // Clip to paint region in wxClientDC
3528 m_clipPaintRegion
= true;
3530 m_nativeUpdateRegion
= m_updateRegion
;
3532 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3534 // Transform m_updateRegion under RTL
3535 m_updateRegion
.Clear();
3538 gdk_drawable_get_size(m_wxwindow
->window
, &width
, NULL
);
3540 wxRegionIterator
upd( m_nativeUpdateRegion
);
3544 rect
.x
= upd
.GetX();
3545 rect
.y
= upd
.GetY();
3546 rect
.width
= upd
.GetWidth();
3547 rect
.height
= upd
.GetHeight();
3549 rect
.x
= width
- rect
.x
- rect
.width
;
3550 m_updateRegion
.Union( rect
);
3556 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3558 // find ancestor from which to steal background
3559 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3561 parent
= (wxWindow
*)this;
3563 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3565 wxRegionIterator
upd( m_nativeUpdateRegion
);
3569 rect
.x
= upd
.GetX();
3570 rect
.y
= upd
.GetY();
3571 rect
.width
= upd
.GetWidth();
3572 rect
.height
= upd
.GetHeight();
3574 gtk_paint_flat_box( parent
->m_widget
->style
,
3576 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3589 wxWindowDC
dc( (wxWindow
*)this );
3590 dc
.SetClippingRegion( m_updateRegion
);
3592 // Work around gtk-qt <= 0.60 bug whereby the window colour
3594 if (GetBackgroundStyle() == wxBG_STYLE_COLOUR
&& GetBackgroundColour().Ok() && wxSystemOptions::GetOptionInt(wxT("gtk.window.force-background-colour")) == 1)
3596 dc
.SetBackground(wxBrush(GetBackgroundColour()));
3600 wxEraseEvent
erase_event( GetId(), &dc
);
3601 erase_event
.SetEventObject( this );
3603 HandleWindowEvent(erase_event
);
3606 wxNcPaintEvent
nc_paint_event( GetId() );
3607 nc_paint_event
.SetEventObject( this );
3608 HandleWindowEvent( nc_paint_event
);
3610 wxPaintEvent
paint_event( GetId() );
3611 paint_event
.SetEventObject( this );
3612 HandleWindowEvent( paint_event
);
3614 m_clipPaintRegion
= false;
3616 m_updateRegion
.Clear();
3617 m_nativeUpdateRegion
.Clear();
3620 void wxWindowGTK::SetDoubleBuffered( bool on
)
3622 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3625 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3628 bool wxWindowGTK::IsDoubleBuffered() const
3630 return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow
);
3633 void wxWindowGTK::ClearBackground()
3635 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3639 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3641 wxWindowBase::DoSetToolTip(tip
);
3644 m_tooltip
->Apply( (wxWindow
*)this );
3647 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const gchar
*tip
)
3649 gtk_tooltips_set_tip(tips
, GetConnectWidget(), tip
, NULL
);
3651 #endif // wxUSE_TOOLTIPS
3653 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3655 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3657 if (!wxWindowBase::SetBackgroundColour(colour
))
3662 // We need the pixel value e.g. for background clearing.
3663 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3666 // apply style change (forceStyle=true so that new style is applied
3667 // even if the bg colour changed from valid to wxNullColour)
3668 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3669 ApplyWidgetStyle(true);
3674 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3676 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3678 if (!wxWindowBase::SetForegroundColour(colour
))
3685 // We need the pixel value e.g. for background clearing.
3686 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3689 // apply style change (forceStyle=true so that new style is applied
3690 // even if the bg colour changed from valid to wxNullColour):
3691 ApplyWidgetStyle(true);
3696 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3698 return gtk_widget_get_pango_context( m_widget
);
3701 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3703 // do we need to apply any changes at all?
3706 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3711 GtkRcStyle
*style
= gtk_rc_style_new();
3716 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3719 int flagsNormal
= 0,
3722 flagsInsensitive
= 0;
3724 if ( m_foregroundColour
.Ok() )
3726 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3728 style
->fg
[GTK_STATE_NORMAL
] =
3729 style
->text
[GTK_STATE_NORMAL
] = *fg
;
3730 flagsNormal
|= GTK_RC_FG
| GTK_RC_TEXT
;
3732 style
->fg
[GTK_STATE_PRELIGHT
] =
3733 style
->text
[GTK_STATE_PRELIGHT
] = *fg
;
3734 flagsPrelight
|= GTK_RC_FG
| GTK_RC_TEXT
;
3736 style
->fg
[GTK_STATE_ACTIVE
] =
3737 style
->text
[GTK_STATE_ACTIVE
] = *fg
;
3738 flagsActive
|= GTK_RC_FG
| GTK_RC_TEXT
;
3741 if ( m_backgroundColour
.Ok() )
3743 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3745 style
->bg
[GTK_STATE_NORMAL
] =
3746 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3747 flagsNormal
|= GTK_RC_BG
| GTK_RC_BASE
;
3749 style
->bg
[GTK_STATE_PRELIGHT
] =
3750 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3751 flagsPrelight
|= GTK_RC_BG
| GTK_RC_BASE
;
3753 style
->bg
[GTK_STATE_ACTIVE
] =
3754 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3755 flagsActive
|= GTK_RC_BG
| GTK_RC_BASE
;
3757 style
->bg
[GTK_STATE_INSENSITIVE
] =
3758 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3759 flagsInsensitive
|= GTK_RC_BG
| GTK_RC_BASE
;
3762 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
;
3763 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
;
3764 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
;
3765 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
;
3770 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3772 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3775 DoApplyWidgetStyle(style
);
3776 gtk_rc_style_unref(style
);
3779 // Style change may affect GTK+'s size calculation:
3780 InvalidateBestSize();
3783 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3785 wxSuspendStyleEvents
s(static_cast<wxWindow
*>(this));
3788 gtk_widget_modify_style(m_wxwindow
, style
);
3790 gtk_widget_modify_style(m_widget
, style
);
3793 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3795 wxWindowBase::SetBackgroundStyle(style
);
3797 if (style
== wxBG_STYLE_CUSTOM
)
3802 window
= m_wxwindow
->window
;
3806 GtkWidget
* const w
= GetConnectWidget();
3807 window
= w
? w
->window
: NULL
;
3812 // Make sure GDK/X11 doesn't refresh the window
3814 gdk_window_set_back_pixmap( window
, None
, False
);
3816 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3819 m_needsStyleChange
= false;
3821 else // window not realized yet
3823 // Do in OnIdle, because the window is not yet available
3824 m_needsStyleChange
= true;
3827 // Don't apply widget style, or we get a grey background
3831 // apply style change (forceStyle=true so that new style is applied
3832 // even if the bg colour changed from valid to wxNullColour):
3833 ApplyWidgetStyle(true);
3838 #if wxUSE_DRAG_AND_DROP
3840 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3842 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3844 GtkWidget
*dnd_widget
= GetConnectWidget();
3846 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3848 if (m_dropTarget
) delete m_dropTarget
;
3849 m_dropTarget
= dropTarget
;
3851 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3854 #endif // wxUSE_DRAG_AND_DROP
3856 GtkWidget
* wxWindowGTK::GetConnectWidget()
3858 GtkWidget
*connect_widget
= m_widget
;
3859 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3861 return connect_widget
;
3864 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow
*window
) const
3866 wxArrayGdkWindows windowsThis
;
3867 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3869 return winThis
? window
== winThis
3870 : windowsThis
.Index(window
) != wxNOT_FOUND
;
3873 GdkWindow
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
3875 return m_wxwindow
? m_wxwindow
->window
: m_widget
->window
;
3878 bool wxWindowGTK::SetFont( const wxFont
&font
)
3880 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3882 if (!wxWindowBase::SetFont(font
))
3885 // apply style change (forceStyle=true so that new style is applied
3886 // even if the font changed from valid to wxNullFont):
3887 ApplyWidgetStyle(true);
3892 void wxWindowGTK::DoCaptureMouse()
3894 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3896 GdkWindow
*window
= (GdkWindow
*) NULL
;
3898 window
= m_wxwindow
->window
;
3900 window
= GetConnectWidget()->window
;
3902 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3904 const wxCursor
* cursor
= &m_cursor
;
3906 cursor
= wxSTANDARD_CURSOR
;
3908 gdk_pointer_grab( window
, FALSE
,
3910 (GDK_BUTTON_PRESS_MASK
|
3911 GDK_BUTTON_RELEASE_MASK
|
3912 GDK_POINTER_MOTION_HINT_MASK
|
3913 GDK_POINTER_MOTION_MASK
),
3915 cursor
->GetCursor(),
3916 (guint32
)GDK_CURRENT_TIME
);
3917 g_captureWindow
= this;
3918 g_captureWindowHasMouse
= true;
3921 void wxWindowGTK::DoReleaseMouse()
3923 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3925 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3927 g_captureWindow
= (wxWindowGTK
*) NULL
;
3929 GdkWindow
*window
= (GdkWindow
*) NULL
;
3931 window
= m_wxwindow
->window
;
3933 window
= GetConnectWidget()->window
;
3938 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3941 void wxWindowGTK::GTKReleaseMouseAndNotify()
3944 wxMouseCaptureLostEvent
evt(GetId());
3945 evt
.SetEventObject( this );
3946 HandleWindowEvent( evt
);
3950 wxWindow
*wxWindowBase::GetCapture()
3952 return (wxWindow
*)g_captureWindow
;
3955 bool wxWindowGTK::IsRetained() const
3960 void wxWindowGTK::SetScrollbar(int orient
,
3964 bool WXUNUSED(update
))
3966 const int dir
= ScrollDirFromOrient(orient
);
3967 GtkRange
* const sb
= m_scrollBar
[dir
];
3968 wxCHECK_RET( sb
, _T("this window is not scrollable") );
3972 // GtkRange requires upper > lower
3977 GtkAdjustment
* const adj
= sb
->adjustment
;
3978 adj
->step_increment
= 1;
3979 adj
->page_increment
=
3980 adj
->page_size
= thumbVisible
;
3983 g_signal_handlers_block_by_func(
3984 sb
, (void*)gtk_scrollbar_value_changed
, this);
3986 gtk_range_set_range(sb
, 0, range
);
3987 m_scrollPos
[dir
] = sb
->adjustment
->value
;
3989 g_signal_handlers_unblock_by_func(
3990 sb
, (void*)gtk_scrollbar_value_changed
, this);
3993 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
3995 const int dir
= ScrollDirFromOrient(orient
);
3996 GtkRange
* const sb
= m_scrollBar
[dir
];
3997 wxCHECK_RET( sb
, _T("this window is not scrollable") );
3999 // This check is more than an optimization. Without it, the slider
4000 // will not move smoothly while tracking when using wxScrollHelper.
4001 if (GetScrollPos(orient
) != pos
)
4003 g_signal_handlers_block_by_func(
4004 sb
, (void*)gtk_scrollbar_value_changed
, this);
4006 gtk_range_set_value(sb
, pos
);
4007 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4009 g_signal_handlers_unblock_by_func(
4010 sb
, (void*)gtk_scrollbar_value_changed
, this);
4014 int wxWindowGTK::GetScrollThumb(int orient
) const
4016 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4017 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4019 return int(sb
->adjustment
->page_size
);
4022 int wxWindowGTK::GetScrollPos( 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
->value
+ 0.5);
4030 int wxWindowGTK::GetScrollRange( 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
->upper
);
4038 // Determine if increment is the same as +/-x, allowing for some small
4039 // difference due to possible inexactness in floating point arithmetic
4040 static inline bool IsScrollIncrement(double increment
, double x
)
4042 wxASSERT(increment
> 0);
4043 const double tolerance
= 1.0 / 1024;
4044 return fabs(increment
- fabs(x
)) < tolerance
;
4047 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4049 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4051 const int barIndex
= range
== m_scrollBar
[1];
4052 GtkAdjustment
* adj
= range
->adjustment
;
4054 const int value
= int(adj
->value
+ 0.5);
4056 // save previous position
4057 const double oldPos
= m_scrollPos
[barIndex
];
4058 // update current position
4059 m_scrollPos
[barIndex
] = adj
->value
;
4060 // If event should be ignored, or integral position has not changed
4061 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4066 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4069 // Difference from last change event
4070 const double diff
= adj
->value
- oldPos
;
4071 const bool isDown
= diff
> 0;
4073 if (IsScrollIncrement(adj
->step_increment
, diff
))
4075 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4077 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4079 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4081 else if (m_mouseButtonDown
)
4083 // Assume track event
4084 m_isScrolling
= true;
4090 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4092 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4094 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4096 // No scrolling requested.
4097 if ((dx
== 0) && (dy
== 0)) return;
4099 m_clipPaintRegion
= true;
4101 WX_PIZZA(m_wxwindow
)->scroll(dx
, dy
);
4103 m_clipPaintRegion
= false;
4106 bool restoreCaret
= (GetCaret() != NULL
&& GetCaret()->IsVisible());
4109 wxRect
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4111 caretRect
.width
+= dx
;
4114 caretRect
.x
+= dx
; caretRect
.width
-= dx
;
4117 caretRect
.height
+= dy
;
4120 caretRect
.y
+= dy
; caretRect
.height
-= dy
;
4123 RefreshRect(caretRect
);
4125 #endif // wxUSE_CARET
4128 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4130 //RN: Note that static controls usually have no border on gtk, so maybe
4131 //it makes sense to treat that as simply no border at the wx level
4133 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4135 GtkShadowType gtkstyle
;
4137 if(wxstyle
& wxBORDER_RAISED
)
4138 gtkstyle
= GTK_SHADOW_OUT
;
4139 else if (wxstyle
& wxBORDER_SUNKEN
)
4140 gtkstyle
= GTK_SHADOW_IN
;
4143 else if (wxstyle
& wxBORDER_DOUBLE
)
4144 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4147 gtkstyle
= GTK_SHADOW_IN
;
4149 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4154 void wxWindowGTK::SetWindowStyleFlag( long style
)
4156 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4157 wxWindowBase::SetWindowStyleFlag(style
);
4160 // Find the wxWindow at the current mouse position, also returning the mouse
4162 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4164 pt
= wxGetMousePosition();
4165 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4169 // Get the current mouse position.
4170 wxPoint
wxGetMousePosition()
4172 /* This crashes when used within wxHelpContext,
4173 so we have to use the X-specific implementation below.
4175 GdkModifierType *mask;
4176 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4178 return wxPoint(x, y);
4182 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4184 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4185 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4186 Window rootReturn
, childReturn
;
4187 int rootX
, rootY
, winX
, winY
;
4188 unsigned int maskReturn
;
4190 XQueryPointer (display
,
4194 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4195 return wxPoint(rootX
, rootY
);
4199 GdkWindow
* wxWindowGTK::GTKGetDrawingWindow() const
4201 GdkWindow
* window
= NULL
;
4203 window
= m_wxwindow
->window
;
4207 // ----------------------------------------------------------------------------
4209 // ----------------------------------------------------------------------------
4211 void wxWindowGTK::GTKFreezeWidget(GtkWidget
*w
)
4213 if ( w
&& !GTK_WIDGET_NO_WINDOW(w
) )
4214 gdk_window_freeze_updates(w
->window
);
4217 void wxWindowGTK::GTKThawWidget(GtkWidget
*w
)
4219 if ( w
&& !GTK_WIDGET_NO_WINDOW(w
) )
4220 gdk_window_thaw_updates(w
->window
);
4223 void wxWindowGTK::DoFreeze()
4225 GTKFreezeWidget(m_widget
);
4226 if ( m_wxwindow
&& m_widget
!= m_wxwindow
)
4227 GTKFreezeWidget(m_wxwindow
);
4230 void wxWindowGTK::DoThaw()
4232 GTKThawWidget(m_widget
);
4233 if ( m_wxwindow
&& m_widget
!= m_wxwindow
)
4234 GTKThawWidget(m_wxwindow
);