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 wxPizza, defined in
116 win_gtk.cpp), 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 wxPizza 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 wxPizza
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->m_scroll_x and pizza->m_scroll_y 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 //-----------------------------------------------------------------------------
316 // "size_request" of m_widget
317 //-----------------------------------------------------------------------------
319 // make it extern because wxStaticText needs to disconnect this one
321 void wxgtk_window_size_request_callback(GtkWidget
* WXUNUSED(widget
),
322 GtkRequisition
*requisition
,
326 win
->GetSize( &w
, &h
);
332 requisition
->height
= h
;
333 requisition
->width
= w
;
341 void wxgtk_combo_size_request_callback(GtkWidget
* WXUNUSED(widget
),
342 GtkRequisition
*requisition
,
345 // This callback is actually hooked into the text entry
346 // of the combo box, not the GtkHBox.
349 win
->GetSize( &w
, &h
);
355 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
357 GtkRequisition entry_req
;
359 entry_req
.height
= 2;
360 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->entry
) )->size_request
)
361 (gcombo
->entry
, &entry_req
);
363 GtkRequisition button_req
;
364 button_req
.width
= 2;
365 button_req
.height
= 2;
366 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
367 (gcombo
->button
, &button_req
);
369 requisition
->width
= w
- button_req
.width
;
370 requisition
->height
= entry_req
.height
;
374 #endif // wxUSE_COMBOBOX
376 //-----------------------------------------------------------------------------
377 // "expose_event" of m_wxwindow
378 //-----------------------------------------------------------------------------
382 gtk_window_expose_callback( GtkWidget
*widget
,
383 GdkEventExpose
*gdk_event
,
388 // if this event is for the border-only GdkWindow
389 if (gdk_event
->window
!= widget
->window
)
395 wxPrintf( wxT("OnExpose from ") );
396 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
397 wxPrintf( win
->GetClassInfo()->GetClassName() );
398 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
399 (int)gdk_event
->area
.y
,
400 (int)gdk_event
->area
.width
,
401 (int)gdk_event
->area
.height
);
406 win
->m_wxwindow
->style
,
410 (GdkRectangle
*) NULL
,
412 (char *)"button", // const_cast
417 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
419 win
->GtkSendPaintEvents();
421 // Let parent window draw window-less widgets
426 //-----------------------------------------------------------------------------
427 // "expose_event" from m_widget, for drawing border
428 //-----------------------------------------------------------------------------
430 #ifndef __WXUNIVERSAL__
433 expose_event_border(GtkWidget
* widget
, GdkEventExpose
* event
, wxWindow
* win
)
435 // if this event is not for the GdkWindow the border is drawn on
436 if (win
->m_wxwindow
== win
->m_widget
&& event
->window
== widget
->window
)
441 // GtkScrolledWindow is GTK_NO_WINDOW
442 if (GTK_WIDGET_NO_WINDOW(widget
))
444 x
= widget
->allocation
.x
;
445 y
= widget
->allocation
.y
;
447 int w
= win
->m_wxwindow
->allocation
.width
;
448 int h
= win
->m_wxwindow
->allocation
.height
;
449 if (win
->HasFlag(wxBORDER_SIMPLE
))
452 gc
= gdk_gc_new(event
->window
);
453 gdk_gc_set_foreground(gc
, &widget
->style
->black
);
454 gdk_draw_rectangle(event
->window
, gc
, false, x
, y
, w
- 1, h
- 1);
459 GtkShadowType shadow
= GTK_SHADOW_IN
;
460 if (win
->HasFlag(wxBORDER_RAISED
))
461 shadow
= GTK_SHADOW_OUT
;
463 widget
->style
, event
->window
, GTK_STATE_NORMAL
,
464 shadow
, &event
->area
, widget
, NULL
, x
, y
, w
, h
);
467 // no further painting is needed for border-only GdkWindow
468 return win
->m_wxwindow
== win
->m_widget
;
471 #endif // !__WXUNIVERSAL__
473 //-----------------------------------------------------------------------------
474 // "key_press_event" from any window
475 //-----------------------------------------------------------------------------
477 // These are used when transforming Ctrl-alpha to ascii values 1-26
478 inline bool wxIsLowerChar(int code
)
480 return (code
>= 'a' && code
<= 'z' );
483 inline bool wxIsUpperChar(int code
)
485 return (code
>= 'A' && code
<= 'Z' );
489 // set WXTRACE to this to see the key event codes on the console
490 #define TRACE_KEYS _T("keyevent")
492 // translates an X key symbol to WXK_XXX value
494 // if isChar is true it means that the value returned will be used for EVT_CHAR
495 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
496 // for example, while if it is false it means that the value is going to be
497 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
499 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
505 // Shift, Control and Alt don't generate the CHAR events at all
508 key_code
= isChar
? 0 : WXK_SHIFT
;
512 key_code
= isChar
? 0 : WXK_CONTROL
;
520 key_code
= isChar
? 0 : WXK_ALT
;
523 // neither do the toggle modifies
524 case GDK_Scroll_Lock
:
525 key_code
= isChar
? 0 : WXK_SCROLL
;
529 key_code
= isChar
? 0 : WXK_CAPITAL
;
533 key_code
= isChar
? 0 : WXK_NUMLOCK
;
537 // various other special keys
550 case GDK_ISO_Left_Tab
:
557 key_code
= WXK_RETURN
;
561 key_code
= WXK_CLEAR
;
565 key_code
= WXK_PAUSE
;
569 key_code
= WXK_SELECT
;
573 key_code
= WXK_PRINT
;
577 key_code
= WXK_EXECUTE
;
581 key_code
= WXK_ESCAPE
;
584 // cursor and other extended keyboard keys
586 key_code
= WXK_DELETE
;
602 key_code
= WXK_RIGHT
;
609 case GDK_Prior
: // == GDK_Page_Up
610 key_code
= WXK_PAGEUP
;
613 case GDK_Next
: // == GDK_Page_Down
614 key_code
= WXK_PAGEDOWN
;
626 key_code
= WXK_INSERT
;
641 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
645 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
649 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
653 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
657 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
661 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
665 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
669 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
673 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
677 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
681 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
685 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
689 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
692 case GDK_KP_Prior
: // == GDK_KP_Page_Up
693 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
696 case GDK_KP_Next
: // == GDK_KP_Page_Down
697 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
701 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
705 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
709 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
713 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
717 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
720 case GDK_KP_Multiply
:
721 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
725 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
728 case GDK_KP_Separator
:
729 // FIXME: what is this?
730 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
733 case GDK_KP_Subtract
:
734 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
738 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
742 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
759 key_code
= WXK_F1
+ keysym
- GDK_F1
;
769 static inline bool wxIsAsciiKeysym(KeySym ks
)
774 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
776 GdkEventKey
*gdk_event
)
780 GdkModifierType state
;
781 if (gdk_event
->window
)
782 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
784 event
.SetTimestamp( gdk_event
->time
);
785 event
.SetId(win
->GetId());
786 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
787 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
788 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
789 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
790 event
.m_scanCode
= gdk_event
->keyval
;
791 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
792 event
.m_rawFlags
= 0;
794 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
796 wxGetMousePosition( &x
, &y
);
797 win
->ScreenToClient( &x
, &y
);
800 event
.SetEventObject( win
);
805 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
807 GdkEventKey
*gdk_event
)
809 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
810 // but only event->keyval which is quite useless to us, so remember
811 // the last character from GDK_KEY_PRESS and reuse it as last resort
813 // NB: should be MT-safe as we're always called from the main thread only
818 } s_lastKeyPress
= { 0, 0 };
820 KeySym keysym
= gdk_event
->keyval
;
822 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
823 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
827 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
831 // do we have the translation or is it a plain ASCII character?
832 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
834 // we should use keysym if it is ASCII as X does some translations
835 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
836 // which we don't want here (but which we do use for OnChar())
837 if ( !wxIsAsciiKeysym(keysym
) )
839 keysym
= (KeySym
)gdk_event
->string
[0];
842 // we want to always get the same key code when the same key is
843 // pressed regardless of the state of the modifiers, i.e. on a
844 // standard US keyboard pressing '5' or '%' ('5' key with
845 // Shift) should result in the same key code in OnKeyDown():
846 // '5' (although OnChar() will get either '5' or '%').
848 // to do it we first translate keysym to keycode (== scan code)
849 // and then back but always using the lower register
850 Display
*dpy
= (Display
*)wxGetDisplay();
851 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
853 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
855 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
857 // use the normalized, i.e. lower register, keysym if we've
859 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
861 // as explained above, we want to have lower register key codes
862 // normally but for the letter keys we want to have the upper ones
864 // NB: don't use XConvertCase() here, we want to do it for letters
866 key_code
= toupper(key_code
);
868 else // non ASCII key, what to do?
870 // by default, ignore it
873 // but if we have cached information from the last KEY_PRESS
874 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
877 if ( keysym
== s_lastKeyPress
.keysym
)
879 key_code
= s_lastKeyPress
.keycode
;
884 if ( gdk_event
->type
== GDK_KEY_PRESS
)
886 // remember it to be reused for KEY_UP event later
887 s_lastKeyPress
.keysym
= keysym
;
888 s_lastKeyPress
.keycode
= key_code
;
892 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
894 // sending unknown key events doesn't really make sense
898 // now fill all the other fields
899 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
901 event
.m_keyCode
= key_code
;
903 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
905 event
.m_uniChar
= key_code
;
915 GtkIMContext
*context
;
916 GdkEventKey
*lastKeyEvent
;
920 context
= gtk_im_multicontext_new();
925 g_object_unref (context
);
931 gtk_window_key_press_callback( GtkWidget
*widget
,
932 GdkEventKey
*gdk_event
,
939 if (g_blockEventsOnDrag
)
942 // GTK+ sends keypress events to the focus widget and then
943 // to all its parent and grandparent widget. We only want
944 // the key events from the focus widget.
945 if (!GTK_WIDGET_HAS_FOCUS(widget
))
948 wxKeyEvent
event( wxEVT_KEY_DOWN
);
950 bool return_after_IM
= false;
952 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
954 // Emit KEY_DOWN event
955 ret
= win
->GetEventHandler()->ProcessEvent( event
);
959 // Return after IM processing as we cannot do
960 // anything with it anyhow.
961 return_after_IM
= true;
964 if ((!ret
) && (win
->m_imData
!= NULL
))
966 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
967 // docs, if IM filter returns true, no further processing should be done.
968 // we should send the key_down event anyway.
969 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
970 win
->m_imData
->lastKeyEvent
= NULL
;
971 if (intercepted_by_IM
)
973 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
984 wxWindowGTK
*ancestor
= win
;
987 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
990 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
991 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
994 if (ancestor
->IsTopLevel())
996 ancestor
= ancestor
->GetParent();
999 #endif // wxUSE_ACCEL
1001 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1002 // will only be sent if it is not in an accelerator table.
1006 KeySym keysym
= gdk_event
->keyval
;
1007 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1008 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1011 if ( wxIsAsciiKeysym(keysym
) )
1014 key_code
= (unsigned char)keysym
;
1016 // gdk_event->string is actually deprecated
1017 else if ( gdk_event
->length
== 1 )
1019 key_code
= (unsigned char)gdk_event
->string
[0];
1025 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1027 event
.m_keyCode
= key_code
;
1029 // To conform to the docs we need to translate Ctrl-alpha
1030 // characters to values in the range 1-26.
1031 if ( event
.ControlDown() &&
1032 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
1034 if ( wxIsLowerChar(key_code
) )
1035 event
.m_keyCode
= key_code
- 'a' + 1;
1036 if ( wxIsUpperChar(key_code
) )
1037 event
.m_keyCode
= key_code
- 'A' + 1;
1039 event
.m_uniChar
= event
.m_keyCode
;
1043 // Implement OnCharHook by checking ancestor top level windows
1044 wxWindow
*parent
= win
;
1045 while (parent
&& !parent
->IsTopLevel())
1046 parent
= parent
->GetParent();
1049 event
.SetEventType( wxEVT_CHAR_HOOK
);
1050 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1055 event
.SetEventType(wxEVT_CHAR
);
1056 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1067 gtk_wxwindow_commit_cb (GtkIMContext
* WXUNUSED(context
),
1071 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1073 // take modifiers, cursor position, timestamp etc. from the last
1074 // key_press_event that was fed into Input Method:
1075 if (window
->m_imData
->lastKeyEvent
)
1077 wxFillOtherKeyEventFields(event
,
1078 window
, window
->m_imData
->lastKeyEvent
);
1082 event
.SetEventObject( window
);
1085 const wxString
data(wxGTK_CONV_BACK_SYS(str
));
1091 // Implement OnCharHook by checking ancestor top level windows
1092 wxWindow
*parent
= window
;
1093 while (parent
&& !parent
->IsTopLevel())
1094 parent
= parent
->GetParent();
1096 for( wxString::const_iterator pstr
= data
.begin(); pstr
!= data
.end(); ++pstr
)
1099 event
.m_uniChar
= *pstr
;
1100 // Backward compatible for ISO-8859-1
1101 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1102 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1104 event
.m_keyCode
= (char)*pstr
;
1105 #endif // wxUSE_UNICODE
1107 // To conform to the docs we need to translate Ctrl-alpha
1108 // characters to values in the range 1-26.
1109 if ( event
.ControlDown() &&
1110 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
1112 if ( wxIsLowerChar(*pstr
) )
1113 event
.m_keyCode
= *pstr
- 'a' + 1;
1114 if ( wxIsUpperChar(*pstr
) )
1115 event
.m_keyCode
= *pstr
- 'A' + 1;
1117 event
.m_keyCode
= *pstr
- 'a' + 1;
1119 event
.m_uniChar
= event
.m_keyCode
;
1125 event
.SetEventType( wxEVT_CHAR_HOOK
);
1126 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1131 event
.SetEventType(wxEVT_CHAR
);
1132 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1139 //-----------------------------------------------------------------------------
1140 // "key_release_event" from any window
1141 //-----------------------------------------------------------------------------
1145 gtk_window_key_release_callback( GtkWidget
* WXUNUSED(widget
),
1146 GdkEventKey
*gdk_event
,
1154 if (g_blockEventsOnDrag
)
1157 wxKeyEvent
event( wxEVT_KEY_UP
);
1158 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1160 // unknown key pressed, ignore (the event would be useless anyhow)
1164 return win
->GTKProcessEvent(event
);
1168 // ============================================================================
1170 // ============================================================================
1172 // ----------------------------------------------------------------------------
1173 // mouse event processing helpers
1174 // ----------------------------------------------------------------------------
1176 // init wxMouseEvent with the info from GdkEventXXX struct
1177 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1178 wxMouseEvent
& event
,
1181 event
.SetTimestamp( gdk_event
->time
);
1182 event
.m_shiftDown
= gdk_event
->state
& GDK_SHIFT_MASK
;
1183 event
.m_controlDown
= gdk_event
->state
& GDK_CONTROL_MASK
;
1184 event
.m_altDown
= gdk_event
->state
& GDK_MOD1_MASK
;
1185 event
.m_metaDown
= gdk_event
->state
& GDK_MOD2_MASK
;
1186 event
.m_leftDown
= gdk_event
->state
& GDK_BUTTON1_MASK
;
1187 event
.m_middleDown
= gdk_event
->state
& GDK_BUTTON2_MASK
;
1188 event
.m_rightDown
= gdk_event
->state
& GDK_BUTTON3_MASK
;
1189 event
.m_aux1Down
= gdk_event
->state
& GDK_BUTTON4_MASK
;
1190 event
.m_aux2Down
= gdk_event
->state
& GDK_BUTTON5_MASK
;
1192 wxPoint pt
= win
->GetClientAreaOrigin();
1193 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1194 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1196 if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
))
1198 // origin in the upper right corner
1199 int window_width
= win
->m_wxwindow
->allocation
.width
;
1200 event
.m_x
= window_width
- event
.m_x
;
1203 event
.SetEventObject( win
);
1204 event
.SetId( win
->GetId() );
1205 event
.SetTimestamp( gdk_event
->time
);
1208 static void AdjustEventButtonState(wxMouseEvent
& event
)
1210 // GDK reports the old state of the button for a button press event, but
1211 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1212 // for a LEFT_DOWN event, not FALSE, so we will invert
1213 // left/right/middleDown for the corresponding click events
1215 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1216 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1217 (event
.GetEventType() == wxEVT_LEFT_UP
))
1219 event
.m_leftDown
= !event
.m_leftDown
;
1223 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1224 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1225 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1227 event
.m_middleDown
= !event
.m_middleDown
;
1231 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1232 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1233 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1235 event
.m_rightDown
= !event
.m_rightDown
;
1240 // find the window to send the mouse event too
1242 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1247 if (win
->m_wxwindow
)
1249 wxPizza
* pizza
= WX_PIZZA(win
->m_wxwindow
);
1250 xx
+= pizza
->m_scroll_x
;
1251 yy
+= pizza
->m_scroll_y
;
1254 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1257 wxWindowGTK
*child
= node
->GetData();
1259 node
= node
->GetNext();
1260 if (!child
->IsShown())
1263 if (child
->IsTransparentForMouse())
1265 // wxStaticBox is transparent in the box itself
1266 int xx1
= child
->m_x
;
1267 int yy1
= child
->m_y
;
1268 int xx2
= child
->m_x
+ child
->m_width
;
1269 int yy2
= child
->m_y
+ child
->m_height
;
1272 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1274 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1276 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1278 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1289 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1290 (child
->m_x
<= xx
) &&
1291 (child
->m_y
<= yy
) &&
1292 (child
->m_x
+child
->m_width
>= xx
) &&
1293 (child
->m_y
+child
->m_height
>= yy
))
1306 // ----------------------------------------------------------------------------
1307 // common event handlers helpers
1308 // ----------------------------------------------------------------------------
1310 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const
1312 // nothing special at this level
1313 return GetEventHandler()->ProcessEvent(event
);
1316 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1322 if (g_blockEventsOnDrag
)
1324 if (g_blockEventsOnScroll
)
1327 if (!GTKIsOwnWindow(event
->window
))
1333 // overloads for all GDK event types we use here: we need to have this as
1334 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1335 // derives from it in the sense that the structs have the same layout
1336 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1337 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1339 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1342 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1343 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1344 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1346 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1348 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1349 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1353 // send the wxChildFocusEvent and wxFocusEvent, common code of
1354 // gtk_window_focus_in_callback() and SetFocus()
1355 static bool DoSendFocusEvents(wxWindow
*win
)
1357 // Notify the parent keeping track of focus for the kbd navigation
1358 // purposes that we got it.
1359 wxChildFocusEvent
eventChildFocus(win
);
1360 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1362 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1363 eventFocus
.SetEventObject(win
);
1365 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1368 // all event handlers must have C linkage as they're called from GTK+ C code
1372 //-----------------------------------------------------------------------------
1373 // "button_press_event"
1374 //-----------------------------------------------------------------------------
1377 gtk_window_button_press_callback( GtkWidget
*widget
,
1378 GdkEventButton
*gdk_event
,
1381 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1383 g_lastButtonNumber
= gdk_event
->button
;
1385 // GDK sends surplus button down events
1386 // before a double click event. We
1387 // need to filter these out.
1388 if ((gdk_event
->type
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
))
1390 GdkEvent
*peek_event
= gdk_event_peek();
1393 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1394 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1396 gdk_event_free( peek_event
);
1401 gdk_event_free( peek_event
);
1406 wxEventType event_type
= wxEVT_NULL
;
1408 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1409 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1411 // Reset GDK internal timestamp variables in order to disable GDK
1412 // triple click events. GDK will then next time believe no button has
1413 // been clicked just before, and send a normal button click event.
1414 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1415 display
->button_click_time
[1] = 0;
1416 display
->button_click_time
[0] = 0;
1419 if (gdk_event
->button
== 1)
1421 // note that GDK generates triple click events which are not supported
1422 // by wxWidgets but still have to be passed to the app as otherwise
1423 // clicks would simply go missing
1424 switch (gdk_event
->type
)
1426 // we shouldn't get triple clicks at all for GTK2 because we
1427 // suppress them artificially using the code above but we still
1428 // should map them to something for GTK1 and not just ignore them
1429 // as this would lose clicks
1430 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1431 case GDK_BUTTON_PRESS
:
1432 event_type
= wxEVT_LEFT_DOWN
;
1435 case GDK_2BUTTON_PRESS
:
1436 event_type
= wxEVT_LEFT_DCLICK
;
1440 // just to silence gcc warnings
1444 else if (gdk_event
->button
== 2)
1446 switch (gdk_event
->type
)
1448 case GDK_3BUTTON_PRESS
:
1449 case GDK_BUTTON_PRESS
:
1450 event_type
= wxEVT_MIDDLE_DOWN
;
1453 case GDK_2BUTTON_PRESS
:
1454 event_type
= wxEVT_MIDDLE_DCLICK
;
1461 else if (gdk_event
->button
== 3)
1463 switch (gdk_event
->type
)
1465 case GDK_3BUTTON_PRESS
:
1466 case GDK_BUTTON_PRESS
:
1467 event_type
= wxEVT_RIGHT_DOWN
;
1470 case GDK_2BUTTON_PRESS
:
1471 event_type
= wxEVT_RIGHT_DCLICK
;
1479 if ( event_type
== wxEVT_NULL
)
1481 // unknown mouse button or click type
1485 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1487 wxMouseEvent
event( event_type
);
1488 InitMouseEvent( win
, event
, gdk_event
);
1490 AdjustEventButtonState(event
);
1492 // wxListBox actually gets mouse events from the item, so we need to give it
1493 // a chance to correct this
1494 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1496 // find the correct window to send the event to: it may be a different one
1497 // from the one which got it at GTK+ level because some controls don't have
1498 // their own X window and thus cannot get any events.
1499 if ( !g_captureWindow
)
1500 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1502 // reset the event object and id in case win changed.
1503 event
.SetEventObject( win
);
1504 event
.SetId( win
->GetId() );
1506 bool ret
= win
->GTKProcessEvent( event
);
1507 g_lastMouseEvent
= NULL
;
1511 if ((event_type
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&
1512 (g_focusWindow
!= win
) /* && win->IsFocusable() */)
1517 if (event_type
== wxEVT_RIGHT_DOWN
)
1519 // generate a "context menu" event: this is similar to right mouse
1520 // click under many GUIs except that it is generated differently
1521 // (right up under MSW, ctrl-click under Mac, right down here) and
1523 // (a) it's a command event and so is propagated to the parent
1524 // (b) under some ports it can be generated from kbd too
1525 // (c) it uses screen coords (because of (a))
1526 wxContextMenuEvent
evtCtx(
1529 win
->ClientToScreen(event
.GetPosition()));
1530 evtCtx
.SetEventObject(win
);
1531 return win
->GTKProcessEvent(evtCtx
);
1537 //-----------------------------------------------------------------------------
1538 // "button_release_event"
1539 //-----------------------------------------------------------------------------
1542 gtk_window_button_release_callback( GtkWidget
*widget
,
1543 GdkEventButton
*gdk_event
,
1546 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1548 g_lastButtonNumber
= 0;
1550 wxEventType event_type
= wxEVT_NULL
;
1552 switch (gdk_event
->button
)
1555 event_type
= wxEVT_LEFT_UP
;
1559 event_type
= wxEVT_MIDDLE_UP
;
1563 event_type
= wxEVT_RIGHT_UP
;
1567 // unknown button, don't process
1571 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1573 wxMouseEvent
event( event_type
);
1574 InitMouseEvent( win
, event
, gdk_event
);
1576 AdjustEventButtonState(event
);
1578 // same wxListBox hack as above
1579 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1581 if ( !g_captureWindow
)
1582 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1584 // reset the event object and id in case win changed.
1585 event
.SetEventObject( win
);
1586 event
.SetId( win
->GetId() );
1588 bool ret
= win
->GTKProcessEvent(event
);
1590 g_lastMouseEvent
= NULL
;
1595 //-----------------------------------------------------------------------------
1596 // "motion_notify_event"
1597 //-----------------------------------------------------------------------------
1600 gtk_window_motion_notify_callback( GtkWidget
* WXUNUSED(widget
),
1601 GdkEventMotion
*gdk_event
,
1604 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1606 if (gdk_event
->is_hint
)
1610 GdkModifierType state
;
1611 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1616 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1618 wxMouseEvent
event( wxEVT_MOTION
);
1619 InitMouseEvent(win
, event
, gdk_event
);
1621 if ( g_captureWindow
)
1623 // synthesise a mouse enter or leave event if needed
1624 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1625 // This seems to be necessary and actually been added to
1626 // GDK itself in version 2.0.X
1629 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1630 if ( hasMouse
!= g_captureWindowHasMouse
)
1632 // the mouse changed window
1633 g_captureWindowHasMouse
= hasMouse
;
1635 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1636 : wxEVT_LEAVE_WINDOW
);
1637 InitMouseEvent(win
, eventM
, gdk_event
);
1638 eventM
.SetEventObject(win
);
1639 win
->GTKProcessEvent(eventM
);
1644 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1646 // reset the event object and id in case win changed.
1647 event
.SetEventObject( win
);
1648 event
.SetId( win
->GetId() );
1651 if ( !g_captureWindow
)
1653 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1654 if (win
->GTKProcessEvent( cevent
))
1656 win
->SetCursor( cevent
.GetCursor() );
1660 bool ret
= win
->GTKProcessEvent(event
);
1662 g_lastMouseEvent
= NULL
;
1667 //-----------------------------------------------------------------------------
1668 // "scroll_event" (mouse wheel event)
1669 //-----------------------------------------------------------------------------
1672 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1676 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1677 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1682 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1683 InitMouseEvent(win
, event
, gdk_event
);
1684 event
.m_linesPerAction
= 3;
1685 event
.m_wheelDelta
= 120;
1686 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1687 event
.m_wheelRotation
= 120;
1689 event
.m_wheelRotation
= -120;
1691 return win
->GTKProcessEvent(event
);
1694 //-----------------------------------------------------------------------------
1696 //-----------------------------------------------------------------------------
1698 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1700 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1701 event
.SetEventObject(win
);
1702 return win
->GTKProcessEvent(event
);
1705 //-----------------------------------------------------------------------------
1707 //-----------------------------------------------------------------------------
1710 gtk_window_focus_in_callback( GtkWidget
* WXUNUSED(widget
),
1711 GdkEventFocus
*WXUNUSED(event
),
1717 gtk_im_context_focus_in(win
->m_imData
->context
);
1720 g_focusWindow
= win
;
1722 wxLogTrace(TRACE_FOCUS
,
1723 _T("%s: focus in"), win
->GetName().c_str());
1726 // caret needs to be informed about focus change
1727 wxCaret
*caret
= win
->GetCaret();
1730 caret
->OnSetFocus();
1732 #endif // wxUSE_CARET
1734 gboolean ret
= FALSE
;
1736 // does the window itself think that it has the focus?
1737 if ( !win
->m_hasFocus
)
1739 // not yet, notify it
1740 win
->m_hasFocus
= true;
1742 (void)DoSendFocusEvents(win
);
1747 // Disable default focus handling for custom windows
1748 // since the default GTK+ handler issues a repaint
1749 if (win
->m_wxwindow
)
1755 //-----------------------------------------------------------------------------
1756 // "focus_out_event"
1757 //-----------------------------------------------------------------------------
1760 gtk_window_focus_out_callback( GtkWidget
* WXUNUSED(widget
),
1761 GdkEventFocus
* WXUNUSED(gdk_event
),
1767 gtk_im_context_focus_out(win
->m_imData
->context
);
1769 wxLogTrace( TRACE_FOCUS
,
1770 _T("%s: focus out"), win
->GetName().c_str() );
1773 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1777 g_focusWindow
= (wxWindowGTK
*)NULL
;
1780 // caret needs to be informed about focus change
1781 wxCaret
*caret
= win
->GetCaret();
1784 caret
->OnKillFocus();
1786 #endif // wxUSE_CARET
1788 // don't send the window a kill focus event if it thinks that it doesn't
1789 // have focus already
1790 if ( win
->m_hasFocus
)
1792 // the event handler might delete the window when it loses focus, so
1793 // check whether this is a custom window before calling it
1794 const bool has_wxwindow
= win
->m_wxwindow
!= NULL
;
1796 win
->m_hasFocus
= false;
1798 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1799 event
.SetEventObject( win
);
1801 (void)win
->GTKProcessEvent( event
);
1803 // Disable default focus handling for custom windows
1804 // since the default GTK+ handler issues a repaint
1809 // continue with normal processing
1814 wx_window_focus_callback(GtkWidget
*widget
,
1815 GtkDirectionType
WXUNUSED(direction
),
1818 // the default handler for focus signal in GtkScrolledWindow sets
1819 // focus to the window itself even if it doesn't accept focus, i.e. has no
1820 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1821 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1822 // any children which might accept focus (we know we don't accept the focus
1823 // ourselves as this signal is only connected in this case)
1824 if ( win
->GetChildren().empty() )
1825 g_signal_stop_emission_by_name(widget
, "focus");
1827 // we didn't change the focus
1831 //-----------------------------------------------------------------------------
1832 // "enter_notify_event"
1833 //-----------------------------------------------------------------------------
1836 gtk_window_enter_callback( GtkWidget
*widget
,
1837 GdkEventCrossing
*gdk_event
,
1840 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1842 // Event was emitted after a grab
1843 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1847 GdkModifierType state
= (GdkModifierType
)0;
1849 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1851 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1852 InitMouseEvent(win
, event
, gdk_event
);
1853 wxPoint pt
= win
->GetClientAreaOrigin();
1854 event
.m_x
= x
+ pt
.x
;
1855 event
.m_y
= y
+ pt
.y
;
1857 if ( !g_captureWindow
)
1859 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1860 if (win
->GTKProcessEvent( cevent
))
1862 win
->SetCursor( cevent
.GetCursor() );
1866 return win
->GTKProcessEvent(event
);
1869 //-----------------------------------------------------------------------------
1870 // "leave_notify_event"
1871 //-----------------------------------------------------------------------------
1874 gtk_window_leave_callback( GtkWidget
*widget
,
1875 GdkEventCrossing
*gdk_event
,
1878 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1880 // Event was emitted after an ungrab
1881 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1883 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1887 GdkModifierType state
= (GdkModifierType
)0;
1889 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1891 InitMouseEvent(win
, event
, gdk_event
);
1893 return win
->GTKProcessEvent(event
);
1896 //-----------------------------------------------------------------------------
1897 // "value_changed" from scrollbar
1898 //-----------------------------------------------------------------------------
1901 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
1903 wxEventType eventType
= win
->GetScrollEventType(range
);
1904 if (eventType
!= wxEVT_NULL
)
1906 // Convert scroll event type to scrollwin event type
1907 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
1909 // find the scrollbar which generated the event
1910 wxWindowGTK::ScrollDir dir
= win
->ScrollDirFromRange(range
);
1912 // generate the corresponding wx event
1913 const int orient
= wxWindow::OrientFromScrollDir(dir
);
1914 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
1915 event
.SetEventObject(win
);
1917 win
->GTKProcessEvent(event
);
1921 //-----------------------------------------------------------------------------
1922 // "button_press_event" from scrollbar
1923 //-----------------------------------------------------------------------------
1926 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
1930 g_blockEventsOnScroll
= true;
1931 win
->m_mouseButtonDown
= true;
1936 //-----------------------------------------------------------------------------
1937 // "event_after" from scrollbar
1938 //-----------------------------------------------------------------------------
1941 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
1943 if (event
->type
== GDK_BUTTON_RELEASE
)
1945 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1947 const int orient
= wxWindow::OrientFromScrollDir(
1948 win
->ScrollDirFromRange(range
));
1949 wxScrollWinEvent
evt(wxEVT_SCROLLWIN_THUMBRELEASE
,
1950 win
->GetScrollPos(orient
), orient
);
1951 evt
.SetEventObject(win
);
1952 win
->GTKProcessEvent(evt
);
1956 //-----------------------------------------------------------------------------
1957 // "button_release_event" from scrollbar
1958 //-----------------------------------------------------------------------------
1961 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
1965 g_blockEventsOnScroll
= false;
1966 win
->m_mouseButtonDown
= false;
1967 // If thumb tracking
1968 if (win
->m_isScrolling
)
1970 win
->m_isScrolling
= false;
1971 // Hook up handler to send thumb release event after this emission is finished.
1972 // To allow setting scroll position from event handler, sending event must
1973 // be deferred until after the GtkRange handler for this signal has run
1974 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1980 //-----------------------------------------------------------------------------
1981 // "realize" from m_widget
1982 //-----------------------------------------------------------------------------
1985 gtk_window_realized_callback(GtkWidget
* widget
, wxWindow
* win
)
1991 gtk_im_context_set_client_window( win
->m_imData
->context
,
1995 // We cannot set colours and fonts before the widget
1996 // been realized, so we do this directly after realization
1997 // or otherwise in idle time
1999 if (win
->m_needsStyleChange
)
2001 win
->SetBackgroundStyle(win
->GetBackgroundStyle());
2002 win
->m_needsStyleChange
= false;
2005 wxWindowCreateEvent
event( win
);
2006 event
.SetEventObject( win
);
2007 win
->GTKProcessEvent( event
);
2010 //-----------------------------------------------------------------------------
2011 // "size_allocate" from m_wxwindow or m_widget
2012 //-----------------------------------------------------------------------------
2015 size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxWindow
* win
)
2017 int w
= alloc
->width
;
2018 int h
= alloc
->height
;
2019 if (win
->m_wxwindow
)
2021 int border_x
, border_y
;
2022 WX_PIZZA(win
->m_wxwindow
)->get_border_widths(border_x
, border_y
);
2028 if (win
->m_oldClientWidth
!= w
|| win
->m_oldClientHeight
!= h
)
2030 win
->m_oldClientWidth
= w
;
2031 win
->m_oldClientHeight
= h
;
2032 // this callback can be connected to m_wxwindow,
2033 // so always get size from m_widget->allocation
2034 win
->m_width
= win
->m_widget
->allocation
.width
;
2035 win
->m_height
= win
->m_widget
->allocation
.height
;
2036 if (!win
->m_nativeSizeEvent
)
2038 wxSizeEvent
event(win
->GetSize(), win
->GetId());
2039 event
.SetEventObject(win
);
2040 win
->GTKProcessEvent(event
);
2045 //-----------------------------------------------------------------------------
2047 //-----------------------------------------------------------------------------
2049 #if GTK_CHECK_VERSION(2, 8, 0)
2051 gtk_window_grab_broken( GtkWidget
*,
2052 GdkEventGrabBroken
*event
,
2055 // Mouse capture has been lost involuntarily, notify the application
2056 if(!event
->keyboard
&& wxWindow::GetCapture() == win
)
2058 wxMouseCaptureLostEvent
evt( win
->GetId() );
2059 evt
.SetEventObject( win
);
2060 win
->GetEventHandler()->ProcessEvent( evt
);
2066 //-----------------------------------------------------------------------------
2068 //-----------------------------------------------------------------------------
2071 void gtk_window_style_set_callback( GtkWidget
*WXUNUSED(widget
),
2072 GtkStyle
*previous_style
,
2075 //wxLogDebug(wxT("gtk_window_style_set_callback"));
2076 if (win
&& previous_style
)
2078 wxString
name(win
->GetName());
2079 //wxLogDebug(wxT("gtk_window_style_set_callback %s"), name.c_str());
2080 wxSysColourChangedEvent event
;
2081 event
.SetEventObject(win
);
2083 win
->GTKProcessEvent( event
);
2089 // Connect/disconnect style-set
2091 void wxConnectStyleSet(wxWindow
* win
)
2093 if (win
->m_wxwindow
)
2094 g_signal_connect (win
->m_wxwindow
, "style_set",
2095 G_CALLBACK (gtk_window_style_set_callback
), win
);
2098 void wxDisconnectStyleSet(wxWindow
* win
)
2100 if (win
->m_wxwindow
)
2101 g_signal_handlers_disconnect_by_func (win
->m_wxwindow
,
2102 (gpointer
) gtk_window_style_set_callback
,
2106 // Helper to suspend colour change event event processing while we change a widget's style
2107 class wxSuspendStyleEvents
2110 wxSuspendStyleEvents(wxWindow
* win
)
2113 if (win
->IsTopLevel())
2114 wxDisconnectStyleSet(win
);
2116 ~wxSuspendStyleEvents()
2118 if (m_win
->IsTopLevel())
2119 wxConnectStyleSet(m_win
);
2125 // ----------------------------------------------------------------------------
2126 // this wxWindowBase function is implemented here (in platform-specific file)
2127 // because it is static and so couldn't be made virtual
2128 // ----------------------------------------------------------------------------
2130 wxWindow
*wxWindowBase::DoFindFocus()
2132 // the cast is necessary when we compile in wxUniversal mode
2133 return (wxWindow
*)g_focusWindow
;
2136 //-----------------------------------------------------------------------------
2137 // InsertChild for wxWindowGTK.
2138 //-----------------------------------------------------------------------------
2140 /* Callback for wxWindowGTK. This very strange beast has to be used because
2141 * C++ has no virtual methods in a constructor. We have to emulate a
2142 * virtual function here as wxNotebook requires a different way to insert
2143 * a child in it. I had opted for creating a wxNotebookPage window class
2144 * which would have made this superfluous (such in the MDI window system),
2145 * but no-one was listening to me... */
2147 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2149 /* the window might have been scrolled already, do we
2150 have to adapt the position */
2151 wxPizza
* pizza
= WX_PIZZA(parent
->m_wxwindow
);
2152 child
->m_x
+= pizza
->m_scroll_x
;
2153 child
->m_y
+= pizza
->m_scroll_y
;
2155 gtk_widget_set_size_request(
2156 child
->m_widget
, child
->m_width
, child
->m_height
);
2158 GTK_FIXED(parent
->m_wxwindow
), child
->m_widget
, child
->m_x
, child
->m_y
);
2161 //-----------------------------------------------------------------------------
2163 //-----------------------------------------------------------------------------
2165 wxWindow
*wxGetActiveWindow()
2167 return wxWindow::FindFocus();
2171 wxMouseState
wxGetMouseState()
2177 GdkModifierType mask
;
2179 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2183 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2184 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2185 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2186 ms
.SetAux1Down(mask
& GDK_BUTTON4_MASK
);
2187 ms
.SetAux2Down(mask
& GDK_BUTTON5_MASK
);
2189 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2190 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2191 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2192 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2197 //-----------------------------------------------------------------------------
2199 //-----------------------------------------------------------------------------
2201 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2203 #ifdef __WXUNIVERSAL__
2204 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2206 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2207 #endif // __WXUNIVERSAL__/__WXGTK__
2209 void wxWindowGTK::Init()
2212 m_widget
= (GtkWidget
*) NULL
;
2213 m_wxwindow
= (GtkWidget
*) NULL
;
2214 m_focusWidget
= (GtkWidget
*) NULL
;
2223 m_isBeingDeleted
= false;
2225 m_showOnIdle
= false;
2228 m_nativeSizeEvent
= false;
2230 m_hasScrolling
= false;
2231 m_isScrolling
= false;
2232 m_mouseButtonDown
= false;
2234 // initialize scrolling stuff
2235 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2237 m_scrollBar
[dir
] = NULL
;
2238 m_scrollPos
[dir
] = 0;
2242 m_oldClientHeight
= 0;
2244 m_insertCallback
= wxInsertChildInWindow
;
2248 m_clipPaintRegion
= false;
2250 m_needsStyleChange
= false;
2252 m_cursor
= *wxSTANDARD_CURSOR
;
2255 m_dirtyTabOrder
= false;
2258 wxWindowGTK::wxWindowGTK()
2263 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2268 const wxString
&name
)
2272 Create( parent
, id
, pos
, size
, style
, name
);
2275 bool wxWindowGTK::Create( wxWindow
*parent
,
2280 const wxString
&name
)
2282 if (!PreCreation( parent
, pos
, size
) ||
2283 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2285 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2289 m_wxwindow
= wxPizza::New(m_windowStyle
);
2290 if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
))
2291 m_widget
= m_wxwindow
;
2294 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2295 gtk_container_set_resize_mode(GTK_CONTAINER(m_widget
), GTK_RESIZE_QUEUE
);
2297 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2299 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2300 scroll_class
->scrollbar_spacing
= 0;
2302 // There is a conflict with default bindings at GTK+
2303 // level between scrolled windows and notebooks both of which want to use
2304 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2305 // direction and notebooks for changing pages -- we decide that if we don't
2306 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2307 // means we can get working keyboard navigation in notebooks
2308 if ( !HasFlag(wxHSCROLL
) )
2311 bindings
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
));
2314 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
);
2315 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
);
2319 if (HasFlag(wxALWAYS_SHOW_SB
))
2321 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
2323 scrolledWindow
->hscrollbar_visible
= TRUE
;
2324 scrolledWindow
->vscrollbar_visible
= TRUE
;
2328 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2331 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2332 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2333 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2334 gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE
);
2336 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2338 // connect various scroll-related events
2339 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2341 // these handlers block mouse events to any window during scrolling
2342 // such as motion events and prevent GTK and wxWidgets from fighting
2343 // over where the slider should be
2344 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2345 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2346 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2347 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2349 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2350 G_CALLBACK(gtk_scrollbar_event_after
), this);
2351 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2353 // these handlers get notified when scrollbar slider moves
2354 g_signal_connect_after(m_scrollBar
[dir
], "value_changed",
2355 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2358 gtk_widget_show( m_wxwindow
);
2362 m_parent
->DoAddChild( this );
2364 m_focusWidget
= m_wxwindow
;
2371 wxWindowGTK::~wxWindowGTK()
2375 if (g_focusWindow
== this)
2376 g_focusWindow
= NULL
;
2378 if ( g_delayedFocus
== this )
2379 g_delayedFocus
= NULL
;
2381 m_isBeingDeleted
= true;
2384 // destroy children before destroying this window itself
2387 // unhook focus handlers to prevent stray events being
2388 // propagated to this (soon to be) dead object
2389 if (m_focusWidget
!= NULL
)
2391 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2392 (gpointer
) gtk_window_focus_in_callback
,
2394 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2395 (gpointer
) gtk_window_focus_out_callback
,
2402 // delete before the widgets to avoid a crash on solaris
2405 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2407 gtk_widget_destroy( m_wxwindow
);
2408 m_wxwindow
= (GtkWidget
*) NULL
;
2413 gtk_widget_destroy( m_widget
);
2414 m_widget
= (GtkWidget
*) NULL
;
2418 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2420 if ( GTKNeedsParent() )
2422 wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") );
2425 // Use either the given size, or the default if -1 is given.
2426 // See wxWindowBase for these functions.
2427 m_width
= WidthDefault(size
.x
) ;
2428 m_height
= HeightDefault(size
.y
);
2436 void wxWindowGTK::PostCreation()
2438 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2444 // these get reported to wxWidgets -> wxPaintEvent
2446 g_signal_connect (m_wxwindow
, "expose_event",
2447 G_CALLBACK (gtk_window_expose_callback
), this);
2449 if (GetLayoutDirection() == wxLayout_LeftToRight
)
2450 gtk_widget_set_redraw_on_allocate(m_wxwindow
, HasFlag(wxFULL_REPAINT_ON_RESIZE
));
2453 // Create input method handler
2454 m_imData
= new wxGtkIMData
;
2456 // Cannot handle drawing preedited text yet
2457 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2459 g_signal_connect (m_imData
->context
, "commit",
2460 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2463 #ifndef __WXUNIVERSAL__
2464 if (HasFlag(wxBORDER_SIMPLE
| wxBORDER_RAISED
| wxBORDER_SUNKEN
))
2466 g_signal_connect(m_widget
, "expose_event",
2467 G_CALLBACK(expose_event_border
), this);
2474 if (!GTK_IS_WINDOW(m_widget
))
2476 if (m_focusWidget
== NULL
)
2477 m_focusWidget
= m_widget
;
2481 g_signal_connect (m_focusWidget
, "focus_in_event",
2482 G_CALLBACK (gtk_window_focus_in_callback
), this);
2483 g_signal_connect (m_focusWidget
, "focus_out_event",
2484 G_CALLBACK (gtk_window_focus_out_callback
), this);
2488 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2489 G_CALLBACK (gtk_window_focus_in_callback
), this);
2490 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2491 G_CALLBACK (gtk_window_focus_out_callback
), this);
2495 if ( !AcceptsFocusFromKeyboard() )
2499 g_signal_connect(m_widget
, "focus",
2500 G_CALLBACK(wx_window_focus_callback
), this);
2503 // connect to the various key and mouse handlers
2505 GtkWidget
*connect_widget
= GetConnectWidget();
2507 ConnectWidget( connect_widget
);
2509 /* We cannot set colours, fonts and cursors before the widget has
2510 been realized, so we do this directly after realization */
2511 g_signal_connect (connect_widget
, "realize",
2512 G_CALLBACK (gtk_window_realized_callback
), this);
2516 g_signal_connect(m_wxwindow
? m_wxwindow
: m_widget
, "size_allocate",
2517 G_CALLBACK(size_allocate
), this);
2522 #if GTK_CHECK_VERSION(2, 8, 0)
2523 if (!gtk_check_version(2,8,0))
2525 // Make sure we can notify the app when mouse capture is lost
2526 g_signal_connect (m_wxwindow
, "grab_broken_event",
2527 G_CALLBACK (gtk_window_grab_broken
), this);
2532 if ( connect_widget
!= m_wxwindow
)
2534 #if GTK_CHECK_VERSION(2, 8, 0)
2535 if (!gtk_check_version(2,8,0))
2537 // Make sure we can notify app code when mouse capture is lost
2538 g_signal_connect (connect_widget
, "grab_broken_event",
2539 G_CALLBACK (gtk_window_grab_broken
), this);
2545 if (GTK_IS_COMBO(m_widget
))
2547 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2549 g_signal_connect (gcombo
->entry
, "size_request",
2550 G_CALLBACK (wxgtk_combo_size_request_callback
),
2553 #endif // wxUSE_COMBOBOX
2554 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2555 if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2557 // If we connect to the "size_request" signal of a GtkFileChooserButton
2558 // then that control won't be sized properly when placed inside sizers
2559 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2560 // FIXME: what should be done here ?
2563 if ( !IsTopLevel() ) // top level windows use their own callback
2565 // This is needed if we want to add our windows into native
2566 // GTK controls, such as the toolbar. With this callback, the
2567 // toolbar gets to know the correct size (the one set by the
2568 // programmer). Sadly, it misbehaves for wxComboBox.
2569 g_signal_connect (m_widget
, "size_request",
2570 G_CALLBACK (wxgtk_window_size_request_callback
),
2574 InheritAttributes();
2578 SetLayoutDirection(wxLayout_Default
);
2580 // unless the window was created initially hidden (i.e. Hide() had been
2581 // called before Create()), we should show it at GTK+ level as well
2583 gtk_widget_show( m_widget
);
2586 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2588 g_signal_connect (widget
, "key_press_event",
2589 G_CALLBACK (gtk_window_key_press_callback
), this);
2590 g_signal_connect (widget
, "key_release_event",
2591 G_CALLBACK (gtk_window_key_release_callback
), this);
2592 g_signal_connect (widget
, "button_press_event",
2593 G_CALLBACK (gtk_window_button_press_callback
), this);
2594 g_signal_connect (widget
, "button_release_event",
2595 G_CALLBACK (gtk_window_button_release_callback
), this);
2596 g_signal_connect (widget
, "motion_notify_event",
2597 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2598 g_signal_connect (widget
, "scroll_event",
2599 G_CALLBACK (window_scroll_event
), this);
2600 g_signal_connect (widget
, "popup_menu",
2601 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2602 g_signal_connect (widget
, "enter_notify_event",
2603 G_CALLBACK (gtk_window_enter_callback
), this);
2604 g_signal_connect (widget
, "leave_notify_event",
2605 G_CALLBACK (gtk_window_leave_callback
), this);
2607 if (IsTopLevel() && m_wxwindow
)
2608 g_signal_connect (m_wxwindow
, "style_set",
2609 G_CALLBACK (gtk_window_style_set_callback
), this);
2612 bool wxWindowGTK::Destroy()
2614 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2618 return wxWindowBase::Destroy();
2621 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2623 gtk_widget_set_size_request(m_widget
, width
, height
);
2624 // inform the parent to perform the move
2625 WX_PIZZA(m_parent
->m_wxwindow
)->move(m_widget
, x
, y
);
2628 void wxWindowGTK::ConstrainSize()
2631 // GPE's window manager doesn't like size hints at all, esp. when the user
2632 // has to use the virtual keyboard, so don't constrain size there
2636 const wxSize minSize
= GetMinSize();
2637 const wxSize maxSize
= GetMaxSize();
2638 if (minSize
.x
> 0 && m_width
< minSize
.x
) m_width
= minSize
.x
;
2639 if (minSize
.y
> 0 && m_height
< minSize
.y
) m_height
= minSize
.y
;
2640 if (maxSize
.x
> 0 && m_width
> maxSize
.x
) m_width
= maxSize
.x
;
2641 if (maxSize
.y
> 0 && m_height
> maxSize
.y
) m_height
= maxSize
.y
;
2645 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2647 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2648 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2650 int currentX
, currentY
;
2651 GetPosition(¤tX
, ¤tY
);
2652 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2654 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2656 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2658 // calculate the best size if we should auto size the window
2659 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2660 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2662 const wxSize sizeBest
= GetBestSize();
2663 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2665 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2666 height
= sizeBest
.y
;
2669 const wxSize
oldSize(m_width
, m_height
);
2677 if (m_parent
->m_wxwindow
)
2679 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2680 m_x
= x
+ pizza
->m_scroll_x
;
2681 m_y
= y
+ pizza
->m_scroll_y
;
2683 int left_border
= 0;
2684 int right_border
= 0;
2686 int bottom_border
= 0;
2688 /* the default button has a border around it */
2689 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2691 GtkBorder
*default_border
= NULL
;
2692 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2695 left_border
+= default_border
->left
;
2696 right_border
+= default_border
->right
;
2697 top_border
+= default_border
->top
;
2698 bottom_border
+= default_border
->bottom
;
2699 gtk_border_free( default_border
);
2703 DoMoveWindow( m_x
- left_border
,
2705 m_width
+left_border
+right_border
,
2706 m_height
+top_border
+bottom_border
);
2709 if (m_width
!= oldSize
.x
|| m_height
!= oldSize
.y
)
2711 // update these variables to keep size_allocate handler
2712 // from sending another size event for this change
2713 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2715 gtk_widget_queue_resize(m_widget
);
2716 if (!m_nativeSizeEvent
)
2718 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2719 event
.SetEventObject( this );
2720 GetEventHandler()->ProcessEvent( event
);
2725 bool wxWindowGTK::GtkShowFromOnIdle()
2727 if (IsShown() && m_showOnIdle
&& !GTK_WIDGET_VISIBLE (m_widget
))
2729 GtkAllocation alloc
;
2732 alloc
.width
= m_width
;
2733 alloc
.height
= m_height
;
2734 gtk_widget_size_allocate( m_widget
, &alloc
);
2735 gtk_widget_show( m_widget
);
2736 wxShowEvent
eventShow(GetId(), true);
2737 eventShow
.SetEventObject(this);
2738 GetEventHandler()->ProcessEvent(eventShow
);
2739 m_showOnIdle
= false;
2746 void wxWindowGTK::OnInternalIdle()
2748 // Check if we have to show window now
2749 if (GtkShowFromOnIdle()) return;
2751 if ( m_dirtyTabOrder
)
2753 m_dirtyTabOrder
= false;
2757 // Update style if the window was not yet realized
2758 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2759 if (m_needsStyleChange
)
2761 SetBackgroundStyle(GetBackgroundStyle());
2762 m_needsStyleChange
= false;
2765 wxCursor cursor
= m_cursor
;
2766 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2770 /* I now set the cursor anew in every OnInternalIdle call
2771 as setting the cursor in a parent window also effects the
2772 windows above so that checking for the current cursor is
2775 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2777 GdkWindow
*window
= m_wxwindow
->window
;
2779 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2781 if (!g_globalCursor
.Ok())
2782 cursor
= *wxSTANDARD_CURSOR
;
2784 window
= m_widget
->window
;
2785 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2786 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2789 else if ( m_widget
)
2791 GdkWindow
*window
= m_widget
->window
;
2792 if ( window
&& !GTK_WIDGET_NO_WINDOW(m_widget
) )
2793 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2797 if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
2798 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2801 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2803 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2805 if (width
) (*width
) = m_width
;
2806 if (height
) (*height
) = m_height
;
2809 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2811 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2813 const wxSize size
= GetSize();
2814 const wxSize clientSize
= GetClientSize();
2815 SetSize(width
+ (size
.x
- clientSize
.x
), height
+ (size
.y
- clientSize
.y
));
2818 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2820 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2831 GetScrollbarWidth(m_widget
, dw
, dh
);
2833 int border_x
, border_y
;
2834 WX_PIZZA(m_wxwindow
)->get_border_widths(border_x
, border_y
);
2846 if (width
) *width
= w
;
2847 if (height
) *height
= h
;
2850 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2852 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2856 if (!IsTopLevel() && m_parent
&& m_parent
->m_wxwindow
)
2858 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2859 dx
= pizza
->m_scroll_x
;
2860 dy
= pizza
->m_scroll_y
;
2863 if (m_x
== -1 && m_y
== -1)
2865 GdkWindow
*source
= (GdkWindow
*) NULL
;
2867 source
= m_wxwindow
->window
;
2869 source
= m_widget
->window
;
2875 gdk_window_get_origin( source
, &org_x
, &org_y
);
2878 m_parent
->ScreenToClient(&org_x
, &org_y
);
2880 wx_const_cast(wxWindowGTK
*, this)->m_x
= org_x
;
2881 wx_const_cast(wxWindowGTK
*, this)->m_y
= org_y
;
2885 if (x
) (*x
) = m_x
- dx
;
2886 if (y
) (*y
) = m_y
- dy
;
2889 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2891 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2893 if (!m_widget
->window
) return;
2895 GdkWindow
*source
= (GdkWindow
*) NULL
;
2897 source
= m_wxwindow
->window
;
2899 source
= m_widget
->window
;
2903 gdk_window_get_origin( source
, &org_x
, &org_y
);
2907 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2909 org_x
+= m_widget
->allocation
.x
;
2910 org_y
+= m_widget
->allocation
.y
;
2917 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2918 *x
= (GetClientSize().x
- *x
) + org_x
;
2926 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
2928 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2930 if (!m_widget
->window
) return;
2932 GdkWindow
*source
= (GdkWindow
*) NULL
;
2934 source
= m_wxwindow
->window
;
2936 source
= m_widget
->window
;
2940 gdk_window_get_origin( source
, &org_x
, &org_y
);
2944 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2946 org_x
+= m_widget
->allocation
.x
;
2947 org_y
+= m_widget
->allocation
.y
;
2953 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2954 *x
= (GetClientSize().x
- *x
) - org_x
;
2961 bool wxWindowGTK::Show( bool show
)
2963 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
2965 if (!wxWindowBase::Show(show
))
2975 gtk_widget_show( m_widget
);
2976 wxShowEvent
eventShow(GetId(), show
);
2977 eventShow
.SetEventObject(this);
2978 GetEventHandler()->ProcessEvent(eventShow
);
2983 gtk_widget_hide( m_widget
);
2984 wxShowEvent
eventShow(GetId(), show
);
2985 eventShow
.SetEventObject(this);
2986 GetEventHandler()->ProcessEvent(eventShow
);
2992 void wxWindowGTK::DoEnable( bool enable
)
2994 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2996 gtk_widget_set_sensitive( m_widget
, enable
);
2997 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2998 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3001 int wxWindowGTK::GetCharHeight() const
3003 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3005 wxFont font
= GetFont();
3006 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3008 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
3013 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3014 PangoLayout
*layout
= pango_layout_new(context
);
3015 pango_layout_set_font_description(layout
, desc
);
3016 pango_layout_set_text(layout
, "H", 1);
3017 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3019 PangoRectangle rect
;
3020 pango_layout_line_get_extents(line
, NULL
, &rect
);
3022 g_object_unref (layout
);
3024 return (int) PANGO_PIXELS(rect
.height
);
3027 int wxWindowGTK::GetCharWidth() const
3029 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3031 wxFont font
= GetFont();
3032 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3034 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
3039 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3040 PangoLayout
*layout
= pango_layout_new(context
);
3041 pango_layout_set_font_description(layout
, desc
);
3042 pango_layout_set_text(layout
, "g", 1);
3043 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3045 PangoRectangle rect
;
3046 pango_layout_line_get_extents(line
, NULL
, &rect
);
3048 g_object_unref (layout
);
3050 return (int) PANGO_PIXELS(rect
.width
);
3053 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3057 int *externalLeading
,
3058 const wxFont
*theFont
) const
3060 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3062 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3071 PangoContext
*context
= NULL
;
3073 context
= gtk_widget_get_pango_context( m_widget
);
3082 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3083 PangoLayout
*layout
= pango_layout_new(context
);
3084 pango_layout_set_font_description(layout
, desc
);
3086 const wxCharBuffer data
= wxGTK_CONV( string
);
3088 pango_layout_set_text(layout
, data
, strlen(data
));
3091 PangoRectangle rect
;
3092 pango_layout_get_extents(layout
, NULL
, &rect
);
3094 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3095 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3098 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3099 int baseline
= pango_layout_iter_get_baseline(iter
);
3100 pango_layout_iter_free(iter
);
3101 *descent
= *y
- PANGO_PIXELS(baseline
);
3103 if (externalLeading
) (*externalLeading
) = 0; // ??
3105 g_object_unref (layout
);
3108 bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
3110 if ( g_delayedFocus
== this )
3112 if ( GTK_WIDGET_REALIZED(m_widget
) )
3114 gtk_widget_grab_focus(m_widget
);
3115 g_delayedFocus
= NULL
;
3124 void wxWindowGTK::SetFocus()
3126 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3129 // don't do anything if we already have focus
3135 // wxWindow::SetFocus() should really set the focus to
3136 // this control, whatever the flags are
3137 if (!GTK_WIDGET_CAN_FOCUS(m_wxwindow
))
3138 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3140 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3142 gtk_widget_grab_focus (m_wxwindow
);
3147 // wxWindow::SetFocus() should really set the focus to
3148 // this control, whatever the flags are
3149 if (!GTK_WIDGET_CAN_FOCUS(m_widget
))
3150 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3152 if (GTK_IS_CONTAINER(m_widget
))
3154 if (GTK_IS_RADIO_BUTTON(m_widget
))
3156 gtk_widget_grab_focus (m_widget
);
3160 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3163 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3166 if (!GTK_WIDGET_REALIZED(m_widget
))
3168 // we can't set the focus to the widget now so we remember that
3169 // it should be focused and will do it later, during the idle
3170 // time, as soon as we can
3171 wxLogTrace(TRACE_FOCUS
,
3172 _T("Delaying setting focus to %s(%s)"),
3173 GetClassInfo()->GetClassName(), GetLabel().c_str());
3175 g_delayedFocus
= this;
3179 wxLogTrace(TRACE_FOCUS
,
3180 _T("Setting focus to %s(%s)"),
3181 GetClassInfo()->GetClassName(), GetLabel().c_str());
3183 gtk_widget_grab_focus (m_widget
);
3188 wxLogTrace(TRACE_FOCUS
,
3189 _T("Can't set focus to %s(%s)"),
3190 GetClassInfo()->GetClassName(), GetLabel().c_str());
3195 void wxWindowGTK::SetCanFocus(bool canFocus
)
3198 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3200 GTK_WIDGET_UNSET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3202 if ( m_wxwindow
&& (m_widget
!= m_wxwindow
) )
3205 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3207 GTK_WIDGET_UNSET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3211 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3213 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3215 wxWindowGTK
*oldParent
= m_parent
,
3216 *newParent
= (wxWindowGTK
*)newParentBase
;
3218 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3220 if ( !wxWindowBase::Reparent(newParent
) )
3223 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3225 /* prevent GTK from deleting the widget arbitrarily */
3226 gtk_widget_ref( m_widget
);
3230 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3233 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3237 if (GTK_WIDGET_VISIBLE (newParent
->m_widget
))
3239 m_showOnIdle
= true;
3240 gtk_widget_hide( m_widget
);
3243 /* insert GTK representation */
3244 (*(newParent
->m_insertCallback
))(newParent
, this);
3247 /* reverse: prevent GTK from deleting the widget arbitrarily */
3248 gtk_widget_unref( m_widget
);
3250 SetLayoutDirection(wxLayout_Default
);
3255 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3257 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3258 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3263 /* insert GTK representation */
3264 (*m_insertCallback
)(this, child
);
3267 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3269 wxWindowBase::AddChild(child
);
3270 m_dirtyTabOrder
= true;
3271 wxTheApp
->WakeUpIdle();
3274 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3276 wxWindowBase::RemoveChild(child
);
3277 m_dirtyTabOrder
= true;
3278 wxTheApp
->WakeUpIdle();
3282 wxLayoutDirection
wxWindowGTK::GTKGetLayout(GtkWidget
*widget
)
3284 return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
3285 ? wxLayout_RightToLeft
3286 : wxLayout_LeftToRight
;
3290 void wxWindowGTK::GTKSetLayout(GtkWidget
*widget
, wxLayoutDirection dir
)
3292 wxASSERT_MSG( dir
!= wxLayout_Default
, _T("invalid layout direction") );
3294 gtk_widget_set_direction(widget
,
3295 dir
== wxLayout_RightToLeft
? GTK_TEXT_DIR_RTL
3296 : GTK_TEXT_DIR_LTR
);
3299 wxLayoutDirection
wxWindowGTK::GetLayoutDirection() const
3301 return GTKGetLayout(m_widget
);
3304 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
)
3306 if ( dir
== wxLayout_Default
)
3308 const wxWindow
*const parent
= GetParent();
3311 // inherit layout from parent.
3312 dir
= parent
->GetLayoutDirection();
3314 else // no parent, use global default layout
3316 dir
= wxTheApp
->GetLayoutDirection();
3320 if ( dir
== wxLayout_Default
)
3323 GTKSetLayout(m_widget
, dir
);
3325 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3326 GTKSetLayout(m_wxwindow
, dir
);
3330 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
,
3331 wxCoord
WXUNUSED(width
),
3332 wxCoord
WXUNUSED(widthTotal
)) const
3334 // We now mirror the coordinates of RTL windows in wxPizza
3338 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3340 wxWindowBase::DoMoveInTabOrder(win
, move
);
3341 m_dirtyTabOrder
= true;
3342 wxTheApp
->WakeUpIdle();
3345 bool wxWindowGTK::DoNavigateIn(int flags
)
3347 if ( flags
& wxNavigationKeyEvent::WinChange
)
3349 wxFAIL_MSG( _T("not implemented") );
3353 else // navigate inside the container
3355 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3356 wxCHECK_MSG( parent
, false, _T("every window must have a TLW parent") );
3358 GtkDirectionType dir
;
3359 dir
= flags
& wxNavigationKeyEvent::IsForward
? GTK_DIR_TAB_FORWARD
3360 : GTK_DIR_TAB_BACKWARD
;
3363 g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
);
3369 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3371 // none needed by default
3375 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3377 // nothing to do by default since none is needed
3380 void wxWindowGTK::RealizeTabOrder()
3384 if ( !m_children
.empty() )
3386 // we don't only construct the correct focus chain but also use
3387 // this opportunity to update the mnemonic widgets for the widgets
3390 GList
*chain
= NULL
;
3391 wxWindowGTK
* mnemonicWindow
= NULL
;
3393 for ( wxWindowList::const_iterator i
= m_children
.begin();
3394 i
!= m_children
.end();
3397 wxWindowGTK
*win
= *i
;
3399 if ( mnemonicWindow
)
3401 if ( win
->AcceptsFocusFromKeyboard() )
3403 // wxComboBox et al. needs to focus on on a different
3404 // widget than m_widget, so if the main widget isn't
3405 // focusable try the connect widget
3406 GtkWidget
* w
= win
->m_widget
;
3407 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3409 w
= win
->GetConnectWidget();
3410 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3416 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3417 mnemonicWindow
= NULL
;
3421 else if ( win
->GTKWidgetNeedsMnemonic() )
3423 mnemonicWindow
= win
;
3426 chain
= g_list_prepend(chain
, win
->m_widget
);
3429 chain
= g_list_reverse(chain
);
3431 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3436 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3441 void wxWindowGTK::Raise()
3443 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3445 if (m_wxwindow
&& m_wxwindow
->window
)
3447 gdk_window_raise( m_wxwindow
->window
);
3449 else if (m_widget
->window
)
3451 gdk_window_raise( m_widget
->window
);
3455 void wxWindowGTK::Lower()
3457 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3459 if (m_wxwindow
&& m_wxwindow
->window
)
3461 gdk_window_lower( m_wxwindow
->window
);
3463 else if (m_widget
->window
)
3465 gdk_window_lower( m_widget
->window
);
3469 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3471 if ( !wxWindowBase::SetCursor(cursor
.Ok() ? cursor
: *wxSTANDARD_CURSOR
) )
3479 void wxWindowGTK::GTKUpdateCursor()
3481 wxCursor
cursor(g_globalCursor
.Ok() ? g_globalCursor
: GetCursor());
3484 wxArrayGdkWindows windowsThis
;
3485 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3488 gdk_window_set_cursor(winThis
, cursor
.GetCursor());
3492 const size_t count
= windowsThis
.size();
3493 for ( size_t n
= 0; n
< count
; n
++ )
3495 GdkWindow
*win
= windowsThis
[n
];
3498 wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?"));
3502 gdk_window_set_cursor(win
, cursor
.GetCursor());
3508 void wxWindowGTK::WarpPointer( int x
, int y
)
3510 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3512 // We provide this function ourselves as it is
3513 // missing in GDK (top of this file).
3515 GdkWindow
*window
= (GdkWindow
*) NULL
;
3517 window
= m_wxwindow
->window
;
3519 window
= GetConnectWidget()->window
;
3522 gdk_window_warp_pointer( window
, x
, y
);
3525 wxWindowGTK::ScrollDir
wxWindowGTK::ScrollDirFromRange(GtkRange
*range
) const
3527 // find the scrollbar which generated the event
3528 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3530 if ( range
== m_scrollBar
[dir
] )
3531 return (ScrollDir
)dir
;
3534 wxFAIL_MSG( _T("event from unknown scrollbar received") );
3536 return ScrollDir_Max
;
3539 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3541 bool changed
= false;
3542 GtkRange
* range
= m_scrollBar
[dir
];
3543 if ( range
&& units
)
3545 GtkAdjustment
* adj
= range
->adjustment
;
3546 gdouble inc
= unit
== ScrollUnit_Line
? adj
->step_increment
3547 : adj
->page_increment
;
3549 const int posOld
= int(adj
->value
+ 0.5);
3550 gtk_range_set_value(range
, posOld
+ units
*inc
);
3552 changed
= int(adj
->value
+ 0.5) != posOld
;
3558 bool wxWindowGTK::ScrollLines(int lines
)
3560 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3563 bool wxWindowGTK::ScrollPages(int pages
)
3565 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3568 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground
),
3573 if (!m_widget
->window
)
3578 if (m_wxwindow
->window
== NULL
) return;
3580 GdkRectangle gdk_rect
,
3584 gdk_rect
.x
= rect
->x
;
3585 gdk_rect
.y
= rect
->y
;
3586 gdk_rect
.width
= rect
->width
;
3587 gdk_rect
.height
= rect
->height
;
3588 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3589 gdk_rect
.x
= GetClientSize().x
- gdk_rect
.x
- gdk_rect
.width
;
3593 else // invalidate everything
3598 gdk_window_invalidate_rect(m_wxwindow
->window
, p
, true);
3602 void wxWindowGTK::Update()
3606 // when we call Update() we really want to update the window immediately on
3607 // screen, even if it means flushing the entire queue and hence slowing down
3608 // everything -- but it should still be done, it's just that Update() should
3609 // be called very rarely
3613 void wxWindowGTK::GtkUpdate()
3615 if (m_wxwindow
&& m_wxwindow
->window
)
3616 gdk_window_process_updates(m_wxwindow
->window
, false);
3617 if (m_widget
&& m_widget
->window
&& (m_wxwindow
!= m_widget
))
3618 gdk_window_process_updates( m_widget
->window
, FALSE
);
3620 // for consistency with other platforms (and also because it's convenient
3621 // to be able to update an entire TLW by calling Update() only once), we
3622 // should also update all our children here
3623 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3625 node
= node
->GetNext() )
3627 node
->GetData()->GtkUpdate();
3631 bool wxWindowGTK::DoIsExposed( int x
, int y
) const
3633 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
3637 bool wxWindowGTK::DoIsExposed( int x
, int y
, int w
, int h
) const
3639 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3640 return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
;
3642 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
3645 void wxWindowGTK::GtkSendPaintEvents()
3649 m_updateRegion
.Clear();
3653 // Clip to paint region in wxClientDC
3654 m_clipPaintRegion
= true;
3656 m_nativeUpdateRegion
= m_updateRegion
;
3658 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3660 // Transform m_updateRegion under RTL
3661 m_updateRegion
.Clear();
3664 gdk_drawable_get_size(m_wxwindow
->window
, &width
, NULL
);
3666 wxRegionIterator
upd( m_nativeUpdateRegion
);
3670 rect
.x
= upd
.GetX();
3671 rect
.y
= upd
.GetY();
3672 rect
.width
= upd
.GetWidth();
3673 rect
.height
= upd
.GetHeight();
3675 rect
.x
= width
- rect
.x
- rect
.width
;
3676 m_updateRegion
.Union( rect
);
3682 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3684 // find ancestor from which to steal background
3685 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3687 parent
= (wxWindow
*)this;
3689 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3691 wxRegionIterator
upd( m_nativeUpdateRegion
);
3695 rect
.x
= upd
.GetX();
3696 rect
.y
= upd
.GetY();
3697 rect
.width
= upd
.GetWidth();
3698 rect
.height
= upd
.GetHeight();
3700 gtk_paint_flat_box( parent
->m_widget
->style
,
3702 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3715 wxWindowDC
dc( (wxWindow
*)this );
3716 dc
.SetClippingRegion( m_updateRegion
);
3718 // Work around gtk-qt <= 0.60 bug whereby the window colour
3720 if (GetBackgroundStyle() == wxBG_STYLE_COLOUR
&& GetBackgroundColour().Ok() && wxSystemOptions::GetOptionInt(wxT("gtk.window.force-background-colour")) == 1)
3722 dc
.SetBackground(wxBrush(GetBackgroundColour()));
3726 wxEraseEvent
erase_event( GetId(), &dc
);
3727 erase_event
.SetEventObject( this );
3729 GetEventHandler()->ProcessEvent(erase_event
);
3732 wxNcPaintEvent
nc_paint_event( GetId() );
3733 nc_paint_event
.SetEventObject( this );
3734 GetEventHandler()->ProcessEvent( nc_paint_event
);
3736 wxPaintEvent
paint_event( GetId() );
3737 paint_event
.SetEventObject( this );
3738 GetEventHandler()->ProcessEvent( paint_event
);
3740 m_clipPaintRegion
= false;
3742 m_updateRegion
.Clear();
3743 m_nativeUpdateRegion
.Clear();
3746 void wxWindowGTK::SetDoubleBuffered( bool on
)
3748 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3751 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3754 bool wxWindowGTK::IsDoubleBuffered() const
3756 return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow
);
3759 void wxWindowGTK::ClearBackground()
3761 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3765 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3767 wxWindowBase::DoSetToolTip(tip
);
3770 m_tooltip
->Apply( (wxWindow
*)this );
3773 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const gchar
*tip
)
3775 gtk_tooltips_set_tip(tips
, GetConnectWidget(), tip
, NULL
);
3777 #endif // wxUSE_TOOLTIPS
3779 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3781 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3783 if (!wxWindowBase::SetBackgroundColour(colour
))
3788 // We need the pixel value e.g. for background clearing.
3789 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3792 // apply style change (forceStyle=true so that new style is applied
3793 // even if the bg colour changed from valid to wxNullColour)
3794 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3795 ApplyWidgetStyle(true);
3800 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3802 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3804 if (!wxWindowBase::SetForegroundColour(colour
))
3811 // We need the pixel value e.g. for background clearing.
3812 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3815 // apply style change (forceStyle=true so that new style is applied
3816 // even if the bg colour changed from valid to wxNullColour):
3817 ApplyWidgetStyle(true);
3822 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3824 return gtk_widget_get_pango_context( m_widget
);
3827 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3829 // do we need to apply any changes at all?
3832 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3837 GtkRcStyle
*style
= gtk_rc_style_new();
3842 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3845 int flagsNormal
= 0,
3848 flagsInsensitive
= 0;
3850 if ( m_foregroundColour
.Ok() )
3852 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3854 style
->fg
[GTK_STATE_NORMAL
] =
3855 style
->text
[GTK_STATE_NORMAL
] = *fg
;
3856 flagsNormal
|= GTK_RC_FG
| GTK_RC_TEXT
;
3858 style
->fg
[GTK_STATE_PRELIGHT
] =
3859 style
->text
[GTK_STATE_PRELIGHT
] = *fg
;
3860 flagsPrelight
|= GTK_RC_FG
| GTK_RC_TEXT
;
3862 style
->fg
[GTK_STATE_ACTIVE
] =
3863 style
->text
[GTK_STATE_ACTIVE
] = *fg
;
3864 flagsActive
|= GTK_RC_FG
| GTK_RC_TEXT
;
3867 if ( m_backgroundColour
.Ok() )
3869 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3871 style
->bg
[GTK_STATE_NORMAL
] =
3872 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3873 flagsNormal
|= GTK_RC_BG
| GTK_RC_BASE
;
3875 style
->bg
[GTK_STATE_PRELIGHT
] =
3876 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3877 flagsPrelight
|= GTK_RC_BG
| GTK_RC_BASE
;
3879 style
->bg
[GTK_STATE_ACTIVE
] =
3880 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3881 flagsActive
|= GTK_RC_BG
| GTK_RC_BASE
;
3883 style
->bg
[GTK_STATE_INSENSITIVE
] =
3884 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3885 flagsInsensitive
|= GTK_RC_BG
| GTK_RC_BASE
;
3888 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
;
3889 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
;
3890 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
;
3891 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
;
3896 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3898 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3901 DoApplyWidgetStyle(style
);
3902 gtk_rc_style_unref(style
);
3905 // Style change may affect GTK+'s size calculation:
3906 InvalidateBestSize();
3909 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3911 wxSuspendStyleEvents
s(static_cast<wxWindow
*>(this));
3914 gtk_widget_modify_style(m_wxwindow
, style
);
3916 gtk_widget_modify_style(m_widget
, style
);
3919 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3921 wxWindowBase::SetBackgroundStyle(style
);
3923 if (style
== wxBG_STYLE_CUSTOM
)
3928 window
= m_wxwindow
->window
;
3932 GtkWidget
* const w
= GetConnectWidget();
3933 window
= w
? w
->window
: NULL
;
3938 // Make sure GDK/X11 doesn't refresh the window
3940 gdk_window_set_back_pixmap( window
, None
, False
);
3942 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3945 m_needsStyleChange
= false;
3947 else // window not realized yet
3949 // Do in OnIdle, because the window is not yet available
3950 m_needsStyleChange
= true;
3953 // Don't apply widget style, or we get a grey background
3957 // apply style change (forceStyle=true so that new style is applied
3958 // even if the bg colour changed from valid to wxNullColour):
3959 ApplyWidgetStyle(true);
3964 #if wxUSE_DRAG_AND_DROP
3966 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3968 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3970 GtkWidget
*dnd_widget
= GetConnectWidget();
3972 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3974 if (m_dropTarget
) delete m_dropTarget
;
3975 m_dropTarget
= dropTarget
;
3977 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3980 #endif // wxUSE_DRAG_AND_DROP
3982 GtkWidget
* wxWindowGTK::GetConnectWidget()
3984 GtkWidget
*connect_widget
= m_widget
;
3985 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3987 return connect_widget
;
3990 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow
*window
) const
3992 wxArrayGdkWindows windowsThis
;
3993 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3995 return winThis
? window
== winThis
3996 : windowsThis
.Index(window
) != wxNOT_FOUND
;
3999 GdkWindow
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
4001 return m_wxwindow
? m_wxwindow
->window
: m_widget
->window
;
4004 bool wxWindowGTK::SetFont( const wxFont
&font
)
4006 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4008 if (!wxWindowBase::SetFont(font
))
4011 // apply style change (forceStyle=true so that new style is applied
4012 // even if the font changed from valid to wxNullFont):
4013 ApplyWidgetStyle(true);
4018 void wxWindowGTK::DoCaptureMouse()
4020 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4022 GdkWindow
*window
= (GdkWindow
*) NULL
;
4024 window
= m_wxwindow
->window
;
4026 window
= GetConnectWidget()->window
;
4028 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4030 const wxCursor
* cursor
= &m_cursor
;
4032 cursor
= wxSTANDARD_CURSOR
;
4034 gdk_pointer_grab( window
, FALSE
,
4036 (GDK_BUTTON_PRESS_MASK
|
4037 GDK_BUTTON_RELEASE_MASK
|
4038 GDK_POINTER_MOTION_HINT_MASK
|
4039 GDK_POINTER_MOTION_MASK
),
4041 cursor
->GetCursor(),
4042 (guint32
)GDK_CURRENT_TIME
);
4043 g_captureWindow
= this;
4044 g_captureWindowHasMouse
= true;
4047 void wxWindowGTK::DoReleaseMouse()
4049 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4051 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4053 g_captureWindow
= (wxWindowGTK
*) NULL
;
4055 GdkWindow
*window
= (GdkWindow
*) NULL
;
4057 window
= m_wxwindow
->window
;
4059 window
= GetConnectWidget()->window
;
4064 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4067 void wxWindowGTK::GTKReleaseMouseAndNotify()
4070 wxMouseCaptureLostEvent
evt(GetId());
4071 evt
.SetEventObject( this );
4072 GetEventHandler()->ProcessEvent( evt
);
4076 wxWindow
*wxWindowBase::GetCapture()
4078 return (wxWindow
*)g_captureWindow
;
4081 bool wxWindowGTK::IsRetained() const
4086 void wxWindowGTK::SetScrollbar(int orient
,
4090 bool WXUNUSED(update
))
4092 const int dir
= ScrollDirFromOrient(orient
);
4093 GtkRange
* const sb
= m_scrollBar
[dir
];
4094 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4098 m_hasScrolling
= true;
4102 // GtkRange requires upper > lower
4107 GtkAdjustment
* const adj
= sb
->adjustment
;
4108 adj
->step_increment
= 1;
4109 adj
->page_increment
=
4110 adj
->page_size
= thumbVisible
;
4113 g_signal_handlers_block_by_func(
4114 sb
, (void*)gtk_scrollbar_value_changed
, this);
4116 gtk_range_set_range(sb
, 0, range
);
4117 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4119 g_signal_handlers_unblock_by_func(
4120 sb
, (void*)gtk_scrollbar_value_changed
, this);
4123 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4125 const int dir
= ScrollDirFromOrient(orient
);
4126 GtkRange
* const sb
= m_scrollBar
[dir
];
4127 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4129 // This check is more than an optimization. Without it, the slider
4130 // will not move smoothly while tracking when using wxScrollHelper.
4131 if (GetScrollPos(orient
) != pos
)
4133 g_signal_handlers_block_by_func(
4134 sb
, (void*)gtk_scrollbar_value_changed
, this);
4136 gtk_range_set_value(sb
, pos
);
4137 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4139 g_signal_handlers_unblock_by_func(
4140 sb
, (void*)gtk_scrollbar_value_changed
, this);
4144 int wxWindowGTK::GetScrollThumb(int orient
) const
4146 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4147 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4149 return int(sb
->adjustment
->page_size
);
4152 int wxWindowGTK::GetScrollPos( int orient
) const
4154 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4155 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4157 return int(sb
->adjustment
->value
+ 0.5);
4160 int wxWindowGTK::GetScrollRange( int orient
) const
4162 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4163 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4165 return int(sb
->adjustment
->upper
);
4168 // Determine if increment is the same as +/-x, allowing for some small
4169 // difference due to possible inexactness in floating point arithmetic
4170 static inline bool IsScrollIncrement(double increment
, double x
)
4172 wxASSERT(increment
> 0);
4173 const double tolerance
= 1.0 / 1024;
4174 return fabs(increment
- fabs(x
)) < tolerance
;
4177 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4181 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4183 const int barIndex
= range
== m_scrollBar
[1];
4184 GtkAdjustment
* adj
= range
->adjustment
;
4186 const int value
= int(adj
->value
+ 0.5);
4188 // save previous position
4189 const double oldPos
= m_scrollPos
[barIndex
];
4190 // update current position
4191 m_scrollPos
[barIndex
] = adj
->value
;
4192 // If event should be ignored, or integral position has not changed
4193 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4198 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4201 // Difference from last change event
4202 const double diff
= adj
->value
- oldPos
;
4203 const bool isDown
= diff
> 0;
4205 if (IsScrollIncrement(adj
->step_increment
, diff
))
4207 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4209 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4211 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4213 else if (m_mouseButtonDown
)
4215 // Assume track event
4216 m_isScrolling
= true;
4222 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4224 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4226 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4228 // No scrolling requested.
4229 if ((dx
== 0) && (dy
== 0)) return;
4231 m_clipPaintRegion
= true;
4233 WX_PIZZA(m_wxwindow
)->scroll(dx
, dy
);
4235 m_clipPaintRegion
= false;
4238 bool restoreCaret
= (GetCaret() != NULL
&& GetCaret()->IsVisible());
4241 wxRect
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4243 caretRect
.width
+= dx
;
4246 caretRect
.x
+= dx
; caretRect
.width
-= dx
;
4249 caretRect
.height
+= dy
;
4252 caretRect
.y
+= dy
; caretRect
.height
-= dy
;
4255 RefreshRect(caretRect
);
4257 #endif // wxUSE_CARET
4260 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4262 //RN: Note that static controls usually have no border on gtk, so maybe
4263 //it makes sense to treat that as simply no border at the wx level
4265 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4267 GtkShadowType gtkstyle
;
4269 if(wxstyle
& wxBORDER_RAISED
)
4270 gtkstyle
= GTK_SHADOW_OUT
;
4271 else if (wxstyle
& wxBORDER_SUNKEN
)
4272 gtkstyle
= GTK_SHADOW_IN
;
4275 else if (wxstyle
& wxBORDER_DOUBLE
)
4276 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4279 gtkstyle
= GTK_SHADOW_IN
;
4281 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4286 void wxWindowGTK::SetWindowStyleFlag( long style
)
4288 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4289 wxWindowBase::SetWindowStyleFlag(style
);
4292 // Find the wxWindow at the current mouse position, also returning the mouse
4294 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4296 pt
= wxGetMousePosition();
4297 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4301 // Get the current mouse position.
4302 wxPoint
wxGetMousePosition()
4304 /* This crashes when used within wxHelpContext,
4305 so we have to use the X-specific implementation below.
4307 GdkModifierType *mask;
4308 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4310 return wxPoint(x, y);
4314 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4316 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4317 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4318 Window rootReturn
, childReturn
;
4319 int rootX
, rootY
, winX
, winY
;
4320 unsigned int maskReturn
;
4322 XQueryPointer (display
,
4326 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4327 return wxPoint(rootX
, rootY
);
4331 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4332 void wxAddGrab(wxWindow
* window
)
4334 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4337 void wxRemoveGrab(wxWindow
* window
)
4339 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4342 GdkWindow
* wxWindowGTK::GTKGetDrawingWindow() const
4344 GdkWindow
* window
= NULL
;
4346 window
= m_wxwindow
->window
;