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"
37 #include "wx/thread.h"
42 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
43 #include <gtk/gtkversion.h>
44 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
45 #undef GTK_DISABLE_DEPRECATED
46 #include <gtk/gtkcombo.h>
47 #define GTK_DISABLE_DEPRECATED
50 #include "wx/gtk/private.h"
51 #include "wx/gtk/win_gtk.h"
52 #include <gdk/gdkkeysyms.h>
55 //-----------------------------------------------------------------------------
56 // documentation on internals
57 //-----------------------------------------------------------------------------
60 I have been asked several times about writing some documentation about
61 the GTK port of wxWidgets, especially its internal structures. Obviously,
62 you cannot understand wxGTK without knowing a little about the GTK, but
63 some more information about what the wxWindow, which is the base class
64 for all other window classes, does seems required as well.
68 What does wxWindow do? It contains the common interface for the following
69 jobs of its descendants:
71 1) Define the rudimentary behaviour common to all window classes, such as
72 resizing, intercepting user input (so as to make it possible to use these
73 events for special purposes in a derived class), window names etc.
75 2) Provide the possibility to contain and manage children, if the derived
76 class is allowed to contain children, which holds true for those window
77 classes which do not display a native GTK widget. To name them, these
78 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
79 work classes are a special case and are handled a bit differently from
80 the rest. The same holds true for the wxNotebook class.
82 3) Provide the possibility to draw into a client area of a window. This,
83 too, only holds true for classes that do not display a native GTK widget
86 4) Provide the entire mechanism for scrolling widgets. This actual inter-
87 face for this is usually in wxScrolledWindow, but the GTK implementation
90 5) A multitude of helper or extra methods for special purposes, such as
91 Drag'n'Drop, managing validators etc.
93 6) Display a border (sunken, raised, simple or none).
95 Normally one might expect, that one wxWidgets window would always correspond
96 to one GTK widget. Under GTK, there is no such all-round widget that has all
97 the functionality. Moreover, the GTK defines a client area as a different
98 widget from the actual widget you are handling. Last but not least some
99 special classes (e.g. wxFrame) handle different categories of widgets and
100 still have the possibility to draw something in the client area.
101 It was therefore required to write a special purpose GTK widget, that would
102 represent a client area in the sense of wxWidgets capable to do the jobs
103 2), 3) and 4). I have written this class and it resides in win_gtk.c of
106 All windows must have a widget, with which they interact with other under-
107 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
108 the wxWindow class has a member variable called m_widget which holds a
109 pointer to this widget. When the window class represents a GTK native widget,
110 this is (in most cases) the only GTK widget the class manages. E.g. the
111 wxStaticText class handles only a GtkLabel widget a pointer to which you
112 can find in m_widget (defined in wxWindow)
114 When the class has a client area for drawing into and for containing children
115 it has to handle the client area widget (of the type GtkPizza, defined in
116 win_gtk.c), but there could be any number of widgets, handled by a class
117 The common rule for all windows is only, that the widget that interacts with
118 the rest of GTK must be referenced in m_widget and all other widgets must be
119 children of this widget on the GTK level. The top-most widget, which also
120 represents the client area, must be in the m_wxwindow field and must be of
123 As I said, the window classes that display a GTK native widget only have
124 one widget, so in the case of e.g. the wxButton class m_widget holds a
125 pointer to a GtkButton widget. But windows with client areas (for drawing
126 and children) have a m_widget field that is a pointer to a GtkScrolled-
127 Window and a m_wxwindow field that is pointer to a GtkPizza and this
128 one is (in the GTK sense) a child of the GtkScrolledWindow.
130 If the m_wxwindow field is set, then all input to this widget is inter-
131 cepted and sent to the wxWidgets class. If not, all input to the widget
132 that gets pointed to by m_widget gets intercepted and sent to the class.
136 The design of scrolling in wxWidgets is markedly different from that offered
137 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
138 clicking on a scrollbar belonging to scrolled window will inevitably move
139 the window. In wxWidgets, the scrollbar will only emit an event, send this
140 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
141 which actually moves the window and its sub-windows. Note that GtkPizza
142 memorizes how much it has been scrolled but that wxWidgets forgets this
143 so that the two coordinates systems have to be kept in synch. This is done
144 in various places using the pizza->xoffset and pizza->yoffset values.
148 Singularly the most broken code in GTK is the code that is supposed to
149 inform subwindows (child windows) about new positions. Very often, duplicate
150 events are sent without changes in size or position, equally often no
151 events are sent at all (All this is due to a bug in the GtkContainer code
152 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
153 GTK's own system and it simply waits for size events for toplevel windows
154 and then iterates down the respective size events to all window. This has
155 the disadvantage that windows might get size events before the GTK widget
156 actually has the reported size. This doesn't normally pose any problem, but
157 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
158 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
159 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
160 window that is used for OpenGL output really has that size (as reported by
165 If someone at some point of time feels the immense desire to have a look at,
166 change or attempt to optimise the Refresh() logic, this person will need an
167 intimate understanding of what "draw" and "expose" events are and what
168 they are used for, in particular when used in connection with GTK's
169 own windowless widgets. Beware.
173 Cursors, too, have been a constant source of pleasure. The main difficulty
174 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
175 for the parent. To prevent this from doing too much harm, I use idle time
176 to set the cursor over and over again, starting from the toplevel windows
177 and ending with the youngest generation (speaking of parent and child windows).
178 Also don't forget that cursors (like much else) are connected to GdkWindows,
179 not GtkWidgets and that the "window" field of a GtkWidget might very well
180 point to the GdkWindow of the parent widget (-> "window-less widget") and
181 that the two obviously have very different meanings.
185 //-----------------------------------------------------------------------------
187 //-----------------------------------------------------------------------------
189 // Don't allow event propagation during drag
190 bool g_blockEventsOnDrag
;
191 // Don't allow mouse event propagation during scroll
192 bool g_blockEventsOnScroll
;
193 extern wxCursor g_globalCursor
;
195 // mouse capture state: the window which has it and if the mouse is currently
197 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
198 static bool g_captureWindowHasMouse
= false;
200 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
202 // the last window which had the focus - this is normally never NULL (except
203 // if we never had focus at all) as even when g_focusWindow is NULL it still
204 // keeps its previous value
205 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
207 // If a window get the focus set but has not been realized
208 // yet, defer setting the focus to idle time.
209 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
211 // global variables because GTK+ DnD want to have the
212 // mouse event that caused it
213 GdkEvent
*g_lastMouseEvent
= (GdkEvent
*) NULL
;
214 int g_lastButtonNumber
= 0;
216 extern bool g_mainThreadLocked
;
218 //-----------------------------------------------------------------------------
220 //-----------------------------------------------------------------------------
225 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
227 # define DEBUG_MAIN_THREAD
230 #define DEBUG_MAIN_THREAD
233 // the trace mask used for the focus debugging messages
234 #define TRACE_FOCUS _T("focus")
236 //-----------------------------------------------------------------------------
237 // missing gdk functions
238 //-----------------------------------------------------------------------------
241 gdk_window_warp_pointer (GdkWindow
*window
,
246 window
= gdk_get_default_root_window();
248 if (!GDK_WINDOW_DESTROYED(window
))
250 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
251 None
, /* not source window -> move from anywhere */
252 GDK_WINDOW_XID(window
), /* dest window */
253 0, 0, 0, 0, /* not source window -> move from anywhere */
258 //-----------------------------------------------------------------------------
259 // local code (see below)
260 //-----------------------------------------------------------------------------
262 // returns the child of win which currently has focus or NULL if not found
264 // Note: can't be static, needed by textctrl.cpp.
265 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
267 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
269 return (wxWindow
*)NULL
;
271 if ( winFocus
== win
)
272 return (wxWindow
*)win
;
274 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
276 node
= node
->GetNext() )
278 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
283 return (wxWindow
*)NULL
;
286 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
)
288 GtkScrolledWindow
* scroll_window
= GTK_SCROLLED_WINDOW(widget
);
289 GtkScrolledWindowClass
* scroll_class
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
));
290 GtkRequisition scroll_req
;
293 if (scroll_window
->vscrollbar_visible
)
295 scroll_req
.width
= 2;
296 scroll_req
.height
= 2;
297 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
298 (scroll_window
->vscrollbar
, &scroll_req
);
299 w
= scroll_req
.width
+
300 scroll_class
->scrollbar_spacing
;
304 if (scroll_window
->hscrollbar_visible
)
306 scroll_req
.width
= 2;
307 scroll_req
.height
= 2;
308 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
309 (scroll_window
->hscrollbar
, &scroll_req
);
310 h
= scroll_req
.height
+
311 scroll_class
->scrollbar_spacing
;
315 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
317 // wxUniversal widgets draw the borders and scrollbars themselves
318 #ifndef __WXUNIVERSAL__
324 if (GTK_WIDGET_NO_WINDOW (widget
))
326 dx
+= widget
->allocation
.x
;
327 dy
+= widget
->allocation
.y
;
335 if (win
->m_hasScrolling
)
337 GetScrollbarWidth(widget
, dw
, dh
);
339 if (win
->GetLayoutDirection() == wxLayout_RightToLeft
)
341 // This is actually wrong for old GTK+ version
342 // which do not display the scrollbar on the
348 int w
= widget
->allocation
.width
-dw
;
349 int h
= widget
->allocation
.height
-dh
;
351 if (win
->HasFlag(wxRAISED_BORDER
))
353 gtk_paint_shadow (widget
->style
,
357 NULL
, NULL
, NULL
, // FIXME: No clipping?
362 if (win
->HasFlag(wxSUNKEN_BORDER
))
364 gtk_paint_shadow (widget
->style
,
368 NULL
, NULL
, NULL
, // FIXME: No clipping?
373 if (win
->HasFlag(wxSIMPLE_BORDER
))
376 gc
= gdk_gc_new( widget
->window
);
377 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
378 gdk_draw_rectangle( widget
->window
, gc
, FALSE
, x
, y
, w
-1, h
-1 );
382 #endif // __WXUNIVERSAL__
385 //-----------------------------------------------------------------------------
386 // "expose_event" of m_widget
387 //-----------------------------------------------------------------------------
391 gtk_window_own_expose_callback( GtkWidget
*widget
,
392 GdkEventExpose
*gdk_event
,
395 if (gdk_event
->count
== 0)
396 draw_frame(widget
, win
);
401 //-----------------------------------------------------------------------------
402 // "size_request" of m_widget
403 //-----------------------------------------------------------------------------
405 // make it extern because wxStaticText needs to disconnect this one
407 void wxgtk_window_size_request_callback(GtkWidget
* WXUNUSED(widget
),
408 GtkRequisition
*requisition
,
412 win
->GetSize( &w
, &h
);
418 requisition
->height
= h
;
419 requisition
->width
= w
;
427 void wxgtk_combo_size_request_callback(GtkWidget
* WXUNUSED(widget
),
428 GtkRequisition
*requisition
,
431 // This callback is actually hooked into the text entry
432 // of the combo box, not the GtkHBox.
435 win
->GetSize( &w
, &h
);
441 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
443 GtkRequisition entry_req
;
445 entry_req
.height
= 2;
446 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->entry
) )->size_request
)
447 (gcombo
->entry
, &entry_req
);
449 GtkRequisition button_req
;
450 button_req
.width
= 2;
451 button_req
.height
= 2;
452 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
453 (gcombo
->button
, &button_req
);
455 requisition
->width
= w
- button_req
.width
;
456 requisition
->height
= entry_req
.height
;
460 #endif // wxUSE_COMBOBOX
462 //-----------------------------------------------------------------------------
463 // "expose_event" of m_wxwindow
464 //-----------------------------------------------------------------------------
468 gtk_window_expose_callback( GtkWidget
*widget
,
469 GdkEventExpose
*gdk_event
,
474 // This callback gets called in drawing-idle time under
475 // GTK 2.0, so we don't need to defer anything to idle
478 GtkPizza
*pizza
= GTK_PIZZA( widget
);
479 if (gdk_event
->window
!= pizza
->bin_window
)
481 // block expose events on GTK_WIDGET(pizza)->window,
482 // all drawing is done on pizza->bin_window
490 wxPrintf( wxT("OnExpose from ") );
491 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
492 wxPrintf( win
->GetClassInfo()->GetClassName() );
493 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
494 (int)gdk_event
->area
.y
,
495 (int)gdk_event
->area
.width
,
496 (int)gdk_event
->area
.height
);
501 win
->m_wxwindow
->style
,
505 (GdkRectangle
*) NULL
,
507 (char *)"button", // const_cast
512 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
514 win
->GtkSendPaintEvents();
516 // Let parent window draw window-less widgets
521 //-----------------------------------------------------------------------------
522 // "key_press_event" from any window
523 //-----------------------------------------------------------------------------
525 // These are used when transforming Ctrl-alpha to ascii values 1-26
526 inline bool wxIsLowerChar(int code
)
528 return (code
>= 'a' && code
<= 'z' );
531 inline bool wxIsUpperChar(int code
)
533 return (code
>= 'A' && code
<= 'Z' );
537 // set WXTRACE to this to see the key event codes on the console
538 #define TRACE_KEYS _T("keyevent")
540 // translates an X key symbol to WXK_XXX value
542 // if isChar is true it means that the value returned will be used for EVT_CHAR
543 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
544 // for example, while if it is false it means that the value is going to be
545 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
547 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
553 // Shift, Control and Alt don't generate the CHAR events at all
556 key_code
= isChar
? 0 : WXK_SHIFT
;
560 key_code
= isChar
? 0 : WXK_CONTROL
;
568 key_code
= isChar
? 0 : WXK_ALT
;
571 // neither do the toggle modifies
572 case GDK_Scroll_Lock
:
573 key_code
= isChar
? 0 : WXK_SCROLL
;
577 key_code
= isChar
? 0 : WXK_CAPITAL
;
581 key_code
= isChar
? 0 : WXK_NUMLOCK
;
585 // various other special keys
598 case GDK_ISO_Left_Tab
:
605 key_code
= WXK_RETURN
;
609 key_code
= WXK_CLEAR
;
613 key_code
= WXK_PAUSE
;
617 key_code
= WXK_SELECT
;
621 key_code
= WXK_PRINT
;
625 key_code
= WXK_EXECUTE
;
629 key_code
= WXK_ESCAPE
;
632 // cursor and other extended keyboard keys
634 key_code
= WXK_DELETE
;
650 key_code
= WXK_RIGHT
;
657 case GDK_Prior
: // == GDK_Page_Up
658 key_code
= WXK_PAGEUP
;
661 case GDK_Next
: // == GDK_Page_Down
662 key_code
= WXK_PAGEDOWN
;
674 key_code
= WXK_INSERT
;
689 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
693 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
697 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
701 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
705 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
709 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
713 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
717 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
721 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
725 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
729 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
733 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
737 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
740 case GDK_KP_Prior
: // == GDK_KP_Page_Up
741 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
744 case GDK_KP_Next
: // == GDK_KP_Page_Down
745 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
749 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
753 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
757 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
761 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
765 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
768 case GDK_KP_Multiply
:
769 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
773 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
776 case GDK_KP_Separator
:
777 // FIXME: what is this?
778 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
781 case GDK_KP_Subtract
:
782 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
786 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
790 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
807 key_code
= WXK_F1
+ keysym
- GDK_F1
;
817 static inline bool wxIsAsciiKeysym(KeySym ks
)
822 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
824 GdkEventKey
*gdk_event
)
828 GdkModifierType state
;
829 if (gdk_event
->window
)
830 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
832 event
.SetTimestamp( gdk_event
->time
);
833 event
.SetId(win
->GetId());
834 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
835 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
836 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
837 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
838 event
.m_scanCode
= gdk_event
->keyval
;
839 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
840 event
.m_rawFlags
= 0;
842 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
844 wxGetMousePosition( &x
, &y
);
845 win
->ScreenToClient( &x
, &y
);
848 event
.SetEventObject( win
);
853 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
855 GdkEventKey
*gdk_event
)
857 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
858 // but only event->keyval which is quite useless to us, so remember
859 // the last character from GDK_KEY_PRESS and reuse it as last resort
861 // NB: should be MT-safe as we're always called from the main thread only
866 } s_lastKeyPress
= { 0, 0 };
868 KeySym keysym
= gdk_event
->keyval
;
870 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
871 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
875 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
879 // do we have the translation or is it a plain ASCII character?
880 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
882 // we should use keysym if it is ASCII as X does some translations
883 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
884 // which we don't want here (but which we do use for OnChar())
885 if ( !wxIsAsciiKeysym(keysym
) )
887 keysym
= (KeySym
)gdk_event
->string
[0];
890 // we want to always get the same key code when the same key is
891 // pressed regardless of the state of the modifiers, i.e. on a
892 // standard US keyboard pressing '5' or '%' ('5' key with
893 // Shift) should result in the same key code in OnKeyDown():
894 // '5' (although OnChar() will get either '5' or '%').
896 // to do it we first translate keysym to keycode (== scan code)
897 // and then back but always using the lower register
898 Display
*dpy
= (Display
*)wxGetDisplay();
899 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
901 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
903 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
905 // use the normalized, i.e. lower register, keysym if we've
907 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
909 // as explained above, we want to have lower register key codes
910 // normally but for the letter keys we want to have the upper ones
912 // NB: don't use XConvertCase() here, we want to do it for letters
914 key_code
= toupper(key_code
);
916 else // non ASCII key, what to do?
918 // by default, ignore it
921 // but if we have cached information from the last KEY_PRESS
922 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
925 if ( keysym
== s_lastKeyPress
.keysym
)
927 key_code
= s_lastKeyPress
.keycode
;
932 if ( gdk_event
->type
== GDK_KEY_PRESS
)
934 // remember it to be reused for KEY_UP event later
935 s_lastKeyPress
.keysym
= keysym
;
936 s_lastKeyPress
.keycode
= key_code
;
940 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
942 // sending unknown key events doesn't really make sense
946 // now fill all the other fields
947 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
949 event
.m_keyCode
= key_code
;
951 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
953 event
.m_uniChar
= key_code
;
963 GtkIMContext
*context
;
964 GdkEventKey
*lastKeyEvent
;
968 context
= gtk_im_multicontext_new();
973 g_object_unref (context
);
979 gtk_window_key_press_callback( GtkWidget
*widget
,
980 GdkEventKey
*gdk_event
,
987 if (g_blockEventsOnDrag
)
990 // GTK+ sends keypress events to the focus widget and then
991 // to all its parent and grandparent widget. We only want
992 // the key events from the focus widget.
993 if (!GTK_WIDGET_HAS_FOCUS(widget
))
996 wxKeyEvent
event( wxEVT_KEY_DOWN
);
998 bool return_after_IM
= false;
1000 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1002 // Emit KEY_DOWN event
1003 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1007 // Return after IM processing as we cannot do
1008 // anything with it anyhow.
1009 return_after_IM
= true;
1012 if ((!ret
) && (win
->m_imData
!= NULL
))
1014 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1015 // docs, if IM filter returns true, no further processing should be done.
1016 // we should send the key_down event anyway.
1017 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1018 win
->m_imData
->lastKeyEvent
= NULL
;
1019 if (intercepted_by_IM
)
1021 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1026 if (return_after_IM
)
1032 wxWindowGTK
*ancestor
= win
;
1035 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1038 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1039 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1042 if (ancestor
->IsTopLevel())
1044 ancestor
= ancestor
->GetParent();
1047 #endif // wxUSE_ACCEL
1049 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1050 // will only be sent if it is not in an accelerator table.
1054 KeySym keysym
= gdk_event
->keyval
;
1055 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1056 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1059 if ( wxIsAsciiKeysym(keysym
) )
1062 key_code
= (unsigned char)keysym
;
1064 // gdk_event->string is actually deprecated
1065 else if ( gdk_event
->length
== 1 )
1067 key_code
= (unsigned char)gdk_event
->string
[0];
1073 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1075 event
.m_keyCode
= key_code
;
1077 // To conform to the docs we need to translate Ctrl-alpha
1078 // characters to values in the range 1-26.
1079 if ( event
.ControlDown() &&
1080 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
1082 if ( wxIsLowerChar(key_code
) )
1083 event
.m_keyCode
= key_code
- 'a' + 1;
1084 if ( wxIsUpperChar(key_code
) )
1085 event
.m_keyCode
= key_code
- 'A' + 1;
1087 event
.m_uniChar
= event
.m_keyCode
;
1091 // Implement OnCharHook by checking ancestor top level windows
1092 wxWindow
*parent
= win
;
1093 while (parent
&& !parent
->IsTopLevel())
1094 parent
= parent
->GetParent();
1097 event
.SetEventType( wxEVT_CHAR_HOOK
);
1098 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1103 event
.SetEventType(wxEVT_CHAR
);
1104 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1115 gtk_wxwindow_commit_cb (GtkIMContext
* WXUNUSED(context
),
1119 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1121 // take modifiers, cursor position, timestamp etc. from the last
1122 // key_press_event that was fed into Input Method:
1123 if (window
->m_imData
->lastKeyEvent
)
1125 wxFillOtherKeyEventFields(event
,
1126 window
, window
->m_imData
->lastKeyEvent
);
1130 event
.SetEventObject( window
);
1133 const wxString
data(wxGTK_CONV_BACK_SYS(str
));
1139 // Implement OnCharHook by checking ancestor top level windows
1140 wxWindow
*parent
= window
;
1141 while (parent
&& !parent
->IsTopLevel())
1142 parent
= parent
->GetParent();
1144 for( wxString::const_iterator pstr
= data
.begin(); pstr
!= data
.end(); ++pstr
)
1147 event
.m_uniChar
= *pstr
;
1148 // Backward compatible for ISO-8859-1
1149 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1150 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1152 event
.m_keyCode
= (char)*pstr
;
1153 #endif // wxUSE_UNICODE
1155 // To conform to the docs we need to translate Ctrl-alpha
1156 // characters to values in the range 1-26.
1157 if ( event
.ControlDown() &&
1158 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
1160 if ( wxIsLowerChar(*pstr
) )
1161 event
.m_keyCode
= *pstr
- 'a' + 1;
1162 if ( wxIsUpperChar(*pstr
) )
1163 event
.m_keyCode
= *pstr
- 'A' + 1;
1165 event
.m_keyCode
= *pstr
- 'a' + 1;
1167 event
.m_uniChar
= event
.m_keyCode
;
1173 event
.SetEventType( wxEVT_CHAR_HOOK
);
1174 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1179 event
.SetEventType(wxEVT_CHAR
);
1180 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1187 //-----------------------------------------------------------------------------
1188 // "key_release_event" from any window
1189 //-----------------------------------------------------------------------------
1193 gtk_window_key_release_callback( GtkWidget
* WXUNUSED(widget
),
1194 GdkEventKey
*gdk_event
,
1202 if (g_blockEventsOnDrag
)
1205 wxKeyEvent
event( wxEVT_KEY_UP
);
1206 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1208 // unknown key pressed, ignore (the event would be useless anyhow)
1212 return win
->GTKProcessEvent(event
);
1216 // ============================================================================
1218 // ============================================================================
1220 // ----------------------------------------------------------------------------
1221 // mouse event processing helpers
1222 // ----------------------------------------------------------------------------
1224 // init wxMouseEvent with the info from GdkEventXXX struct
1225 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1226 wxMouseEvent
& event
,
1229 event
.SetTimestamp( gdk_event
->time
);
1230 event
.m_shiftDown
= gdk_event
->state
& GDK_SHIFT_MASK
;
1231 event
.m_controlDown
= gdk_event
->state
& GDK_CONTROL_MASK
;
1232 event
.m_altDown
= gdk_event
->state
& GDK_MOD1_MASK
;
1233 event
.m_metaDown
= gdk_event
->state
& GDK_MOD2_MASK
;
1234 event
.m_leftDown
= gdk_event
->state
& GDK_BUTTON1_MASK
;
1235 event
.m_middleDown
= gdk_event
->state
& GDK_BUTTON2_MASK
;
1236 event
.m_rightDown
= gdk_event
->state
& GDK_BUTTON3_MASK
;
1237 event
.m_aux1Down
= gdk_event
->state
& GDK_BUTTON4_MASK
;
1238 event
.m_aux2Down
= gdk_event
->state
& GDK_BUTTON5_MASK
;
1240 wxPoint pt
= win
->GetClientAreaOrigin();
1241 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1242 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1244 if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
))
1246 // origin in the upper right corner
1247 int window_width
= gtk_pizza_get_rtl_offset( GTK_PIZZA(win
->m_wxwindow
) );
1248 event
.m_x
= window_width
- event
.m_x
;
1251 event
.SetEventObject( win
);
1252 event
.SetId( win
->GetId() );
1253 event
.SetTimestamp( gdk_event
->time
);
1256 static void AdjustEventButtonState(wxMouseEvent
& event
)
1258 // GDK reports the old state of the button for a button press event, but
1259 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1260 // for a LEFT_DOWN event, not FALSE, so we will invert
1261 // left/right/middleDown for the corresponding click events
1263 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1264 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1265 (event
.GetEventType() == wxEVT_LEFT_UP
))
1267 event
.m_leftDown
= !event
.m_leftDown
;
1271 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1272 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1273 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1275 event
.m_middleDown
= !event
.m_middleDown
;
1279 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1280 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1281 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1283 event
.m_rightDown
= !event
.m_rightDown
;
1288 // find the window to send the mouse event too
1290 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1295 if (win
->m_wxwindow
)
1297 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1298 xx
+= gtk_pizza_get_xoffset( pizza
);
1299 yy
+= gtk_pizza_get_yoffset( pizza
);
1302 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1305 wxWindowGTK
*child
= node
->GetData();
1307 node
= node
->GetNext();
1308 if (!child
->IsShown())
1311 if (child
->IsTransparentForMouse())
1313 // wxStaticBox is transparent in the box itself
1314 int xx1
= child
->m_x
;
1315 int yy1
= child
->m_y
;
1316 int xx2
= child
->m_x
+ child
->m_width
;
1317 int yy2
= child
->m_y
+ child
->m_height
;
1320 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1322 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1324 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1326 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1337 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1338 (child
->m_x
<= xx
) &&
1339 (child
->m_y
<= yy
) &&
1340 (child
->m_x
+child
->m_width
>= xx
) &&
1341 (child
->m_y
+child
->m_height
>= yy
))
1354 // ----------------------------------------------------------------------------
1355 // common event handlers helpers
1356 // ----------------------------------------------------------------------------
1358 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const
1360 // nothing special at this level
1361 return GetEventHandler()->ProcessEvent(event
);
1364 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1370 if (g_blockEventsOnDrag
)
1372 if (g_blockEventsOnScroll
)
1375 if (!GTKIsOwnWindow(event
->window
))
1381 // overloads for all GDK event types we use here: we need to have this as
1382 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1383 // derives from it in the sense that the structs have the same layout
1384 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1385 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1387 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1390 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1391 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1392 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1394 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1396 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1397 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1401 // send the wxChildFocusEvent and wxFocusEvent, common code of
1402 // gtk_window_focus_in_callback() and SetFocus()
1403 static bool DoSendFocusEvents(wxWindow
*win
)
1405 // Notify the parent keeping track of focus for the kbd navigation
1406 // purposes that we got it.
1407 wxChildFocusEvent
eventChildFocus(win
);
1408 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1410 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1411 eventFocus
.SetEventObject(win
);
1413 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1416 // all event handlers must have C linkage as they're called from GTK+ C code
1420 //-----------------------------------------------------------------------------
1421 // "button_press_event"
1422 //-----------------------------------------------------------------------------
1425 gtk_window_button_press_callback( GtkWidget
*widget
,
1426 GdkEventButton
*gdk_event
,
1429 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1431 g_lastButtonNumber
= gdk_event
->button
;
1433 // GDK sends surplus button down events
1434 // before a double click event. We
1435 // need to filter these out.
1436 if ((gdk_event
->type
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
))
1438 GdkEvent
*peek_event
= gdk_event_peek();
1441 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1442 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1444 gdk_event_free( peek_event
);
1449 gdk_event_free( peek_event
);
1454 wxEventType event_type
= wxEVT_NULL
;
1456 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1457 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1459 // Reset GDK internal timestamp variables in order to disable GDK
1460 // triple click events. GDK will then next time believe no button has
1461 // been clicked just before, and send a normal button click event.
1462 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1463 display
->button_click_time
[1] = 0;
1464 display
->button_click_time
[0] = 0;
1467 if (gdk_event
->button
== 1)
1469 // note that GDK generates triple click events which are not supported
1470 // by wxWidgets but still have to be passed to the app as otherwise
1471 // clicks would simply go missing
1472 switch (gdk_event
->type
)
1474 // we shouldn't get triple clicks at all for GTK2 because we
1475 // suppress them artificially using the code above but we still
1476 // should map them to something for GTK1 and not just ignore them
1477 // as this would lose clicks
1478 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1479 case GDK_BUTTON_PRESS
:
1480 event_type
= wxEVT_LEFT_DOWN
;
1483 case GDK_2BUTTON_PRESS
:
1484 event_type
= wxEVT_LEFT_DCLICK
;
1488 // just to silence gcc warnings
1492 else if (gdk_event
->button
== 2)
1494 switch (gdk_event
->type
)
1496 case GDK_3BUTTON_PRESS
:
1497 case GDK_BUTTON_PRESS
:
1498 event_type
= wxEVT_MIDDLE_DOWN
;
1501 case GDK_2BUTTON_PRESS
:
1502 event_type
= wxEVT_MIDDLE_DCLICK
;
1509 else if (gdk_event
->button
== 3)
1511 switch (gdk_event
->type
)
1513 case GDK_3BUTTON_PRESS
:
1514 case GDK_BUTTON_PRESS
:
1515 event_type
= wxEVT_RIGHT_DOWN
;
1518 case GDK_2BUTTON_PRESS
:
1519 event_type
= wxEVT_RIGHT_DCLICK
;
1527 if ( event_type
== wxEVT_NULL
)
1529 // unknown mouse button or click type
1533 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1535 wxMouseEvent
event( event_type
);
1536 InitMouseEvent( win
, event
, gdk_event
);
1538 AdjustEventButtonState(event
);
1540 // wxListBox actually gets mouse events from the item, so we need to give it
1541 // a chance to correct this
1542 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1544 // find the correct window to send the event to: it may be a different one
1545 // from the one which got it at GTK+ level because some controls don't have
1546 // their own X window and thus cannot get any events.
1547 if ( !g_captureWindow
)
1548 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1550 // reset the event object and id in case win changed.
1551 event
.SetEventObject( win
);
1552 event
.SetId( win
->GetId() );
1554 bool ret
= win
->GTKProcessEvent( event
);
1555 g_lastMouseEvent
= NULL
;
1559 if ((event_type
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&
1560 (g_focusWindow
!= win
) /* && win->IsFocusable() */)
1565 if (event_type
== wxEVT_RIGHT_DOWN
)
1567 // generate a "context menu" event: this is similar to right mouse
1568 // click under many GUIs except that it is generated differently
1569 // (right up under MSW, ctrl-click under Mac, right down here) and
1571 // (a) it's a command event and so is propagated to the parent
1572 // (b) under some ports it can be generated from kbd too
1573 // (c) it uses screen coords (because of (a))
1574 wxContextMenuEvent
evtCtx(
1577 win
->ClientToScreen(event
.GetPosition()));
1578 evtCtx
.SetEventObject(win
);
1579 return win
->GTKProcessEvent(evtCtx
);
1585 //-----------------------------------------------------------------------------
1586 // "button_release_event"
1587 //-----------------------------------------------------------------------------
1590 gtk_window_button_release_callback( GtkWidget
*widget
,
1591 GdkEventButton
*gdk_event
,
1594 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1596 g_lastButtonNumber
= 0;
1598 wxEventType event_type
= wxEVT_NULL
;
1600 switch (gdk_event
->button
)
1603 event_type
= wxEVT_LEFT_UP
;
1607 event_type
= wxEVT_MIDDLE_UP
;
1611 event_type
= wxEVT_RIGHT_UP
;
1615 // unknown button, don't process
1619 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1621 wxMouseEvent
event( event_type
);
1622 InitMouseEvent( win
, event
, gdk_event
);
1624 AdjustEventButtonState(event
);
1626 // same wxListBox hack as above
1627 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1629 if ( !g_captureWindow
)
1630 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1632 // reset the event object and id in case win changed.
1633 event
.SetEventObject( win
);
1634 event
.SetId( win
->GetId() );
1636 bool ret
= win
->GTKProcessEvent(event
);
1638 g_lastMouseEvent
= NULL
;
1643 //-----------------------------------------------------------------------------
1644 // "motion_notify_event"
1645 //-----------------------------------------------------------------------------
1648 gtk_window_motion_notify_callback( GtkWidget
* WXUNUSED(widget
),
1649 GdkEventMotion
*gdk_event
,
1652 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1654 if (gdk_event
->is_hint
)
1658 GdkModifierType state
;
1659 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1664 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1666 wxMouseEvent
event( wxEVT_MOTION
);
1667 InitMouseEvent(win
, event
, gdk_event
);
1669 if ( g_captureWindow
)
1671 // synthesise a mouse enter or leave event if needed
1672 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1673 // This seems to be necessary and actually been added to
1674 // GDK itself in version 2.0.X
1677 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1678 if ( hasMouse
!= g_captureWindowHasMouse
)
1680 // the mouse changed window
1681 g_captureWindowHasMouse
= hasMouse
;
1683 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1684 : wxEVT_LEAVE_WINDOW
);
1685 InitMouseEvent(win
, eventM
, gdk_event
);
1686 eventM
.SetEventObject(win
);
1687 win
->GTKProcessEvent(eventM
);
1692 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1694 // reset the event object and id in case win changed.
1695 event
.SetEventObject( win
);
1696 event
.SetId( win
->GetId() );
1699 if ( !g_captureWindow
)
1701 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1702 if (win
->GTKProcessEvent( cevent
))
1704 win
->SetCursor( cevent
.GetCursor() );
1708 bool ret
= win
->GTKProcessEvent(event
);
1710 g_lastMouseEvent
= NULL
;
1715 //-----------------------------------------------------------------------------
1716 // "scroll_event" (mouse wheel event)
1717 //-----------------------------------------------------------------------------
1720 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1724 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1725 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1730 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1731 InitMouseEvent(win
, event
, gdk_event
);
1732 event
.m_linesPerAction
= 3;
1733 event
.m_wheelDelta
= 120;
1734 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1735 event
.m_wheelRotation
= 120;
1737 event
.m_wheelRotation
= -120;
1739 return win
->GTKProcessEvent(event
);
1742 //-----------------------------------------------------------------------------
1744 //-----------------------------------------------------------------------------
1746 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1748 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1749 event
.SetEventObject(win
);
1750 return win
->GTKProcessEvent(event
);
1753 //-----------------------------------------------------------------------------
1755 //-----------------------------------------------------------------------------
1758 gtk_window_focus_in_callback( GtkWidget
* WXUNUSED(widget
),
1759 GdkEventFocus
*WXUNUSED(event
),
1765 gtk_im_context_focus_in(win
->m_imData
->context
);
1768 g_focusWindow
= win
;
1770 wxLogTrace(TRACE_FOCUS
,
1771 _T("%s: focus in"), win
->GetName().c_str());
1774 // caret needs to be informed about focus change
1775 wxCaret
*caret
= win
->GetCaret();
1778 caret
->OnSetFocus();
1780 #endif // wxUSE_CARET
1782 gboolean ret
= FALSE
;
1784 // does the window itself think that it has the focus?
1785 if ( !win
->m_hasFocus
)
1787 // not yet, notify it
1788 win
->m_hasFocus
= true;
1790 (void)DoSendFocusEvents(win
);
1795 // Disable default focus handling for custom windows
1796 // since the default GTK+ handler issues a repaint
1797 if (win
->m_wxwindow
)
1803 //-----------------------------------------------------------------------------
1804 // "focus_out_event"
1805 //-----------------------------------------------------------------------------
1808 gtk_window_focus_out_callback( GtkWidget
* WXUNUSED(widget
),
1809 GdkEventFocus
* WXUNUSED(gdk_event
),
1815 gtk_im_context_focus_out(win
->m_imData
->context
);
1817 wxLogTrace( TRACE_FOCUS
,
1818 _T("%s: focus out"), win
->GetName().c_str() );
1821 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1825 g_focusWindow
= (wxWindowGTK
*)NULL
;
1828 // caret needs to be informed about focus change
1829 wxCaret
*caret
= win
->GetCaret();
1832 caret
->OnKillFocus();
1834 #endif // wxUSE_CARET
1836 // don't send the window a kill focus event if it thinks that it doesn't
1837 // have focus already
1838 if ( win
->m_hasFocus
)
1840 // the event handler might delete the window when it loses focus, so
1841 // check whether this is a custom window before calling it
1842 const bool has_wxwindow
= win
->m_wxwindow
!= NULL
;
1844 win
->m_hasFocus
= false;
1846 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1847 event
.SetEventObject( win
);
1849 (void)win
->GTKProcessEvent( event
);
1851 // Disable default focus handling for custom windows
1852 // since the default GTK+ handler issues a repaint
1857 // continue with normal processing
1862 wx_window_focus_callback(GtkWidget
*widget
,
1863 GtkDirectionType
WXUNUSED(direction
),
1866 // the default handler for focus signal in GtkPizza (or, rather, in
1867 // GtkScrolledWindow from which GtkPizza inherits this behaviour) sets
1868 // focus to the window itself even if it doesn't accept focus, i.e. has no
1869 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1870 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1871 // any children which might accept focus (we know we don't accept the focus
1872 // ourselves as this signal is only connected in this case)
1873 if ( win
->GetChildren().empty() )
1874 g_signal_stop_emission_by_name(widget
, "focus");
1876 // we didn't change the focus
1880 //-----------------------------------------------------------------------------
1881 // "enter_notify_event"
1882 //-----------------------------------------------------------------------------
1885 gtk_window_enter_callback( GtkWidget
*widget
,
1886 GdkEventCrossing
*gdk_event
,
1889 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1891 // Event was emitted after a grab
1892 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1896 GdkModifierType state
= (GdkModifierType
)0;
1898 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1900 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1901 InitMouseEvent(win
, event
, gdk_event
);
1902 wxPoint pt
= win
->GetClientAreaOrigin();
1903 event
.m_x
= x
+ pt
.x
;
1904 event
.m_y
= y
+ pt
.y
;
1906 if ( !g_captureWindow
)
1908 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1909 if (win
->GTKProcessEvent( cevent
))
1911 win
->SetCursor( cevent
.GetCursor() );
1915 return win
->GTKProcessEvent(event
);
1918 //-----------------------------------------------------------------------------
1919 // "leave_notify_event"
1920 //-----------------------------------------------------------------------------
1923 gtk_window_leave_callback( GtkWidget
*widget
,
1924 GdkEventCrossing
*gdk_event
,
1927 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1929 // Event was emitted after an ungrab
1930 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1932 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1936 GdkModifierType state
= (GdkModifierType
)0;
1938 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1940 InitMouseEvent(win
, event
, gdk_event
);
1942 return win
->GTKProcessEvent(event
);
1945 //-----------------------------------------------------------------------------
1946 // "value_changed" from scrollbar
1947 //-----------------------------------------------------------------------------
1950 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
1952 wxEventType eventType
= win
->GetScrollEventType(range
);
1953 if (eventType
!= wxEVT_NULL
)
1955 // Convert scroll event type to scrollwin event type
1956 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
1958 // find the scrollbar which generated the event
1959 wxWindowGTK::ScrollDir dir
= win
->ScrollDirFromRange(range
);
1961 // generate the corresponding wx event
1962 const int orient
= wxWindow::OrientFromScrollDir(dir
);
1963 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
1964 event
.SetEventObject(win
);
1966 win
->GTKProcessEvent(event
);
1970 //-----------------------------------------------------------------------------
1971 // "button_press_event" from scrollbar
1972 //-----------------------------------------------------------------------------
1975 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
1979 g_blockEventsOnScroll
= true;
1980 win
->m_mouseButtonDown
= true;
1985 //-----------------------------------------------------------------------------
1986 // "event_after" from scrollbar
1987 //-----------------------------------------------------------------------------
1990 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
1992 if (event
->type
== GDK_BUTTON_RELEASE
)
1994 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1996 const int orient
= wxWindow::OrientFromScrollDir(
1997 win
->ScrollDirFromRange(range
));
1998 wxScrollWinEvent
evt(wxEVT_SCROLLWIN_THUMBRELEASE
,
1999 win
->GetScrollPos(orient
), orient
);
2000 evt
.SetEventObject(win
);
2001 win
->GTKProcessEvent(evt
);
2005 //-----------------------------------------------------------------------------
2006 // "button_release_event" from scrollbar
2007 //-----------------------------------------------------------------------------
2010 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
2014 g_blockEventsOnScroll
= false;
2015 win
->m_mouseButtonDown
= false;
2016 // If thumb tracking
2017 if (win
->m_isScrolling
)
2019 win
->m_isScrolling
= false;
2020 // Hook up handler to send thumb release event after this emission is finished.
2021 // To allow setting scroll position from event handler, sending event must
2022 // be deferred until after the GtkRange handler for this signal has run
2023 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
2029 //-----------------------------------------------------------------------------
2030 // "realize" from m_widget
2031 //-----------------------------------------------------------------------------
2034 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2040 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2041 gtk_im_context_set_client_window( win
->m_imData
->context
,
2042 pizza
->bin_window
);
2045 // We cannot set colours and fonts before the widget
2046 // been realized, so we do this directly after realization
2047 // or otherwise in idle time
2049 if (win
->m_needsStyleChange
)
2051 win
->SetBackgroundStyle(win
->GetBackgroundStyle());
2052 win
->m_needsStyleChange
= false;
2055 wxWindowCreateEvent
event( win
);
2056 event
.SetEventObject( win
);
2057 win
->GTKProcessEvent( event
);
2060 //-----------------------------------------------------------------------------
2061 // "size_allocate" from m_wxwindow or m_widget
2062 //-----------------------------------------------------------------------------
2065 size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxWindow
* win
)
2067 int w
= alloc
->width
;
2068 int h
= alloc
->height
;
2069 if (win
->m_wxwindow
)
2071 const int border
= GTK_CONTAINER(win
->m_wxwindow
)->border_width
;
2077 if (win
->m_oldClientWidth
!= w
|| win
->m_oldClientHeight
!= h
)
2079 win
->m_oldClientWidth
= w
;
2080 win
->m_oldClientHeight
= h
;
2081 // this callback can be connected to m_wxwindow,
2082 // so always get size from m_widget->allocation
2083 win
->m_width
= win
->m_widget
->allocation
.width
;
2084 win
->m_height
= win
->m_widget
->allocation
.height
;
2085 if (!win
->m_nativeSizeEvent
)
2087 wxSizeEvent
event(win
->GetSize(), win
->GetId());
2088 event
.SetEventObject(win
);
2089 win
->GTKProcessEvent(event
);
2094 //-----------------------------------------------------------------------------
2096 //-----------------------------------------------------------------------------
2098 #if GTK_CHECK_VERSION(2, 8, 0)
2100 gtk_window_grab_broken( GtkWidget
*,
2101 GdkEventGrabBroken
*event
,
2104 // Mouse capture has been lost involuntarily, notify the application
2105 if(!event
->keyboard
&& wxWindow::GetCapture() == win
)
2107 wxMouseCaptureLostEvent
evt( win
->GetId() );
2108 evt
.SetEventObject( win
);
2109 win
->GetEventHandler()->ProcessEvent( evt
);
2115 //-----------------------------------------------------------------------------
2117 //-----------------------------------------------------------------------------
2120 void gtk_window_style_set_callback( GtkWidget
*WXUNUSED(widget
),
2121 GtkStyle
*previous_style
,
2124 //wxLogDebug(wxT("gtk_window_style_set_callback"));
2125 if (win
&& previous_style
)
2127 wxString
name(win
->GetName());
2128 //wxLogDebug(wxT("gtk_window_style_set_callback %s"), name.c_str());
2129 wxSysColourChangedEvent event
;
2130 event
.SetEventObject(win
);
2132 win
->GTKProcessEvent( event
);
2138 // Connect/disconnect style-set
2140 void wxConnectStyleSet(wxWindow
* win
)
2142 if (win
->m_wxwindow
)
2143 g_signal_connect (win
->m_wxwindow
, "style_set",
2144 G_CALLBACK (gtk_window_style_set_callback
), win
);
2147 void wxDisconnectStyleSet(wxWindow
* win
)
2149 if (win
->m_wxwindow
)
2150 g_signal_handlers_disconnect_by_func (win
->m_wxwindow
,
2151 (gpointer
) gtk_window_style_set_callback
,
2155 // Helper to suspend colour change event event processing while we change a widget's style
2156 class wxSuspendStyleEvents
2159 wxSuspendStyleEvents(wxWindow
* win
)
2162 if (win
->IsTopLevel())
2163 wxDisconnectStyleSet(win
);
2165 ~wxSuspendStyleEvents()
2167 if (m_win
->IsTopLevel())
2168 wxConnectStyleSet(m_win
);
2174 // ----------------------------------------------------------------------------
2175 // this wxWindowBase function is implemented here (in platform-specific file)
2176 // because it is static and so couldn't be made virtual
2177 // ----------------------------------------------------------------------------
2179 wxWindow
*wxWindowBase::DoFindFocus()
2181 // the cast is necessary when we compile in wxUniversal mode
2182 return (wxWindow
*)g_focusWindow
;
2185 //-----------------------------------------------------------------------------
2186 // InsertChild for wxWindowGTK.
2187 //-----------------------------------------------------------------------------
2189 /* Callback for wxWindowGTK. This very strange beast has to be used because
2190 * C++ has no virtual methods in a constructor. We have to emulate a
2191 * virtual function here as wxNotebook requires a different way to insert
2192 * a child in it. I had opted for creating a wxNotebookPage window class
2193 * which would have made this superfluous (such in the MDI window system),
2194 * but no-one was listening to me... */
2196 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2198 /* the window might have been scrolled already, do we
2199 have to adapt the position */
2200 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2201 child
->m_x
+= gtk_pizza_get_xoffset( pizza
);
2202 child
->m_y
+= gtk_pizza_get_yoffset( pizza
);
2204 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2212 //-----------------------------------------------------------------------------
2214 //-----------------------------------------------------------------------------
2216 wxWindow
*wxGetActiveWindow()
2218 return wxWindow::FindFocus();
2222 wxMouseState
wxGetMouseState()
2228 GdkModifierType mask
;
2230 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2234 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2235 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2236 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2237 ms
.SetAux1Down(mask
& GDK_BUTTON4_MASK
);
2238 ms
.SetAux2Down(mask
& GDK_BUTTON5_MASK
);
2240 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2241 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2242 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2243 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2248 //-----------------------------------------------------------------------------
2250 //-----------------------------------------------------------------------------
2252 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2254 #ifdef __WXUNIVERSAL__
2255 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2257 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2258 #endif // __WXUNIVERSAL__/__WXGTK__
2260 void wxWindowGTK::Init()
2263 m_widget
= (GtkWidget
*) NULL
;
2264 m_wxwindow
= (GtkWidget
*) NULL
;
2265 m_focusWidget
= (GtkWidget
*) NULL
;
2274 m_isBeingDeleted
= false;
2276 m_showOnIdle
= false;
2279 m_nativeSizeEvent
= false;
2281 m_hasScrolling
= false;
2282 m_isScrolling
= false;
2283 m_mouseButtonDown
= false;
2285 // initialize scrolling stuff
2286 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2288 m_scrollBar
[dir
] = NULL
;
2289 m_scrollPos
[dir
] = 0;
2293 m_oldClientHeight
= 0;
2295 m_insertCallback
= wxInsertChildInWindow
;
2299 m_clipPaintRegion
= false;
2301 m_needsStyleChange
= false;
2303 m_cursor
= *wxSTANDARD_CURSOR
;
2306 m_dirtyTabOrder
= false;
2309 wxWindowGTK::wxWindowGTK()
2314 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2319 const wxString
&name
)
2323 Create( parent
, id
, pos
, size
, style
, name
);
2326 bool wxWindowGTK::Create( wxWindow
*parent
,
2331 const wxString
&name
)
2333 if (!PreCreation( parent
, pos
, size
) ||
2334 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2336 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2340 if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
))
2342 m_wxwindow
= gtk_pizza_new_no_scroll();
2344 #ifndef __WXUNIVERSAL__
2345 if (HasFlag(wxSIMPLE_BORDER
))
2346 gtk_container_set_border_width((GtkContainer
*)m_wxwindow
, 1);
2347 else if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2348 gtk_container_set_border_width((GtkContainer
*)m_wxwindow
, 2);
2349 #endif // __WXUNIVERSAL__
2351 m_widget
= m_wxwindow
;
2355 m_wxwindow
= gtk_pizza_new();
2357 #ifndef __WXUNIVERSAL__
2358 if (HasFlag(wxSIMPLE_BORDER
))
2359 gtk_container_set_border_width((GtkContainer
*)m_wxwindow
, 1);
2360 else if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2361 gtk_container_set_border_width((GtkContainer
*)m_wxwindow
, 2);
2362 #endif // __WXUNIVERSAL__
2364 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2366 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2368 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2369 scroll_class
->scrollbar_spacing
= 0;
2371 // There is a conflict with default bindings at GTK+
2372 // level between scrolled windows and notebooks both of which want to use
2373 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2374 // direction and notebooks for changing pages -- we decide that if we don't
2375 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2376 // means we can get working keyboard navigation in notebooks
2377 if ( !HasFlag(wxHSCROLL
) )
2380 bindings
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
));
2383 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
);
2384 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
);
2388 if (HasFlag(wxALWAYS_SHOW_SB
))
2390 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
2392 scrolledWindow
->hscrollbar_visible
= TRUE
;
2393 scrolledWindow
->vscrollbar_visible
= TRUE
;
2397 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2400 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2401 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2402 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2403 gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE
);
2405 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2407 // connect various scroll-related events
2408 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2410 // these handlers block mouse events to any window during scrolling
2411 // such as motion events and prevent GTK and wxWidgets from fighting
2412 // over where the slider should be
2413 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2414 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2415 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2416 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2418 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2419 G_CALLBACK(gtk_scrollbar_event_after
), this);
2420 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2422 // these handlers get notified when scrollbar slider moves
2423 g_signal_connect_after(m_scrollBar
[dir
], "value_changed",
2424 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2427 gtk_widget_show( m_wxwindow
);
2431 m_parent
->DoAddChild( this );
2433 m_focusWidget
= m_wxwindow
;
2440 wxWindowGTK::~wxWindowGTK()
2444 if (g_focusWindow
== this)
2445 g_focusWindow
= NULL
;
2447 if ( g_delayedFocus
== this )
2448 g_delayedFocus
= NULL
;
2450 m_isBeingDeleted
= true;
2453 // destroy children before destroying this window itself
2456 // unhook focus handlers to prevent stray events being
2457 // propagated to this (soon to be) dead object
2458 if (m_focusWidget
!= NULL
)
2460 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2461 (gpointer
) gtk_window_focus_in_callback
,
2463 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2464 (gpointer
) gtk_window_focus_out_callback
,
2471 // delete before the widgets to avoid a crash on solaris
2474 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2476 gtk_widget_destroy( m_wxwindow
);
2477 m_wxwindow
= (GtkWidget
*) NULL
;
2482 gtk_widget_destroy( m_widget
);
2483 m_widget
= (GtkWidget
*) NULL
;
2487 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2489 if ( GTKNeedsParent() )
2491 wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") );
2494 // Use either the given size, or the default if -1 is given.
2495 // See wxWindowBase for these functions.
2496 m_width
= WidthDefault(size
.x
) ;
2497 m_height
= HeightDefault(size
.y
);
2505 void wxWindowGTK::PostCreation()
2507 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2513 // these get reported to wxWidgets -> wxPaintEvent
2515 g_signal_connect (m_wxwindow
, "expose_event",
2516 G_CALLBACK (gtk_window_expose_callback
), this);
2518 if (GetLayoutDirection() == wxLayout_LeftToRight
)
2519 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2522 // Create input method handler
2523 m_imData
= new wxGtkIMData
;
2525 // Cannot handle drawing preedited text yet
2526 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2528 g_signal_connect (m_imData
->context
, "commit",
2529 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2531 // these are called when the "sunken" or "raised" borders are drawn
2532 g_signal_connect (m_widget
, "expose_event",
2533 G_CALLBACK (gtk_window_own_expose_callback
), this);
2538 if (!GTK_IS_WINDOW(m_widget
))
2540 if (m_focusWidget
== NULL
)
2541 m_focusWidget
= m_widget
;
2545 g_signal_connect (m_focusWidget
, "focus_in_event",
2546 G_CALLBACK (gtk_window_focus_in_callback
), this);
2547 g_signal_connect (m_focusWidget
, "focus_out_event",
2548 G_CALLBACK (gtk_window_focus_out_callback
), this);
2552 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2553 G_CALLBACK (gtk_window_focus_in_callback
), this);
2554 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2555 G_CALLBACK (gtk_window_focus_out_callback
), this);
2559 if ( !AcceptsFocusFromKeyboard() )
2563 g_signal_connect(m_widget
, "focus",
2564 G_CALLBACK(wx_window_focus_callback
), this);
2567 // connect to the various key and mouse handlers
2569 GtkWidget
*connect_widget
= GetConnectWidget();
2571 ConnectWidget( connect_widget
);
2573 /* We cannot set colours, fonts and cursors before the widget has
2574 been realized, so we do this directly after realization */
2575 g_signal_connect (connect_widget
, "realize",
2576 G_CALLBACK (gtk_window_realized_callback
), this);
2580 g_signal_connect(m_wxwindow
? m_wxwindow
: m_widget
, "size_allocate",
2581 G_CALLBACK(size_allocate
), this);
2586 #if GTK_CHECK_VERSION(2, 8, 0)
2587 if (!gtk_check_version(2,8,0))
2589 // Make sure we can notify the app when mouse capture is lost
2590 g_signal_connect (m_wxwindow
, "grab_broken_event",
2591 G_CALLBACK (gtk_window_grab_broken
), this);
2596 if ( connect_widget
!= m_wxwindow
)
2598 #if GTK_CHECK_VERSION(2, 8, 0)
2599 if (!gtk_check_version(2,8,0))
2601 // Make sure we can notify app code when mouse capture is lost
2602 g_signal_connect (connect_widget
, "grab_broken_event",
2603 G_CALLBACK (gtk_window_grab_broken
), this);
2609 if (GTK_IS_COMBO(m_widget
))
2611 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2613 g_signal_connect (gcombo
->entry
, "size_request",
2614 G_CALLBACK (wxgtk_combo_size_request_callback
),
2617 #endif // wxUSE_COMBOBOX
2618 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2619 if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2621 // If we connect to the "size_request" signal of a GtkFileChooserButton
2622 // then that control won't be sized properly when placed inside sizers
2623 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2624 // FIXME: what should be done here ?
2627 if ( !IsTopLevel() ) // top level windows use their own callback
2629 // This is needed if we want to add our windows into native
2630 // GTK controls, such as the toolbar. With this callback, the
2631 // toolbar gets to know the correct size (the one set by the
2632 // programmer). Sadly, it misbehaves for wxComboBox.
2633 g_signal_connect (m_widget
, "size_request",
2634 G_CALLBACK (wxgtk_window_size_request_callback
),
2638 InheritAttributes();
2642 SetLayoutDirection(wxLayout_Default
);
2644 // unless the window was created initially hidden (i.e. Hide() had been
2645 // called before Create()), we should show it at GTK+ level as well
2647 gtk_widget_show( m_widget
);
2650 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2652 g_signal_connect (widget
, "key_press_event",
2653 G_CALLBACK (gtk_window_key_press_callback
), this);
2654 g_signal_connect (widget
, "key_release_event",
2655 G_CALLBACK (gtk_window_key_release_callback
), this);
2656 g_signal_connect (widget
, "button_press_event",
2657 G_CALLBACK (gtk_window_button_press_callback
), this);
2658 g_signal_connect (widget
, "button_release_event",
2659 G_CALLBACK (gtk_window_button_release_callback
), this);
2660 g_signal_connect (widget
, "motion_notify_event",
2661 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2662 g_signal_connect (widget
, "scroll_event",
2663 G_CALLBACK (window_scroll_event
), this);
2664 g_signal_connect (widget
, "popup_menu",
2665 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2666 g_signal_connect (widget
, "enter_notify_event",
2667 G_CALLBACK (gtk_window_enter_callback
), this);
2668 g_signal_connect (widget
, "leave_notify_event",
2669 G_CALLBACK (gtk_window_leave_callback
), this);
2671 if (IsTopLevel() && m_wxwindow
)
2672 g_signal_connect (m_wxwindow
, "style_set",
2673 G_CALLBACK (gtk_window_style_set_callback
), this);
2676 bool wxWindowGTK::Destroy()
2678 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2682 return wxWindowBase::Destroy();
2685 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2687 // inform the parent to perform the move
2688 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2692 void wxWindowGTK::ConstrainSize()
2695 // GPE's window manager doesn't like size hints at all, esp. when the user
2696 // has to use the virtual keyboard, so don't constrain size there
2700 const wxSize minSize
= GetMinSize();
2701 const wxSize maxSize
= GetMaxSize();
2702 if (minSize
.x
> 0 && m_width
< minSize
.x
) m_width
= minSize
.x
;
2703 if (minSize
.y
> 0 && m_height
< minSize
.y
) m_height
= minSize
.y
;
2704 if (maxSize
.x
> 0 && m_width
> maxSize
.x
) m_width
= maxSize
.x
;
2705 if (maxSize
.y
> 0 && m_height
> maxSize
.y
) m_height
= maxSize
.y
;
2709 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2711 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2712 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2714 int currentX
, currentY
;
2715 GetPosition(¤tX
, ¤tY
);
2716 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2718 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2720 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2722 // calculate the best size if we should auto size the window
2723 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2724 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2726 const wxSize sizeBest
= GetBestSize();
2727 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2729 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2730 height
= sizeBest
.y
;
2733 const wxSize
oldSize(m_width
, m_height
);
2741 if (m_parent
->m_wxwindow
)
2743 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2744 m_x
= x
+ gtk_pizza_get_xoffset(pizza
);
2745 m_y
= y
+ gtk_pizza_get_yoffset(pizza
);
2747 int left_border
= 0;
2748 int right_border
= 0;
2750 int bottom_border
= 0;
2752 /* the default button has a border around it */
2753 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2755 GtkBorder
*default_border
= NULL
;
2756 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2759 left_border
+= default_border
->left
;
2760 right_border
+= default_border
->right
;
2761 top_border
+= default_border
->top
;
2762 bottom_border
+= default_border
->bottom
;
2763 gtk_border_free( default_border
);
2767 DoMoveWindow( m_x
- left_border
,
2769 m_width
+left_border
+right_border
,
2770 m_height
+top_border
+bottom_border
);
2773 if (m_width
!= oldSize
.x
|| m_height
!= oldSize
.y
)
2775 // update these variables to keep size_allocate handler
2776 // from sending another size event for this change
2777 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2779 gtk_widget_queue_resize(m_widget
);
2780 if (!m_nativeSizeEvent
)
2782 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2783 event
.SetEventObject( this );
2784 GetEventHandler()->ProcessEvent( event
);
2789 bool wxWindowGTK::GtkShowFromOnIdle()
2791 if (IsShown() && m_showOnIdle
&& !GTK_WIDGET_VISIBLE (m_widget
))
2793 GtkAllocation alloc
;
2796 alloc
.width
= m_width
;
2797 alloc
.height
= m_height
;
2798 gtk_widget_size_allocate( m_widget
, &alloc
);
2799 gtk_widget_show( m_widget
);
2800 wxShowEvent
eventShow(GetId(), true);
2801 eventShow
.SetEventObject(this);
2802 GetEventHandler()->ProcessEvent(eventShow
);
2803 m_showOnIdle
= false;
2810 void wxWindowGTK::OnInternalIdle()
2812 // Check if we have to show window now
2813 if (GtkShowFromOnIdle()) return;
2815 if ( m_dirtyTabOrder
)
2817 m_dirtyTabOrder
= false;
2821 // Update style if the window was not yet realized
2822 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2823 if (m_needsStyleChange
)
2825 SetBackgroundStyle(GetBackgroundStyle());
2826 m_needsStyleChange
= false;
2829 wxCursor cursor
= m_cursor
;
2830 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2834 /* I now set the cursor anew in every OnInternalIdle call
2835 as setting the cursor in a parent window also effects the
2836 windows above so that checking for the current cursor is
2839 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2841 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2843 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2845 if (!g_globalCursor
.Ok())
2846 cursor
= *wxSTANDARD_CURSOR
;
2848 window
= m_widget
->window
;
2849 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2850 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2853 else if ( m_widget
)
2855 GdkWindow
*window
= m_widget
->window
;
2856 if ( window
&& !GTK_WIDGET_NO_WINDOW(m_widget
) )
2857 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2861 if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
2862 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2865 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2867 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2869 if (width
) (*width
) = m_width
;
2870 if (height
) (*height
) = m_height
;
2873 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2875 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2877 const wxSize size
= GetSize();
2878 const wxSize clientSize
= GetClientSize();
2879 SetSize(width
+ (size
.x
- clientSize
.x
), height
+ (size
.y
- clientSize
.y
));
2882 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2884 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2895 GetScrollbarWidth(m_widget
, dw
, dh
);
2897 const int border
= GTK_CONTAINER(m_wxwindow
)->border_width
;
2909 if (width
) *width
= w
;
2910 if (height
) *height
= h
;
2913 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2915 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2919 if (!IsTopLevel() && m_parent
&& m_parent
->m_wxwindow
)
2921 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2922 dx
= gtk_pizza_get_xoffset( pizza
);
2923 dy
= gtk_pizza_get_yoffset( pizza
);
2926 if (m_x
== -1 && m_y
== -1)
2928 GdkWindow
*source
= (GdkWindow
*) NULL
;
2930 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2932 source
= m_widget
->window
;
2938 gdk_window_get_origin( source
, &org_x
, &org_y
);
2941 m_parent
->ScreenToClient(&org_x
, &org_y
);
2943 wx_const_cast(wxWindowGTK
*, this)->m_x
= org_x
;
2944 wx_const_cast(wxWindowGTK
*, this)->m_y
= org_y
;
2948 if (x
) (*x
) = m_x
- dx
;
2949 if (y
) (*y
) = m_y
- dy
;
2952 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2954 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2956 if (!m_widget
->window
) return;
2958 GdkWindow
*source
= (GdkWindow
*) NULL
;
2960 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2962 source
= m_widget
->window
;
2966 gdk_window_get_origin( source
, &org_x
, &org_y
);
2970 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2972 org_x
+= m_widget
->allocation
.x
;
2973 org_y
+= m_widget
->allocation
.y
;
2980 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2981 *x
= (GetClientSize().x
- *x
) + org_x
;
2989 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
2991 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2993 if (!m_widget
->window
) return;
2995 GdkWindow
*source
= (GdkWindow
*) NULL
;
2997 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2999 source
= m_widget
->window
;
3003 gdk_window_get_origin( source
, &org_x
, &org_y
);
3007 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3009 org_x
+= m_widget
->allocation
.x
;
3010 org_y
+= m_widget
->allocation
.y
;
3016 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3017 *x
= (GetClientSize().x
- *x
) - org_x
;
3024 bool wxWindowGTK::Show( bool show
)
3026 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3028 if (!wxWindowBase::Show(show
))
3038 gtk_widget_show( m_widget
);
3039 wxShowEvent
eventShow(GetId(), show
);
3040 eventShow
.SetEventObject(this);
3041 GetEventHandler()->ProcessEvent(eventShow
);
3046 gtk_widget_hide( m_widget
);
3047 wxShowEvent
eventShow(GetId(), show
);
3048 eventShow
.SetEventObject(this);
3049 GetEventHandler()->ProcessEvent(eventShow
);
3055 void wxWindowGTK::DoEnable( bool enable
)
3057 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3059 gtk_widget_set_sensitive( m_widget
, enable
);
3060 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3061 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3064 int wxWindowGTK::GetCharHeight() const
3066 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3068 wxFont font
= GetFont();
3069 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3071 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
3076 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3077 PangoLayout
*layout
= pango_layout_new(context
);
3078 pango_layout_set_font_description(layout
, desc
);
3079 pango_layout_set_text(layout
, "H", 1);
3080 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3082 PangoRectangle rect
;
3083 pango_layout_line_get_extents(line
, NULL
, &rect
);
3085 g_object_unref (layout
);
3087 return (int) PANGO_PIXELS(rect
.height
);
3090 int wxWindowGTK::GetCharWidth() const
3092 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3094 wxFont font
= GetFont();
3095 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3097 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
3102 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3103 PangoLayout
*layout
= pango_layout_new(context
);
3104 pango_layout_set_font_description(layout
, desc
);
3105 pango_layout_set_text(layout
, "g", 1);
3106 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3108 PangoRectangle rect
;
3109 pango_layout_line_get_extents(line
, NULL
, &rect
);
3111 g_object_unref (layout
);
3113 return (int) PANGO_PIXELS(rect
.width
);
3116 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3120 int *externalLeading
,
3121 const wxFont
*theFont
) const
3123 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3125 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3134 PangoContext
*context
= NULL
;
3136 context
= gtk_widget_get_pango_context( m_widget
);
3145 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3146 PangoLayout
*layout
= pango_layout_new(context
);
3147 pango_layout_set_font_description(layout
, desc
);
3149 const wxCharBuffer data
= wxGTK_CONV( string
);
3151 pango_layout_set_text(layout
, data
, strlen(data
));
3154 PangoRectangle rect
;
3155 pango_layout_get_extents(layout
, NULL
, &rect
);
3157 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3158 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3161 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3162 int baseline
= pango_layout_iter_get_baseline(iter
);
3163 pango_layout_iter_free(iter
);
3164 *descent
= *y
- PANGO_PIXELS(baseline
);
3166 if (externalLeading
) (*externalLeading
) = 0; // ??
3168 g_object_unref (layout
);
3171 bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
3173 if ( g_delayedFocus
== this )
3175 if ( GTK_WIDGET_REALIZED(m_widget
) )
3177 gtk_widget_grab_focus(m_widget
);
3178 g_delayedFocus
= NULL
;
3187 void wxWindowGTK::SetFocus()
3189 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3192 // don't do anything if we already have focus
3198 // wxWindow::SetFocus() should really set the focus to
3199 // this control, whatever the flags are
3200 if (!GTK_WIDGET_CAN_FOCUS(m_wxwindow
))
3201 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3203 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3205 gtk_widget_grab_focus (m_wxwindow
);
3210 // wxWindow::SetFocus() should really set the focus to
3211 // this control, whatever the flags are
3212 if (!GTK_WIDGET_CAN_FOCUS(m_widget
))
3213 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3215 if (GTK_IS_CONTAINER(m_widget
))
3217 if (GTK_IS_RADIO_BUTTON(m_widget
))
3219 gtk_widget_grab_focus (m_widget
);
3223 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3226 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3229 if (!GTK_WIDGET_REALIZED(m_widget
))
3231 // we can't set the focus to the widget now so we remember that
3232 // it should be focused and will do it later, during the idle
3233 // time, as soon as we can
3234 wxLogTrace(TRACE_FOCUS
,
3235 _T("Delaying setting focus to %s(%s)"),
3236 GetClassInfo()->GetClassName(), GetLabel().c_str());
3238 g_delayedFocus
= this;
3242 wxLogTrace(TRACE_FOCUS
,
3243 _T("Setting focus to %s(%s)"),
3244 GetClassInfo()->GetClassName(), GetLabel().c_str());
3246 gtk_widget_grab_focus (m_widget
);
3251 wxLogTrace(TRACE_FOCUS
,
3252 _T("Can't set focus to %s(%s)"),
3253 GetClassInfo()->GetClassName(), GetLabel().c_str());
3258 void wxWindowGTK::SetCanFocus(bool canFocus
)
3261 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3263 GTK_WIDGET_UNSET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3265 if ( m_wxwindow
&& (m_widget
!= m_wxwindow
) )
3268 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3270 GTK_WIDGET_UNSET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3274 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3276 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3278 wxWindowGTK
*oldParent
= m_parent
,
3279 *newParent
= (wxWindowGTK
*)newParentBase
;
3281 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3283 if ( !wxWindowBase::Reparent(newParent
) )
3286 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3288 /* prevent GTK from deleting the widget arbitrarily */
3289 gtk_widget_ref( m_widget
);
3293 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3296 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3300 if (GTK_WIDGET_VISIBLE (newParent
->m_widget
))
3302 m_showOnIdle
= true;
3303 gtk_widget_hide( m_widget
);
3306 /* insert GTK representation */
3307 (*(newParent
->m_insertCallback
))(newParent
, this);
3310 /* reverse: prevent GTK from deleting the widget arbitrarily */
3311 gtk_widget_unref( m_widget
);
3313 SetLayoutDirection(wxLayout_Default
);
3318 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3320 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3321 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3326 /* insert GTK representation */
3327 (*m_insertCallback
)(this, child
);
3330 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3332 wxWindowBase::AddChild(child
);
3333 m_dirtyTabOrder
= true;
3334 wxTheApp
->WakeUpIdle();
3337 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3339 wxWindowBase::RemoveChild(child
);
3340 m_dirtyTabOrder
= true;
3341 wxTheApp
->WakeUpIdle();
3345 wxLayoutDirection
wxWindowGTK::GTKGetLayout(GtkWidget
*widget
)
3347 return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
3348 ? wxLayout_RightToLeft
3349 : wxLayout_LeftToRight
;
3353 void wxWindowGTK::GTKSetLayout(GtkWidget
*widget
, wxLayoutDirection dir
)
3355 wxASSERT_MSG( dir
!= wxLayout_Default
, _T("invalid layout direction") );
3357 gtk_widget_set_direction(widget
,
3358 dir
== wxLayout_RightToLeft
? GTK_TEXT_DIR_RTL
3359 : GTK_TEXT_DIR_LTR
);
3362 wxLayoutDirection
wxWindowGTK::GetLayoutDirection() const
3364 return GTKGetLayout(m_widget
);
3367 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
)
3369 if ( dir
== wxLayout_Default
)
3371 const wxWindow
*const parent
= GetParent();
3374 // inherit layout from parent.
3375 dir
= parent
->GetLayoutDirection();
3377 else // no parent, use global default layout
3379 dir
= wxTheApp
->GetLayoutDirection();
3383 if ( dir
== wxLayout_Default
)
3386 GTKSetLayout(m_widget
, dir
);
3388 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3389 GTKSetLayout(m_wxwindow
, dir
);
3393 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
,
3394 wxCoord
WXUNUSED(width
),
3395 wxCoord
WXUNUSED(widthTotal
)) const
3397 // We now mirrors the coordinates of RTL windows in GtkPizza
3401 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3403 wxWindowBase::DoMoveInTabOrder(win
, move
);
3404 m_dirtyTabOrder
= true;
3405 wxTheApp
->WakeUpIdle();
3408 bool wxWindowGTK::DoNavigateIn(int flags
)
3410 if ( flags
& wxNavigationKeyEvent::WinChange
)
3412 wxFAIL_MSG( _T("not implemented") );
3416 else // navigate inside the container
3418 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3419 wxCHECK_MSG( parent
, false, _T("every window must have a TLW parent") );
3421 GtkDirectionType dir
;
3422 dir
= flags
& wxNavigationKeyEvent::IsForward
? GTK_DIR_TAB_FORWARD
3423 : GTK_DIR_TAB_BACKWARD
;
3426 g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
);
3432 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3434 // none needed by default
3438 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3440 // nothing to do by default since none is needed
3443 void wxWindowGTK::RealizeTabOrder()
3447 if ( !m_children
.empty() )
3449 // we don't only construct the correct focus chain but also use
3450 // this opportunity to update the mnemonic widgets for the widgets
3453 GList
*chain
= NULL
;
3454 wxWindowGTK
* mnemonicWindow
= NULL
;
3456 for ( wxWindowList::const_iterator i
= m_children
.begin();
3457 i
!= m_children
.end();
3460 wxWindowGTK
*win
= *i
;
3462 if ( mnemonicWindow
)
3464 if ( win
->AcceptsFocusFromKeyboard() )
3466 // wxComboBox et al. needs to focus on on a different
3467 // widget than m_widget, so if the main widget isn't
3468 // focusable try the connect widget
3469 GtkWidget
* w
= win
->m_widget
;
3470 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3472 w
= win
->GetConnectWidget();
3473 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3479 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3480 mnemonicWindow
= NULL
;
3484 else if ( win
->GTKWidgetNeedsMnemonic() )
3486 mnemonicWindow
= win
;
3489 chain
= g_list_prepend(chain
, win
->m_widget
);
3492 chain
= g_list_reverse(chain
);
3494 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3499 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3504 void wxWindowGTK::Raise()
3506 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3508 if (m_wxwindow
&& m_wxwindow
->window
)
3510 gdk_window_raise( m_wxwindow
->window
);
3512 else if (m_widget
->window
)
3514 gdk_window_raise( m_widget
->window
);
3518 void wxWindowGTK::Lower()
3520 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3522 if (m_wxwindow
&& m_wxwindow
->window
)
3524 gdk_window_lower( m_wxwindow
->window
);
3526 else if (m_widget
->window
)
3528 gdk_window_lower( m_widget
->window
);
3532 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3534 if ( !wxWindowBase::SetCursor(cursor
.Ok() ? cursor
: *wxSTANDARD_CURSOR
) )
3542 void wxWindowGTK::GTKUpdateCursor()
3544 wxCursor
cursor(g_globalCursor
.Ok() ? g_globalCursor
: GetCursor());
3547 wxArrayGdkWindows windowsThis
;
3548 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3551 gdk_window_set_cursor(winThis
, cursor
.GetCursor());
3555 const size_t count
= windowsThis
.size();
3556 for ( size_t n
= 0; n
< count
; n
++ )
3558 GdkWindow
*win
= windowsThis
[n
];
3561 wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?"));
3565 gdk_window_set_cursor(win
, cursor
.GetCursor());
3571 void wxWindowGTK::WarpPointer( int x
, int y
)
3573 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3575 // We provide this function ourselves as it is
3576 // missing in GDK (top of this file).
3578 GdkWindow
*window
= (GdkWindow
*) NULL
;
3580 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3582 window
= GetConnectWidget()->window
;
3585 gdk_window_warp_pointer( window
, x
, y
);
3588 wxWindowGTK::ScrollDir
wxWindowGTK::ScrollDirFromRange(GtkRange
*range
) const
3590 // find the scrollbar which generated the event
3591 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3593 if ( range
== m_scrollBar
[dir
] )
3594 return (ScrollDir
)dir
;
3597 wxFAIL_MSG( _T("event from unknown scrollbar received") );
3599 return ScrollDir_Max
;
3602 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3604 bool changed
= false;
3605 GtkRange
* range
= m_scrollBar
[dir
];
3606 if ( range
&& units
)
3608 GtkAdjustment
* adj
= range
->adjustment
;
3609 gdouble inc
= unit
== ScrollUnit_Line
? adj
->step_increment
3610 : adj
->page_increment
;
3612 const int posOld
= int(adj
->value
+ 0.5);
3613 gtk_range_set_value(range
, posOld
+ units
*inc
);
3615 changed
= int(adj
->value
+ 0.5) != posOld
;
3621 bool wxWindowGTK::ScrollLines(int lines
)
3623 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3626 bool wxWindowGTK::ScrollPages(int pages
)
3628 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3631 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground
),
3636 if (!m_widget
->window
)
3641 if (!GTK_PIZZA(m_wxwindow
)->bin_window
) return;
3643 GdkRectangle gdk_rect
,
3647 gdk_rect
.x
= rect
->x
;
3648 gdk_rect
.y
= rect
->y
;
3649 gdk_rect
.width
= rect
->width
;
3650 gdk_rect
.height
= rect
->height
;
3651 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3652 gdk_rect
.x
= GetClientSize().x
- gdk_rect
.x
- gdk_rect
.width
;
3656 else // invalidate everything
3661 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3665 void wxWindowGTK::Update()
3669 // when we call Update() we really want to update the window immediately on
3670 // screen, even if it means flushing the entire queue and hence slowing down
3671 // everything -- but it should still be done, it's just that Update() should
3672 // be called very rarely
3676 void wxWindowGTK::GtkUpdate()
3678 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3679 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3680 if (m_widget
&& m_widget
->window
&& (m_wxwindow
!= m_widget
))
3681 gdk_window_process_updates( m_widget
->window
, FALSE
);
3683 // for consistency with other platforms (and also because it's convenient
3684 // to be able to update an entire TLW by calling Update() only once), we
3685 // should also update all our children here
3686 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3688 node
= node
->GetNext() )
3690 node
->GetData()->GtkUpdate();
3694 bool wxWindowGTK::DoIsExposed( int x
, int y
) const
3696 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
3700 bool wxWindowGTK::DoIsExposed( int x
, int y
, int w
, int h
) const
3702 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3703 return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
;
3705 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
3708 void wxWindowGTK::GtkSendPaintEvents()
3712 m_updateRegion
.Clear();
3716 // Clip to paint region in wxClientDC
3717 m_clipPaintRegion
= true;
3719 m_nativeUpdateRegion
= m_updateRegion
;
3721 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3723 // Transform m_updateRegion under RTL
3724 m_updateRegion
.Clear();
3727 gdk_window_get_geometry( GTK_PIZZA(m_wxwindow
)->bin_window
,
3728 NULL
, NULL
, &width
, NULL
, NULL
);
3730 wxRegionIterator
upd( m_nativeUpdateRegion
);
3734 rect
.x
= upd
.GetX();
3735 rect
.y
= upd
.GetY();
3736 rect
.width
= upd
.GetWidth();
3737 rect
.height
= upd
.GetHeight();
3739 rect
.x
= width
- rect
.x
- rect
.width
;
3740 m_updateRegion
.Union( rect
);
3746 // widget to draw on
3747 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3749 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3751 // find ancestor from which to steal background
3752 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3754 parent
= (wxWindow
*)this;
3756 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3758 wxRegionIterator
upd( m_nativeUpdateRegion
);
3762 rect
.x
= upd
.GetX();
3763 rect
.y
= upd
.GetY();
3764 rect
.width
= upd
.GetWidth();
3765 rect
.height
= upd
.GetHeight();
3767 gtk_paint_flat_box( parent
->m_widget
->style
,
3769 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3782 wxWindowDC
dc( (wxWindow
*)this );
3783 dc
.SetClippingRegion( m_updateRegion
);
3785 // Work around gtk-qt <= 0.60 bug whereby the window colour
3787 if (GetBackgroundStyle() == wxBG_STYLE_COLOUR
&& GetBackgroundColour().Ok() && wxSystemOptions::GetOptionInt(wxT("gtk.window.force-background-colour")) == 1)
3789 dc
.SetBackground(wxBrush(GetBackgroundColour()));
3793 wxEraseEvent
erase_event( GetId(), &dc
);
3794 erase_event
.SetEventObject( this );
3796 GetEventHandler()->ProcessEvent(erase_event
);
3799 wxNcPaintEvent
nc_paint_event( GetId() );
3800 nc_paint_event
.SetEventObject( this );
3801 GetEventHandler()->ProcessEvent( nc_paint_event
);
3803 wxPaintEvent
paint_event( GetId() );
3804 paint_event
.SetEventObject( this );
3805 GetEventHandler()->ProcessEvent( paint_event
);
3807 m_clipPaintRegion
= false;
3809 m_updateRegion
.Clear();
3810 m_nativeUpdateRegion
.Clear();
3813 void wxWindowGTK::SetDoubleBuffered( bool on
)
3815 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3818 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3821 bool wxWindowGTK::IsDoubleBuffered() const
3823 return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow
);
3826 void wxWindowGTK::ClearBackground()
3828 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3832 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3834 wxWindowBase::DoSetToolTip(tip
);
3837 m_tooltip
->Apply( (wxWindow
*)this );
3840 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const gchar
*tip
)
3842 gtk_tooltips_set_tip(tips
, GetConnectWidget(), tip
, NULL
);
3844 #endif // wxUSE_TOOLTIPS
3846 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3848 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3850 if (!wxWindowBase::SetBackgroundColour(colour
))
3855 // We need the pixel value e.g. for background clearing.
3856 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3859 // apply style change (forceStyle=true so that new style is applied
3860 // even if the bg colour changed from valid to wxNullColour)
3861 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3862 ApplyWidgetStyle(true);
3867 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3869 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3871 if (!wxWindowBase::SetForegroundColour(colour
))
3878 // We need the pixel value e.g. for background clearing.
3879 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3882 // apply style change (forceStyle=true so that new style is applied
3883 // even if the bg colour changed from valid to wxNullColour):
3884 ApplyWidgetStyle(true);
3889 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3891 return gtk_widget_get_pango_context( m_widget
);
3894 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3896 // do we need to apply any changes at all?
3899 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3904 GtkRcStyle
*style
= gtk_rc_style_new();
3909 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3912 int flagsNormal
= 0,
3915 flagsInsensitive
= 0;
3917 if ( m_foregroundColour
.Ok() )
3919 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3921 style
->fg
[GTK_STATE_NORMAL
] =
3922 style
->text
[GTK_STATE_NORMAL
] = *fg
;
3923 flagsNormal
|= GTK_RC_FG
| GTK_RC_TEXT
;
3925 style
->fg
[GTK_STATE_PRELIGHT
] =
3926 style
->text
[GTK_STATE_PRELIGHT
] = *fg
;
3927 flagsPrelight
|= GTK_RC_FG
| GTK_RC_TEXT
;
3929 style
->fg
[GTK_STATE_ACTIVE
] =
3930 style
->text
[GTK_STATE_ACTIVE
] = *fg
;
3931 flagsActive
|= GTK_RC_FG
| GTK_RC_TEXT
;
3934 if ( m_backgroundColour
.Ok() )
3936 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3938 style
->bg
[GTK_STATE_NORMAL
] =
3939 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3940 flagsNormal
|= GTK_RC_BG
| GTK_RC_BASE
;
3942 style
->bg
[GTK_STATE_PRELIGHT
] =
3943 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3944 flagsPrelight
|= GTK_RC_BG
| GTK_RC_BASE
;
3946 style
->bg
[GTK_STATE_ACTIVE
] =
3947 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3948 flagsActive
|= GTK_RC_BG
| GTK_RC_BASE
;
3950 style
->bg
[GTK_STATE_INSENSITIVE
] =
3951 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3952 flagsInsensitive
|= GTK_RC_BG
| GTK_RC_BASE
;
3955 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
;
3956 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
;
3957 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
;
3958 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
;
3963 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3965 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3968 DoApplyWidgetStyle(style
);
3969 gtk_rc_style_unref(style
);
3972 // Style change may affect GTK+'s size calculation:
3973 InvalidateBestSize();
3976 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3978 wxSuspendStyleEvents
s(static_cast<wxWindow
*>(this));
3981 gtk_widget_modify_style(m_wxwindow
, style
);
3983 gtk_widget_modify_style(m_widget
, style
);
3986 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3988 wxWindowBase::SetBackgroundStyle(style
);
3990 if (style
== wxBG_STYLE_CUSTOM
)
3995 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3999 GtkWidget
* const w
= GetConnectWidget();
4000 window
= w
? w
->window
: NULL
;
4005 // Make sure GDK/X11 doesn't refresh the window
4007 gdk_window_set_back_pixmap( window
, None
, False
);
4009 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4012 m_needsStyleChange
= false;
4014 else // window not realized yet
4016 // Do in OnIdle, because the window is not yet available
4017 m_needsStyleChange
= true;
4020 // Don't apply widget style, or we get a grey background
4024 // apply style change (forceStyle=true so that new style is applied
4025 // even if the bg colour changed from valid to wxNullColour):
4026 ApplyWidgetStyle(true);
4031 #if wxUSE_DRAG_AND_DROP
4033 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4035 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4037 GtkWidget
*dnd_widget
= GetConnectWidget();
4039 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4041 if (m_dropTarget
) delete m_dropTarget
;
4042 m_dropTarget
= dropTarget
;
4044 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4047 #endif // wxUSE_DRAG_AND_DROP
4049 GtkWidget
* wxWindowGTK::GetConnectWidget()
4051 GtkWidget
*connect_widget
= m_widget
;
4052 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4054 return connect_widget
;
4057 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow
*window
) const
4059 wxArrayGdkWindows windowsThis
;
4060 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
4062 return winThis
? window
== winThis
4063 : windowsThis
.Index(window
) != wxNOT_FOUND
;
4066 GdkWindow
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
4068 return m_wxwindow
? GTK_PIZZA(m_wxwindow
)->bin_window
: m_widget
->window
;
4071 bool wxWindowGTK::SetFont( const wxFont
&font
)
4073 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4075 if (!wxWindowBase::SetFont(font
))
4078 // apply style change (forceStyle=true so that new style is applied
4079 // even if the font changed from valid to wxNullFont):
4080 ApplyWidgetStyle(true);
4085 void wxWindowGTK::DoCaptureMouse()
4087 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4089 GdkWindow
*window
= (GdkWindow
*) NULL
;
4091 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4093 window
= GetConnectWidget()->window
;
4095 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4097 const wxCursor
* cursor
= &m_cursor
;
4099 cursor
= wxSTANDARD_CURSOR
;
4101 gdk_pointer_grab( window
, FALSE
,
4103 (GDK_BUTTON_PRESS_MASK
|
4104 GDK_BUTTON_RELEASE_MASK
|
4105 GDK_POINTER_MOTION_HINT_MASK
|
4106 GDK_POINTER_MOTION_MASK
),
4108 cursor
->GetCursor(),
4109 (guint32
)GDK_CURRENT_TIME
);
4110 g_captureWindow
= this;
4111 g_captureWindowHasMouse
= true;
4114 void wxWindowGTK::DoReleaseMouse()
4116 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4118 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4120 g_captureWindow
= (wxWindowGTK
*) NULL
;
4122 GdkWindow
*window
= (GdkWindow
*) NULL
;
4124 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4126 window
= GetConnectWidget()->window
;
4131 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4134 void wxWindowGTK::GTKReleaseMouseAndNotify()
4137 wxMouseCaptureLostEvent
evt(GetId());
4138 evt
.SetEventObject( this );
4139 GetEventHandler()->ProcessEvent( evt
);
4143 wxWindow
*wxWindowBase::GetCapture()
4145 return (wxWindow
*)g_captureWindow
;
4148 bool wxWindowGTK::IsRetained() const
4153 void wxWindowGTK::SetScrollbar(int orient
,
4157 bool WXUNUSED(update
))
4159 const int dir
= ScrollDirFromOrient(orient
);
4160 GtkRange
* const sb
= m_scrollBar
[dir
];
4161 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4165 m_hasScrolling
= true;
4169 // GtkRange requires upper > lower
4174 GtkAdjustment
* const adj
= sb
->adjustment
;
4175 adj
->step_increment
= 1;
4176 adj
->page_increment
=
4177 adj
->page_size
= thumbVisible
;
4180 g_signal_handlers_block_by_func(
4181 sb
, (void*)gtk_scrollbar_value_changed
, this);
4183 gtk_range_set_range(sb
, 0, range
);
4184 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4186 g_signal_handlers_unblock_by_func(
4187 sb
, (void*)gtk_scrollbar_value_changed
, this);
4190 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4192 const int dir
= ScrollDirFromOrient(orient
);
4193 GtkRange
* const sb
= m_scrollBar
[dir
];
4194 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4196 // This check is more than an optimization. Without it, the slider
4197 // will not move smoothly while tracking when using wxScrollHelper.
4198 if (GetScrollPos(orient
) != pos
)
4200 g_signal_handlers_block_by_func(
4201 sb
, (void*)gtk_scrollbar_value_changed
, this);
4203 gtk_range_set_value(sb
, pos
);
4204 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4206 g_signal_handlers_unblock_by_func(
4207 sb
, (void*)gtk_scrollbar_value_changed
, this);
4211 int wxWindowGTK::GetScrollThumb(int orient
) const
4213 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4214 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4216 return int(sb
->adjustment
->page_size
);
4219 int wxWindowGTK::GetScrollPos( int orient
) const
4221 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4222 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4224 return int(sb
->adjustment
->value
+ 0.5);
4227 int wxWindowGTK::GetScrollRange( int orient
) const
4229 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4230 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4232 return int(sb
->adjustment
->upper
);
4235 // Determine if increment is the same as +/-x, allowing for some small
4236 // difference due to possible inexactness in floating point arithmetic
4237 static inline bool IsScrollIncrement(double increment
, double x
)
4239 wxASSERT(increment
> 0);
4240 const double tolerance
= 1.0 / 1024;
4241 return fabs(increment
- fabs(x
)) < tolerance
;
4244 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4248 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4250 const int barIndex
= range
== m_scrollBar
[1];
4251 GtkAdjustment
* adj
= range
->adjustment
;
4253 const int value
= int(adj
->value
+ 0.5);
4255 // save previous position
4256 const double oldPos
= m_scrollPos
[barIndex
];
4257 // update current position
4258 m_scrollPos
[barIndex
] = adj
->value
;
4259 // If event should be ignored, or integral position has not changed
4260 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4265 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4268 // Difference from last change event
4269 const double diff
= adj
->value
- oldPos
;
4270 const bool isDown
= diff
> 0;
4272 if (IsScrollIncrement(adj
->step_increment
, diff
))
4274 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4276 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4278 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4280 else if (m_mouseButtonDown
)
4282 // Assume track event
4283 m_isScrolling
= true;
4289 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4291 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4293 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4295 // No scrolling requested.
4296 if ((dx
== 0) && (dy
== 0)) return;
4298 m_clipPaintRegion
= true;
4300 if (GetLayoutDirection() == wxLayout_RightToLeft
)
4301 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), dx
, -dy
);
4303 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4305 m_clipPaintRegion
= false;
4308 bool restoreCaret
= (GetCaret() != NULL
&& GetCaret()->IsVisible());
4311 wxRect
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4313 caretRect
.width
+= dx
;
4316 caretRect
.x
+= dx
; caretRect
.width
-= dx
;
4319 caretRect
.height
+= dy
;
4322 caretRect
.y
+= dy
; caretRect
.height
-= dy
;
4325 RefreshRect(caretRect
);
4327 #endif // wxUSE_CARET
4330 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4332 //RN: Note that static controls usually have no border on gtk, so maybe
4333 //it makes sense to treat that as simply no border at the wx level
4335 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4337 GtkShadowType gtkstyle
;
4339 if(wxstyle
& wxBORDER_RAISED
)
4340 gtkstyle
= GTK_SHADOW_OUT
;
4341 else if (wxstyle
& wxBORDER_SUNKEN
)
4342 gtkstyle
= GTK_SHADOW_IN
;
4345 else if (wxstyle
& wxBORDER_DOUBLE
)
4346 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4349 gtkstyle
= GTK_SHADOW_IN
;
4351 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4356 void wxWindowGTK::SetWindowStyleFlag( long style
)
4358 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4359 wxWindowBase::SetWindowStyleFlag(style
);
4362 // Find the wxWindow at the current mouse position, also returning the mouse
4364 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4366 pt
= wxGetMousePosition();
4367 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4371 // Get the current mouse position.
4372 wxPoint
wxGetMousePosition()
4374 /* This crashes when used within wxHelpContext,
4375 so we have to use the X-specific implementation below.
4377 GdkModifierType *mask;
4378 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4380 return wxPoint(x, y);
4384 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4386 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4387 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4388 Window rootReturn
, childReturn
;
4389 int rootX
, rootY
, winX
, winY
;
4390 unsigned int maskReturn
;
4392 XQueryPointer (display
,
4396 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4397 return wxPoint(rootX
, rootY
);
4401 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4402 void wxAddGrab(wxWindow
* window
)
4404 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4407 void wxRemoveGrab(wxWindow
* window
)
4409 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );