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 #include "wx/gtk/private.h"
43 #include "wx/gtk/win_gtk.h"
44 #include <gdk/gdkkeysyms.h>
47 //-----------------------------------------------------------------------------
48 // documentation on internals
49 //-----------------------------------------------------------------------------
52 I have been asked several times about writing some documentation about
53 the GTK port of wxWidgets, especially its internal structures. Obviously,
54 you cannot understand wxGTK without knowing a little about the GTK, but
55 some more information about what the wxWindow, which is the base class
56 for all other window classes, does seems required as well.
60 What does wxWindow do? It contains the common interface for the following
61 jobs of its descendants:
63 1) Define the rudimentary behaviour common to all window classes, such as
64 resizing, intercepting user input (so as to make it possible to use these
65 events for special purposes in a derived class), window names etc.
67 2) Provide the possibility to contain and manage children, if the derived
68 class is allowed to contain children, which holds true for those window
69 classes which do not display a native GTK widget. To name them, these
70 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
71 work classes are a special case and are handled a bit differently from
72 the rest. The same holds true for the wxNotebook class.
74 3) Provide the possibility to draw into a client area of a window. This,
75 too, only holds true for classes that do not display a native GTK widget
78 4) Provide the entire mechanism for scrolling widgets. This actual inter-
79 face for this is usually in wxScrolledWindow, but the GTK implementation
82 5) A multitude of helper or extra methods for special purposes, such as
83 Drag'n'Drop, managing validators etc.
85 6) Display a border (sunken, raised, simple or none).
87 Normally one might expect, that one wxWidgets window would always correspond
88 to one GTK widget. Under GTK, there is no such all-round widget that has all
89 the functionality. Moreover, the GTK defines a client area as a different
90 widget from the actual widget you are handling. Last but not least some
91 special classes (e.g. wxFrame) handle different categories of widgets and
92 still have the possibility to draw something in the client area.
93 It was therefore required to write a special purpose GTK widget, that would
94 represent a client area in the sense of wxWidgets capable to do the jobs
95 2), 3) and 4). I have written this class and it resides in win_gtk.c of
98 All windows must have a widget, with which they interact with other under-
99 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
100 the wxWindow class has a member variable called m_widget which holds a
101 pointer to this widget. When the window class represents a GTK native widget,
102 this is (in most cases) the only GTK widget the class manages. E.g. the
103 wxStaticText class handles only a GtkLabel widget a pointer to which you
104 can find in m_widget (defined in wxWindow)
106 When the class has a client area for drawing into and for containing children
107 it has to handle the client area widget (of the type wxPizza, defined in
108 win_gtk.cpp), but there could be any number of widgets, handled by a class.
109 The common rule for all windows is only, that the widget that interacts with
110 the rest of GTK must be referenced in m_widget and all other widgets must be
111 children of this widget on the GTK level. The top-most widget, which also
112 represents the client area, must be in the m_wxwindow field and must be of
115 As I said, the window classes that display a GTK native widget only have
116 one widget, so in the case of e.g. the wxButton class m_widget holds a
117 pointer to a GtkButton widget. But windows with client areas (for drawing
118 and children) have a m_widget field that is a pointer to a GtkScrolled-
119 Window and a m_wxwindow field that is pointer to a wxPizza and this
120 one is (in the GTK sense) a child of the GtkScrolledWindow.
122 If the m_wxwindow field is set, then all input to this widget is inter-
123 cepted and sent to the wxWidgets class. If not, all input to the widget
124 that gets pointed to by m_widget gets intercepted and sent to the class.
128 The design of scrolling in wxWidgets is markedly different from that offered
129 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
130 clicking on a scrollbar belonging to scrolled window will inevitably move
131 the window. In wxWidgets, the scrollbar will only emit an event, send this
132 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
133 which actually moves the window and its sub-windows. Note that wxPizza
134 memorizes how much it has been scrolled but that wxWidgets forgets this
135 so that the two coordinates systems have to be kept in synch. This is done
136 in various places using the pizza->m_scroll_x and pizza->m_scroll_y values.
140 Singularly the most broken code in GTK is the code that is supposed to
141 inform subwindows (child windows) about new positions. Very often, duplicate
142 events are sent without changes in size or position, equally often no
143 events are sent at all (All this is due to a bug in the GtkContainer code
144 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
145 GTK's own system and it simply waits for size events for toplevel windows
146 and then iterates down the respective size events to all window. This has
147 the disadvantage that windows might get size events before the GTK widget
148 actually has the reported size. This doesn't normally pose any problem, but
149 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
150 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
151 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
152 window that is used for OpenGL output really has that size (as reported by
157 If someone at some point of time feels the immense desire to have a look at,
158 change or attempt to optimise the Refresh() logic, this person will need an
159 intimate understanding of what "draw" and "expose" events are and what
160 they are used for, in particular when used in connection with GTK's
161 own windowless widgets. Beware.
165 Cursors, too, have been a constant source of pleasure. The main difficulty
166 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
167 for the parent. To prevent this from doing too much harm, I use idle time
168 to set the cursor over and over again, starting from the toplevel windows
169 and ending with the youngest generation (speaking of parent and child windows).
170 Also don't forget that cursors (like much else) are connected to GdkWindows,
171 not GtkWidgets and that the "window" field of a GtkWidget might very well
172 point to the GdkWindow of the parent widget (-> "window-less widget") and
173 that the two obviously have very different meanings.
177 //-----------------------------------------------------------------------------
179 //-----------------------------------------------------------------------------
181 // Don't allow event propagation during drag
182 bool g_blockEventsOnDrag
;
183 // Don't allow mouse event propagation during scroll
184 bool g_blockEventsOnScroll
;
185 extern wxCursor g_globalCursor
;
187 // mouse capture state: the window which has it and if the mouse is currently
189 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
190 static bool g_captureWindowHasMouse
= false;
192 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
194 // the last window which had the focus - this is normally never NULL (except
195 // if we never had focus at all) as even when g_focusWindow is NULL it still
196 // keeps its previous value
197 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
199 // If a window get the focus set but has not been realized
200 // yet, defer setting the focus to idle time.
201 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
203 // global variables because GTK+ DnD want to have the
204 // mouse event that caused it
205 GdkEvent
*g_lastMouseEvent
= (GdkEvent
*) NULL
;
206 int g_lastButtonNumber
= 0;
208 extern bool g_mainThreadLocked
;
210 //-----------------------------------------------------------------------------
212 //-----------------------------------------------------------------------------
217 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
219 # define DEBUG_MAIN_THREAD
222 #define DEBUG_MAIN_THREAD
225 // the trace mask used for the focus debugging messages
226 #define TRACE_FOCUS _T("focus")
228 //-----------------------------------------------------------------------------
229 // missing gdk functions
230 //-----------------------------------------------------------------------------
233 gdk_window_warp_pointer (GdkWindow
*window
,
238 window
= gdk_get_default_root_window();
240 if (!GDK_WINDOW_DESTROYED(window
))
242 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
243 None
, /* not source window -> move from anywhere */
244 GDK_WINDOW_XID(window
), /* dest window */
245 0, 0, 0, 0, /* not source window -> move from anywhere */
250 //-----------------------------------------------------------------------------
251 // local code (see below)
252 //-----------------------------------------------------------------------------
254 // returns the child of win which currently has focus or NULL if not found
256 // Note: can't be static, needed by textctrl.cpp.
257 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
259 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
261 return (wxWindow
*)NULL
;
263 if ( winFocus
== win
)
264 return (wxWindow
*)win
;
266 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
268 node
= node
->GetNext() )
270 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
275 return (wxWindow
*)NULL
;
278 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
)
280 GtkScrolledWindow
* scroll_window
= GTK_SCROLLED_WINDOW(widget
);
281 GtkScrolledWindowClass
* scroll_class
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
));
282 GtkRequisition scroll_req
;
285 if (scroll_window
->vscrollbar_visible
)
287 scroll_req
.width
= 2;
288 scroll_req
.height
= 2;
289 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
290 (scroll_window
->vscrollbar
, &scroll_req
);
291 w
= scroll_req
.width
+
292 scroll_class
->scrollbar_spacing
;
296 if (scroll_window
->hscrollbar_visible
)
298 scroll_req
.width
= 2;
299 scroll_req
.height
= 2;
300 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
301 (scroll_window
->hscrollbar
, &scroll_req
);
302 h
= scroll_req
.height
+
303 scroll_class
->scrollbar_spacing
;
307 //-----------------------------------------------------------------------------
308 // "size_request" of m_widget
309 //-----------------------------------------------------------------------------
311 // make it extern because wxStaticText needs to disconnect this one
313 void wxgtk_window_size_request_callback(GtkWidget
* WXUNUSED(widget
),
314 GtkRequisition
*requisition
,
318 win
->GetSize( &w
, &h
);
324 requisition
->height
= h
;
325 requisition
->width
= w
;
333 void wxgtk_combo_size_request_callback(GtkWidget
* WXUNUSED(widget
),
334 GtkRequisition
*requisition
,
337 // This callback is actually hooked into the text entry
338 // of the combo box, not the GtkHBox.
341 win
->GetSize( &w
, &h
);
347 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
349 GtkRequisition entry_req
;
351 entry_req
.height
= 2;
352 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->entry
) )->size_request
)
353 (gcombo
->entry
, &entry_req
);
355 GtkRequisition button_req
;
356 button_req
.width
= 2;
357 button_req
.height
= 2;
358 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
359 (gcombo
->button
, &button_req
);
361 requisition
->width
= w
- button_req
.width
;
362 requisition
->height
= entry_req
.height
;
366 #endif // wxUSE_COMBOBOX
368 //-----------------------------------------------------------------------------
369 // "expose_event" of m_wxwindow
370 //-----------------------------------------------------------------------------
374 gtk_window_expose_callback( GtkWidget
*widget
,
375 GdkEventExpose
*gdk_event
,
380 // if this event is for the border-only GdkWindow
381 if (gdk_event
->window
!= widget
->window
)
387 wxPrintf( wxT("OnExpose from ") );
388 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
389 wxPrintf( win
->GetClassInfo()->GetClassName() );
390 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
391 (int)gdk_event
->area
.y
,
392 (int)gdk_event
->area
.width
,
393 (int)gdk_event
->area
.height
);
398 win
->m_wxwindow
->style
,
402 (GdkRectangle
*) NULL
,
404 (char *)"button", // const_cast
409 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
411 win
->GtkSendPaintEvents();
413 // Let parent window draw window-less widgets
418 //-----------------------------------------------------------------------------
419 // "expose_event" from m_widget, for drawing border
420 //-----------------------------------------------------------------------------
422 #ifndef __WXUNIVERSAL__
425 expose_event_border(GtkWidget
* widget
, GdkEventExpose
* event
, wxWindow
* win
)
427 // if this event is not for the GdkWindow the border is drawn on
428 if (win
->m_wxwindow
== win
->m_widget
&& event
->window
== widget
->window
)
433 // GtkScrolledWindow is GTK_NO_WINDOW
434 if (GTK_WIDGET_NO_WINDOW(widget
))
436 x
= widget
->allocation
.x
;
437 y
= widget
->allocation
.y
;
439 int w
= win
->m_wxwindow
->allocation
.width
;
440 int h
= win
->m_wxwindow
->allocation
.height
;
441 if (win
->HasFlag(wxBORDER_SIMPLE
))
444 gc
= gdk_gc_new(event
->window
);
445 gdk_gc_set_foreground(gc
, &widget
->style
->black
);
446 gdk_draw_rectangle(event
->window
, gc
, false, x
, y
, w
- 1, h
- 1);
451 GtkShadowType shadow
= GTK_SHADOW_IN
;
452 if (win
->HasFlag(wxBORDER_RAISED
))
453 shadow
= GTK_SHADOW_OUT
;
455 widget
->style
, event
->window
, GTK_STATE_NORMAL
,
456 shadow
, &event
->area
, widget
, NULL
, x
, y
, w
, h
);
459 // no further painting is needed for border-only GdkWindow
460 return win
->m_wxwindow
== win
->m_widget
;
463 #endif // !__WXUNIVERSAL__
465 //-----------------------------------------------------------------------------
466 // "key_press_event" from any window
467 //-----------------------------------------------------------------------------
469 // These are used when transforming Ctrl-alpha to ascii values 1-26
470 inline bool wxIsLowerChar(int code
)
472 return (code
>= 'a' && code
<= 'z' );
475 inline bool wxIsUpperChar(int code
)
477 return (code
>= 'A' && code
<= 'Z' );
481 // set WXTRACE to this to see the key event codes on the console
482 #define TRACE_KEYS _T("keyevent")
484 // translates an X key symbol to WXK_XXX value
486 // if isChar is true it means that the value returned will be used for EVT_CHAR
487 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
488 // for example, while if it is false it means that the value is going to be
489 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
491 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
497 // Shift, Control and Alt don't generate the CHAR events at all
500 key_code
= isChar
? 0 : WXK_SHIFT
;
504 key_code
= isChar
? 0 : WXK_CONTROL
;
512 key_code
= isChar
? 0 : WXK_ALT
;
515 // neither do the toggle modifies
516 case GDK_Scroll_Lock
:
517 key_code
= isChar
? 0 : WXK_SCROLL
;
521 key_code
= isChar
? 0 : WXK_CAPITAL
;
525 key_code
= isChar
? 0 : WXK_NUMLOCK
;
529 // various other special keys
542 case GDK_ISO_Left_Tab
:
549 key_code
= WXK_RETURN
;
553 key_code
= WXK_CLEAR
;
557 key_code
= WXK_PAUSE
;
561 key_code
= WXK_SELECT
;
565 key_code
= WXK_PRINT
;
569 key_code
= WXK_EXECUTE
;
573 key_code
= WXK_ESCAPE
;
576 // cursor and other extended keyboard keys
578 key_code
= WXK_DELETE
;
594 key_code
= WXK_RIGHT
;
601 case GDK_Prior
: // == GDK_Page_Up
602 key_code
= WXK_PAGEUP
;
605 case GDK_Next
: // == GDK_Page_Down
606 key_code
= WXK_PAGEDOWN
;
618 key_code
= WXK_INSERT
;
633 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
637 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
641 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
645 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
649 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
653 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
657 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
661 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
665 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
669 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
673 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
677 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
681 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
684 case GDK_KP_Prior
: // == GDK_KP_Page_Up
685 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
688 case GDK_KP_Next
: // == GDK_KP_Page_Down
689 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
693 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
697 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
701 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
705 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
709 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
712 case GDK_KP_Multiply
:
713 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
717 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
720 case GDK_KP_Separator
:
721 // FIXME: what is this?
722 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
725 case GDK_KP_Subtract
:
726 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
730 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
734 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
751 key_code
= WXK_F1
+ keysym
- GDK_F1
;
761 static inline bool wxIsAsciiKeysym(KeySym ks
)
766 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
768 GdkEventKey
*gdk_event
)
772 GdkModifierType state
;
773 if (gdk_event
->window
)
774 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
776 event
.SetTimestamp( gdk_event
->time
);
777 event
.SetId(win
->GetId());
778 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
779 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
780 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
781 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
782 event
.m_scanCode
= gdk_event
->keyval
;
783 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
784 event
.m_rawFlags
= 0;
786 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
788 wxGetMousePosition( &x
, &y
);
789 win
->ScreenToClient( &x
, &y
);
792 event
.SetEventObject( win
);
797 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
799 GdkEventKey
*gdk_event
)
801 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
802 // but only event->keyval which is quite useless to us, so remember
803 // the last character from GDK_KEY_PRESS and reuse it as last resort
805 // NB: should be MT-safe as we're always called from the main thread only
810 } s_lastKeyPress
= { 0, 0 };
812 KeySym keysym
= gdk_event
->keyval
;
814 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
815 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
819 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
823 // do we have the translation or is it a plain ASCII character?
824 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
826 // we should use keysym if it is ASCII as X does some translations
827 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
828 // which we don't want here (but which we do use for OnChar())
829 if ( !wxIsAsciiKeysym(keysym
) )
831 keysym
= (KeySym
)gdk_event
->string
[0];
834 // we want to always get the same key code when the same key is
835 // pressed regardless of the state of the modifiers, i.e. on a
836 // standard US keyboard pressing '5' or '%' ('5' key with
837 // Shift) should result in the same key code in OnKeyDown():
838 // '5' (although OnChar() will get either '5' or '%').
840 // to do it we first translate keysym to keycode (== scan code)
841 // and then back but always using the lower register
842 Display
*dpy
= (Display
*)wxGetDisplay();
843 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
845 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
847 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
849 // use the normalized, i.e. lower register, keysym if we've
851 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
853 // as explained above, we want to have lower register key codes
854 // normally but for the letter keys we want to have the upper ones
856 // NB: don't use XConvertCase() here, we want to do it for letters
858 key_code
= toupper(key_code
);
860 else // non ASCII key, what to do?
862 // by default, ignore it
865 // but if we have cached information from the last KEY_PRESS
866 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
869 if ( keysym
== s_lastKeyPress
.keysym
)
871 key_code
= s_lastKeyPress
.keycode
;
876 if ( gdk_event
->type
== GDK_KEY_PRESS
)
878 // remember it to be reused for KEY_UP event later
879 s_lastKeyPress
.keysym
= keysym
;
880 s_lastKeyPress
.keycode
= key_code
;
884 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
886 // sending unknown key events doesn't really make sense
890 // now fill all the other fields
891 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
893 event
.m_keyCode
= key_code
;
895 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
897 event
.m_uniChar
= key_code
;
907 GtkIMContext
*context
;
908 GdkEventKey
*lastKeyEvent
;
912 context
= gtk_im_multicontext_new();
917 g_object_unref (context
);
923 gtk_window_key_press_callback( GtkWidget
*widget
,
924 GdkEventKey
*gdk_event
,
931 if (g_blockEventsOnDrag
)
934 // GTK+ sends keypress events to the focus widget and then
935 // to all its parent and grandparent widget. We only want
936 // the key events from the focus widget.
937 if (!GTK_WIDGET_HAS_FOCUS(widget
))
940 wxKeyEvent
event( wxEVT_KEY_DOWN
);
942 bool return_after_IM
= false;
944 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
946 // Emit KEY_DOWN event
947 ret
= win
->GetEventHandler()->ProcessEvent( event
);
951 // Return after IM processing as we cannot do
952 // anything with it anyhow.
953 return_after_IM
= true;
956 if ((!ret
) && (win
->m_imData
!= NULL
))
958 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
959 // docs, if IM filter returns true, no further processing should be done.
960 // we should send the key_down event anyway.
961 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
962 win
->m_imData
->lastKeyEvent
= NULL
;
963 if (intercepted_by_IM
)
965 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
976 wxWindowGTK
*ancestor
= win
;
979 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
982 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
983 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
986 if (ancestor
->IsTopLevel())
988 ancestor
= ancestor
->GetParent();
991 #endif // wxUSE_ACCEL
993 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
994 // will only be sent if it is not in an accelerator table.
998 KeySym keysym
= gdk_event
->keyval
;
999 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1000 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1003 if ( wxIsAsciiKeysym(keysym
) )
1006 key_code
= (unsigned char)keysym
;
1008 // gdk_event->string is actually deprecated
1009 else if ( gdk_event
->length
== 1 )
1011 key_code
= (unsigned char)gdk_event
->string
[0];
1017 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1019 event
.m_keyCode
= key_code
;
1021 // To conform to the docs we need to translate Ctrl-alpha
1022 // characters to values in the range 1-26.
1023 if ( event
.ControlDown() &&
1024 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
1026 if ( wxIsLowerChar(key_code
) )
1027 event
.m_keyCode
= key_code
- 'a' + 1;
1028 if ( wxIsUpperChar(key_code
) )
1029 event
.m_keyCode
= key_code
- 'A' + 1;
1031 event
.m_uniChar
= event
.m_keyCode
;
1035 // Implement OnCharHook by checking ancestor top level windows
1036 wxWindow
*parent
= win
;
1037 while (parent
&& !parent
->IsTopLevel())
1038 parent
= parent
->GetParent();
1041 event
.SetEventType( wxEVT_CHAR_HOOK
);
1042 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1047 event
.SetEventType(wxEVT_CHAR
);
1048 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1059 gtk_wxwindow_commit_cb (GtkIMContext
* WXUNUSED(context
),
1063 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1065 // take modifiers, cursor position, timestamp etc. from the last
1066 // key_press_event that was fed into Input Method:
1067 if (window
->m_imData
->lastKeyEvent
)
1069 wxFillOtherKeyEventFields(event
,
1070 window
, window
->m_imData
->lastKeyEvent
);
1074 event
.SetEventObject( window
);
1077 const wxString
data(wxGTK_CONV_BACK_SYS(str
));
1083 // Implement OnCharHook by checking ancestor top level windows
1084 wxWindow
*parent
= window
;
1085 while (parent
&& !parent
->IsTopLevel())
1086 parent
= parent
->GetParent();
1088 for( wxString::const_iterator pstr
= data
.begin(); pstr
!= data
.end(); ++pstr
)
1091 event
.m_uniChar
= *pstr
;
1092 // Backward compatible for ISO-8859-1
1093 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1094 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1096 event
.m_keyCode
= (char)*pstr
;
1097 #endif // wxUSE_UNICODE
1099 // To conform to the docs we need to translate Ctrl-alpha
1100 // characters to values in the range 1-26.
1101 if ( event
.ControlDown() &&
1102 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
1104 if ( wxIsLowerChar(*pstr
) )
1105 event
.m_keyCode
= *pstr
- 'a' + 1;
1106 if ( wxIsUpperChar(*pstr
) )
1107 event
.m_keyCode
= *pstr
- 'A' + 1;
1109 event
.m_keyCode
= *pstr
- 'a' + 1;
1111 event
.m_uniChar
= event
.m_keyCode
;
1117 event
.SetEventType( wxEVT_CHAR_HOOK
);
1118 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1123 event
.SetEventType(wxEVT_CHAR
);
1124 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1131 //-----------------------------------------------------------------------------
1132 // "key_release_event" from any window
1133 //-----------------------------------------------------------------------------
1137 gtk_window_key_release_callback( GtkWidget
* WXUNUSED(widget
),
1138 GdkEventKey
*gdk_event
,
1146 if (g_blockEventsOnDrag
)
1149 wxKeyEvent
event( wxEVT_KEY_UP
);
1150 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1152 // unknown key pressed, ignore (the event would be useless anyhow)
1156 return win
->GTKProcessEvent(event
);
1160 // ============================================================================
1162 // ============================================================================
1164 // ----------------------------------------------------------------------------
1165 // mouse event processing helpers
1166 // ----------------------------------------------------------------------------
1168 // init wxMouseEvent with the info from GdkEventXXX struct
1169 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1170 wxMouseEvent
& event
,
1173 event
.SetTimestamp( gdk_event
->time
);
1174 event
.m_shiftDown
= gdk_event
->state
& GDK_SHIFT_MASK
;
1175 event
.m_controlDown
= gdk_event
->state
& GDK_CONTROL_MASK
;
1176 event
.m_altDown
= gdk_event
->state
& GDK_MOD1_MASK
;
1177 event
.m_metaDown
= gdk_event
->state
& GDK_MOD2_MASK
;
1178 event
.m_leftDown
= gdk_event
->state
& GDK_BUTTON1_MASK
;
1179 event
.m_middleDown
= gdk_event
->state
& GDK_BUTTON2_MASK
;
1180 event
.m_rightDown
= gdk_event
->state
& GDK_BUTTON3_MASK
;
1181 event
.m_aux1Down
= gdk_event
->state
& GDK_BUTTON4_MASK
;
1182 event
.m_aux2Down
= gdk_event
->state
& GDK_BUTTON5_MASK
;
1184 wxPoint pt
= win
->GetClientAreaOrigin();
1185 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1186 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1188 if ((win
->m_wxwindow
) && (win
->GetLayoutDirection() == wxLayout_RightToLeft
))
1190 // origin in the upper right corner
1191 int window_width
= win
->m_wxwindow
->allocation
.width
;
1192 event
.m_x
= window_width
- event
.m_x
;
1195 event
.SetEventObject( win
);
1196 event
.SetId( win
->GetId() );
1197 event
.SetTimestamp( gdk_event
->time
);
1200 static void AdjustEventButtonState(wxMouseEvent
& event
)
1202 // GDK reports the old state of the button for a button press event, but
1203 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1204 // for a LEFT_DOWN event, not FALSE, so we will invert
1205 // left/right/middleDown for the corresponding click events
1207 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1208 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1209 (event
.GetEventType() == wxEVT_LEFT_UP
))
1211 event
.m_leftDown
= !event
.m_leftDown
;
1215 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1216 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1217 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1219 event
.m_middleDown
= !event
.m_middleDown
;
1223 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1224 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1225 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1227 event
.m_rightDown
= !event
.m_rightDown
;
1232 // find the window to send the mouse event too
1234 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1239 if (win
->m_wxwindow
)
1241 wxPizza
* pizza
= WX_PIZZA(win
->m_wxwindow
);
1242 xx
+= pizza
->m_scroll_x
;
1243 yy
+= pizza
->m_scroll_y
;
1246 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1249 wxWindowGTK
*child
= node
->GetData();
1251 node
= node
->GetNext();
1252 if (!child
->IsShown())
1255 if (child
->IsTransparentForMouse())
1257 // wxStaticBox is transparent in the box itself
1258 int xx1
= child
->m_x
;
1259 int yy1
= child
->m_y
;
1260 int xx2
= child
->m_x
+ child
->m_width
;
1261 int yy2
= child
->m_y
+ child
->m_height
;
1264 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1266 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1268 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1270 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1281 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1282 (child
->m_x
<= xx
) &&
1283 (child
->m_y
<= yy
) &&
1284 (child
->m_x
+child
->m_width
>= xx
) &&
1285 (child
->m_y
+child
->m_height
>= yy
))
1298 // ----------------------------------------------------------------------------
1299 // common event handlers helpers
1300 // ----------------------------------------------------------------------------
1302 bool wxWindowGTK::GTKProcessEvent(wxEvent
& event
) const
1304 // nothing special at this level
1305 return GetEventHandler()->ProcessEvent(event
);
1308 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1314 if (g_blockEventsOnDrag
)
1316 if (g_blockEventsOnScroll
)
1319 if (!GTKIsOwnWindow(event
->window
))
1325 // overloads for all GDK event types we use here: we need to have this as
1326 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1327 // derives from it in the sense that the structs have the same layout
1328 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1329 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1331 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1334 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1335 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1336 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1338 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1340 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1341 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1345 // send the wxChildFocusEvent and wxFocusEvent, common code of
1346 // gtk_window_focus_in_callback() and SetFocus()
1347 static bool DoSendFocusEvents(wxWindow
*win
)
1349 // Notify the parent keeping track of focus for the kbd navigation
1350 // purposes that we got it.
1351 wxChildFocusEvent
eventChildFocus(win
);
1352 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1354 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1355 eventFocus
.SetEventObject(win
);
1357 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1360 // all event handlers must have C linkage as they're called from GTK+ C code
1364 //-----------------------------------------------------------------------------
1365 // "button_press_event"
1366 //-----------------------------------------------------------------------------
1369 gtk_window_button_press_callback( GtkWidget
*widget
,
1370 GdkEventButton
*gdk_event
,
1373 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1375 g_lastButtonNumber
= gdk_event
->button
;
1377 // GDK sends surplus button down events
1378 // before a double click event. We
1379 // need to filter these out.
1380 if ((gdk_event
->type
== GDK_BUTTON_PRESS
) && (win
->m_wxwindow
))
1382 GdkEvent
*peek_event
= gdk_event_peek();
1385 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1386 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1388 gdk_event_free( peek_event
);
1393 gdk_event_free( peek_event
);
1398 wxEventType event_type
= wxEVT_NULL
;
1400 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1401 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1403 // Reset GDK internal timestamp variables in order to disable GDK
1404 // triple click events. GDK will then next time believe no button has
1405 // been clicked just before, and send a normal button click event.
1406 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1407 display
->button_click_time
[1] = 0;
1408 display
->button_click_time
[0] = 0;
1411 if (gdk_event
->button
== 1)
1413 // note that GDK generates triple click events which are not supported
1414 // by wxWidgets but still have to be passed to the app as otherwise
1415 // clicks would simply go missing
1416 switch (gdk_event
->type
)
1418 // we shouldn't get triple clicks at all for GTK2 because we
1419 // suppress them artificially using the code above but we still
1420 // should map them to something for GTK1 and not just ignore them
1421 // as this would lose clicks
1422 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1423 case GDK_BUTTON_PRESS
:
1424 event_type
= wxEVT_LEFT_DOWN
;
1427 case GDK_2BUTTON_PRESS
:
1428 event_type
= wxEVT_LEFT_DCLICK
;
1432 // just to silence gcc warnings
1436 else if (gdk_event
->button
== 2)
1438 switch (gdk_event
->type
)
1440 case GDK_3BUTTON_PRESS
:
1441 case GDK_BUTTON_PRESS
:
1442 event_type
= wxEVT_MIDDLE_DOWN
;
1445 case GDK_2BUTTON_PRESS
:
1446 event_type
= wxEVT_MIDDLE_DCLICK
;
1453 else if (gdk_event
->button
== 3)
1455 switch (gdk_event
->type
)
1457 case GDK_3BUTTON_PRESS
:
1458 case GDK_BUTTON_PRESS
:
1459 event_type
= wxEVT_RIGHT_DOWN
;
1462 case GDK_2BUTTON_PRESS
:
1463 event_type
= wxEVT_RIGHT_DCLICK
;
1471 if ( event_type
== wxEVT_NULL
)
1473 // unknown mouse button or click type
1477 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1479 wxMouseEvent
event( event_type
);
1480 InitMouseEvent( win
, event
, gdk_event
);
1482 AdjustEventButtonState(event
);
1484 // wxListBox actually gets mouse events from the item, so we need to give it
1485 // a chance to correct this
1486 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1488 // find the correct window to send the event to: it may be a different one
1489 // from the one which got it at GTK+ level because some controls don't have
1490 // their own X window and thus cannot get any events.
1491 if ( !g_captureWindow
)
1492 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1494 // reset the event object and id in case win changed.
1495 event
.SetEventObject( win
);
1496 event
.SetId( win
->GetId() );
1498 bool ret
= win
->GTKProcessEvent( event
);
1499 g_lastMouseEvent
= NULL
;
1503 if ((event_type
== wxEVT_LEFT_DOWN
) && !win
->IsOfStandardClass() &&
1504 (g_focusWindow
!= win
) /* && win->IsFocusable() */)
1509 if (event_type
== wxEVT_RIGHT_DOWN
)
1511 // generate a "context menu" event: this is similar to right mouse
1512 // click under many GUIs except that it is generated differently
1513 // (right up under MSW, ctrl-click under Mac, right down here) and
1515 // (a) it's a command event and so is propagated to the parent
1516 // (b) under some ports it can be generated from kbd too
1517 // (c) it uses screen coords (because of (a))
1518 wxContextMenuEvent
evtCtx(
1521 win
->ClientToScreen(event
.GetPosition()));
1522 evtCtx
.SetEventObject(win
);
1523 return win
->GTKProcessEvent(evtCtx
);
1529 //-----------------------------------------------------------------------------
1530 // "button_release_event"
1531 //-----------------------------------------------------------------------------
1534 gtk_window_button_release_callback( GtkWidget
*widget
,
1535 GdkEventButton
*gdk_event
,
1538 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1540 g_lastButtonNumber
= 0;
1542 wxEventType event_type
= wxEVT_NULL
;
1544 switch (gdk_event
->button
)
1547 event_type
= wxEVT_LEFT_UP
;
1551 event_type
= wxEVT_MIDDLE_UP
;
1555 event_type
= wxEVT_RIGHT_UP
;
1559 // unknown button, don't process
1563 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1565 wxMouseEvent
event( event_type
);
1566 InitMouseEvent( win
, event
, gdk_event
);
1568 AdjustEventButtonState(event
);
1570 // same wxListBox hack as above
1571 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1573 if ( !g_captureWindow
)
1574 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1576 // reset the event object and id in case win changed.
1577 event
.SetEventObject( win
);
1578 event
.SetId( win
->GetId() );
1580 bool ret
= win
->GTKProcessEvent(event
);
1582 g_lastMouseEvent
= NULL
;
1587 //-----------------------------------------------------------------------------
1588 // "motion_notify_event"
1589 //-----------------------------------------------------------------------------
1592 gtk_window_motion_notify_callback( GtkWidget
* WXUNUSED(widget
),
1593 GdkEventMotion
*gdk_event
,
1596 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1598 if (gdk_event
->is_hint
)
1602 GdkModifierType state
;
1603 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1608 g_lastMouseEvent
= (GdkEvent
*) gdk_event
;
1610 wxMouseEvent
event( wxEVT_MOTION
);
1611 InitMouseEvent(win
, event
, gdk_event
);
1613 if ( g_captureWindow
)
1615 // synthesise a mouse enter or leave event if needed
1616 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1617 // This seems to be necessary and actually been added to
1618 // GDK itself in version 2.0.X
1621 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1622 if ( hasMouse
!= g_captureWindowHasMouse
)
1624 // the mouse changed window
1625 g_captureWindowHasMouse
= hasMouse
;
1627 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1628 : wxEVT_LEAVE_WINDOW
);
1629 InitMouseEvent(win
, eventM
, gdk_event
);
1630 eventM
.SetEventObject(win
);
1631 win
->GTKProcessEvent(eventM
);
1636 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1638 // reset the event object and id in case win changed.
1639 event
.SetEventObject( win
);
1640 event
.SetId( win
->GetId() );
1643 if ( !g_captureWindow
)
1645 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1646 if (win
->GTKProcessEvent( cevent
))
1648 win
->SetCursor( cevent
.GetCursor() );
1652 bool ret
= win
->GTKProcessEvent(event
);
1654 g_lastMouseEvent
= NULL
;
1659 //-----------------------------------------------------------------------------
1660 // "scroll_event" (mouse wheel event)
1661 //-----------------------------------------------------------------------------
1664 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1668 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1669 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1674 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1675 InitMouseEvent(win
, event
, gdk_event
);
1676 event
.m_linesPerAction
= 3;
1677 event
.m_wheelDelta
= 120;
1678 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1679 event
.m_wheelRotation
= 120;
1681 event
.m_wheelRotation
= -120;
1683 return win
->GTKProcessEvent(event
);
1686 //-----------------------------------------------------------------------------
1688 //-----------------------------------------------------------------------------
1690 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1692 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1693 event
.SetEventObject(win
);
1694 return win
->GTKProcessEvent(event
);
1697 //-----------------------------------------------------------------------------
1699 //-----------------------------------------------------------------------------
1702 gtk_window_focus_in_callback( GtkWidget
* WXUNUSED(widget
),
1703 GdkEventFocus
*WXUNUSED(event
),
1709 gtk_im_context_focus_in(win
->m_imData
->context
);
1712 g_focusWindow
= win
;
1714 wxLogTrace(TRACE_FOCUS
,
1715 _T("%s: focus in"), win
->GetName().c_str());
1718 // caret needs to be informed about focus change
1719 wxCaret
*caret
= win
->GetCaret();
1722 caret
->OnSetFocus();
1724 #endif // wxUSE_CARET
1726 gboolean ret
= FALSE
;
1728 // does the window itself think that it has the focus?
1729 if ( !win
->m_hasFocus
)
1731 // not yet, notify it
1732 win
->m_hasFocus
= true;
1734 (void)DoSendFocusEvents(win
);
1739 // Disable default focus handling for custom windows
1740 // since the default GTK+ handler issues a repaint
1741 if (win
->m_wxwindow
)
1747 //-----------------------------------------------------------------------------
1748 // "focus_out_event"
1749 //-----------------------------------------------------------------------------
1752 gtk_window_focus_out_callback( GtkWidget
* WXUNUSED(widget
),
1753 GdkEventFocus
* WXUNUSED(gdk_event
),
1759 gtk_im_context_focus_out(win
->m_imData
->context
);
1761 wxLogTrace( TRACE_FOCUS
,
1762 _T("%s: focus out"), win
->GetName().c_str() );
1765 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1769 g_focusWindow
= (wxWindowGTK
*)NULL
;
1772 // caret needs to be informed about focus change
1773 wxCaret
*caret
= win
->GetCaret();
1776 caret
->OnKillFocus();
1778 #endif // wxUSE_CARET
1780 // don't send the window a kill focus event if it thinks that it doesn't
1781 // have focus already
1782 if ( win
->m_hasFocus
)
1784 // the event handler might delete the window when it loses focus, so
1785 // check whether this is a custom window before calling it
1786 const bool has_wxwindow
= win
->m_wxwindow
!= NULL
;
1788 win
->m_hasFocus
= false;
1790 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1791 event
.SetEventObject( win
);
1793 (void)win
->GTKProcessEvent( event
);
1795 // Disable default focus handling for custom windows
1796 // since the default GTK+ handler issues a repaint
1801 // continue with normal processing
1806 wx_window_focus_callback(GtkWidget
*widget
,
1807 GtkDirectionType
WXUNUSED(direction
),
1810 // the default handler for focus signal in GtkScrolledWindow sets
1811 // focus to the window itself even if it doesn't accept focus, i.e. has no
1812 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1813 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1814 // any children which might accept focus (we know we don't accept the focus
1815 // ourselves as this signal is only connected in this case)
1816 if ( win
->GetChildren().empty() )
1817 g_signal_stop_emission_by_name(widget
, "focus");
1819 // we didn't change the focus
1823 //-----------------------------------------------------------------------------
1824 // "enter_notify_event"
1825 //-----------------------------------------------------------------------------
1828 gtk_window_enter_callback( GtkWidget
*widget
,
1829 GdkEventCrossing
*gdk_event
,
1832 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1834 // Event was emitted after a grab
1835 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1839 GdkModifierType state
= (GdkModifierType
)0;
1841 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1843 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1844 InitMouseEvent(win
, event
, gdk_event
);
1845 wxPoint pt
= win
->GetClientAreaOrigin();
1846 event
.m_x
= x
+ pt
.x
;
1847 event
.m_y
= y
+ pt
.y
;
1849 if ( !g_captureWindow
)
1851 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1852 if (win
->GTKProcessEvent( cevent
))
1854 win
->SetCursor( cevent
.GetCursor() );
1858 return win
->GTKProcessEvent(event
);
1861 //-----------------------------------------------------------------------------
1862 // "leave_notify_event"
1863 //-----------------------------------------------------------------------------
1866 gtk_window_leave_callback( GtkWidget
*widget
,
1867 GdkEventCrossing
*gdk_event
,
1870 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1872 // Event was emitted after an ungrab
1873 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1875 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1879 GdkModifierType state
= (GdkModifierType
)0;
1881 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1883 InitMouseEvent(win
, event
, gdk_event
);
1885 return win
->GTKProcessEvent(event
);
1888 //-----------------------------------------------------------------------------
1889 // "value_changed" from scrollbar
1890 //-----------------------------------------------------------------------------
1893 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
1895 wxEventType eventType
= win
->GetScrollEventType(range
);
1896 if (eventType
!= wxEVT_NULL
)
1898 // Convert scroll event type to scrollwin event type
1899 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
1901 // find the scrollbar which generated the event
1902 wxWindowGTK::ScrollDir dir
= win
->ScrollDirFromRange(range
);
1904 // generate the corresponding wx event
1905 const int orient
= wxWindow::OrientFromScrollDir(dir
);
1906 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
1907 event
.SetEventObject(win
);
1909 win
->GTKProcessEvent(event
);
1913 //-----------------------------------------------------------------------------
1914 // "button_press_event" from scrollbar
1915 //-----------------------------------------------------------------------------
1918 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
1922 g_blockEventsOnScroll
= true;
1923 win
->m_mouseButtonDown
= true;
1928 //-----------------------------------------------------------------------------
1929 // "event_after" from scrollbar
1930 //-----------------------------------------------------------------------------
1933 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
1935 if (event
->type
== GDK_BUTTON_RELEASE
)
1937 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1939 const int orient
= wxWindow::OrientFromScrollDir(
1940 win
->ScrollDirFromRange(range
));
1941 wxScrollWinEvent
evt(wxEVT_SCROLLWIN_THUMBRELEASE
,
1942 win
->GetScrollPos(orient
), orient
);
1943 evt
.SetEventObject(win
);
1944 win
->GTKProcessEvent(evt
);
1948 //-----------------------------------------------------------------------------
1949 // "button_release_event" from scrollbar
1950 //-----------------------------------------------------------------------------
1953 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
1957 g_blockEventsOnScroll
= false;
1958 win
->m_mouseButtonDown
= false;
1959 // If thumb tracking
1960 if (win
->m_isScrolling
)
1962 win
->m_isScrolling
= false;
1963 // Hook up handler to send thumb release event after this emission is finished.
1964 // To allow setting scroll position from event handler, sending event must
1965 // be deferred until after the GtkRange handler for this signal has run
1966 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
1972 //-----------------------------------------------------------------------------
1973 // "realize" from m_widget
1974 //-----------------------------------------------------------------------------
1977 gtk_window_realized_callback(GtkWidget
* widget
, wxWindow
* win
)
1983 gtk_im_context_set_client_window( win
->m_imData
->context
,
1987 // We cannot set colours and fonts before the widget
1988 // been realized, so we do this directly after realization
1989 // or otherwise in idle time
1991 if (win
->m_needsStyleChange
)
1993 win
->SetBackgroundStyle(win
->GetBackgroundStyle());
1994 win
->m_needsStyleChange
= false;
1997 wxWindowCreateEvent
event( win
);
1998 event
.SetEventObject( win
);
1999 win
->GTKProcessEvent( event
);
2002 //-----------------------------------------------------------------------------
2003 // "size_allocate" from m_wxwindow or m_widget
2004 //-----------------------------------------------------------------------------
2007 size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxWindow
* win
)
2009 int w
= alloc
->width
;
2010 int h
= alloc
->height
;
2011 if (win
->m_wxwindow
)
2013 int border_x
, border_y
;
2014 WX_PIZZA(win
->m_wxwindow
)->get_border_widths(border_x
, border_y
);
2020 if (win
->m_oldClientWidth
!= w
|| win
->m_oldClientHeight
!= h
)
2022 win
->m_oldClientWidth
= w
;
2023 win
->m_oldClientHeight
= h
;
2024 // this callback can be connected to m_wxwindow,
2025 // so always get size from m_widget->allocation
2026 win
->m_width
= win
->m_widget
->allocation
.width
;
2027 win
->m_height
= win
->m_widget
->allocation
.height
;
2028 if (!win
->m_nativeSizeEvent
)
2030 wxSizeEvent
event(win
->GetSize(), win
->GetId());
2031 event
.SetEventObject(win
);
2032 win
->GTKProcessEvent(event
);
2037 //-----------------------------------------------------------------------------
2039 //-----------------------------------------------------------------------------
2041 #if GTK_CHECK_VERSION(2, 8, 0)
2043 gtk_window_grab_broken( GtkWidget
*,
2044 GdkEventGrabBroken
*event
,
2047 // Mouse capture has been lost involuntarily, notify the application
2048 if(!event
->keyboard
&& wxWindow::GetCapture() == win
)
2050 wxMouseCaptureLostEvent
evt( win
->GetId() );
2051 evt
.SetEventObject( win
);
2052 win
->GetEventHandler()->ProcessEvent( evt
);
2058 //-----------------------------------------------------------------------------
2060 //-----------------------------------------------------------------------------
2063 void gtk_window_style_set_callback( GtkWidget
*WXUNUSED(widget
),
2064 GtkStyle
*previous_style
,
2067 //wxLogDebug(wxT("gtk_window_style_set_callback"));
2068 if (win
&& previous_style
)
2070 wxString
name(win
->GetName());
2071 //wxLogDebug(wxT("gtk_window_style_set_callback %s"), name.c_str());
2072 wxSysColourChangedEvent event
;
2073 event
.SetEventObject(win
);
2075 win
->GTKProcessEvent( event
);
2081 // Connect/disconnect style-set
2083 void wxConnectStyleSet(wxWindow
* win
)
2085 if (win
->m_wxwindow
)
2086 g_signal_connect (win
->m_wxwindow
, "style_set",
2087 G_CALLBACK (gtk_window_style_set_callback
), win
);
2090 void wxDisconnectStyleSet(wxWindow
* win
)
2092 if (win
->m_wxwindow
)
2093 g_signal_handlers_disconnect_by_func (win
->m_wxwindow
,
2094 (gpointer
) gtk_window_style_set_callback
,
2098 // Helper to suspend colour change event event processing while we change a widget's style
2099 class wxSuspendStyleEvents
2102 wxSuspendStyleEvents(wxWindow
* win
)
2105 if (win
->IsTopLevel())
2106 wxDisconnectStyleSet(win
);
2108 ~wxSuspendStyleEvents()
2110 if (m_win
->IsTopLevel())
2111 wxConnectStyleSet(m_win
);
2117 // ----------------------------------------------------------------------------
2118 // this wxWindowBase function is implemented here (in platform-specific file)
2119 // because it is static and so couldn't be made virtual
2120 // ----------------------------------------------------------------------------
2122 wxWindow
*wxWindowBase::DoFindFocus()
2124 // the cast is necessary when we compile in wxUniversal mode
2125 return (wxWindow
*)g_focusWindow
;
2128 //-----------------------------------------------------------------------------
2129 // InsertChild for wxWindowGTK.
2130 //-----------------------------------------------------------------------------
2132 /* Callback for wxWindowGTK. This very strange beast has to be used because
2133 * C++ has no virtual methods in a constructor. We have to emulate a
2134 * virtual function here as wxNotebook requires a different way to insert
2135 * a child in it. I had opted for creating a wxNotebookPage window class
2136 * which would have made this superfluous (such in the MDI window system),
2137 * but no-one was listening to me... */
2139 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2141 /* the window might have been scrolled already, do we
2142 have to adapt the position */
2143 wxPizza
* pizza
= WX_PIZZA(parent
->m_wxwindow
);
2144 child
->m_x
+= pizza
->m_scroll_x
;
2145 child
->m_y
+= pizza
->m_scroll_y
;
2147 gtk_widget_set_size_request(
2148 child
->m_widget
, child
->m_width
, child
->m_height
);
2150 GTK_FIXED(parent
->m_wxwindow
), child
->m_widget
, child
->m_x
, child
->m_y
);
2153 //-----------------------------------------------------------------------------
2155 //-----------------------------------------------------------------------------
2157 wxWindow
*wxGetActiveWindow()
2159 return wxWindow::FindFocus();
2163 wxMouseState
wxGetMouseState()
2169 GdkModifierType mask
;
2171 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2175 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2176 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2177 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2178 ms
.SetAux1Down(mask
& GDK_BUTTON4_MASK
);
2179 ms
.SetAux2Down(mask
& GDK_BUTTON5_MASK
);
2181 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2182 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2183 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2184 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2189 //-----------------------------------------------------------------------------
2191 //-----------------------------------------------------------------------------
2193 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2195 #ifdef __WXUNIVERSAL__
2196 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2198 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2199 #endif // __WXUNIVERSAL__/__WXGTK__
2201 void wxWindowGTK::Init()
2204 m_widget
= (GtkWidget
*) NULL
;
2205 m_wxwindow
= (GtkWidget
*) NULL
;
2206 m_focusWidget
= (GtkWidget
*) NULL
;
2215 m_isBeingDeleted
= false;
2217 m_showOnIdle
= false;
2220 m_nativeSizeEvent
= false;
2222 m_hasScrolling
= false;
2223 m_isScrolling
= false;
2224 m_mouseButtonDown
= false;
2226 // initialize scrolling stuff
2227 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2229 m_scrollBar
[dir
] = NULL
;
2230 m_scrollPos
[dir
] = 0;
2234 m_oldClientHeight
= 0;
2236 m_insertCallback
= wxInsertChildInWindow
;
2240 m_clipPaintRegion
= false;
2242 m_needsStyleChange
= false;
2244 m_cursor
= *wxSTANDARD_CURSOR
;
2247 m_dirtyTabOrder
= false;
2250 wxWindowGTK::wxWindowGTK()
2255 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2260 const wxString
&name
)
2264 Create( parent
, id
, pos
, size
, style
, name
);
2267 bool wxWindowGTK::Create( wxWindow
*parent
,
2272 const wxString
&name
)
2274 if (!PreCreation( parent
, pos
, size
) ||
2275 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2277 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2281 m_wxwindow
= wxPizza::New(m_windowStyle
);
2282 if (!HasFlag(wxHSCROLL
) && !HasFlag(wxVSCROLL
))
2283 m_widget
= m_wxwindow
;
2286 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2287 gtk_container_set_resize_mode(GTK_CONTAINER(m_widget
), GTK_RESIZE_QUEUE
);
2289 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2291 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2292 scroll_class
->scrollbar_spacing
= 0;
2294 // There is a conflict with default bindings at GTK+
2295 // level between scrolled windows and notebooks both of which want to use
2296 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2297 // direction and notebooks for changing pages -- we decide that if we don't
2298 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2299 // means we can get working keyboard navigation in notebooks
2300 if ( !HasFlag(wxHSCROLL
) )
2303 bindings
= gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget
));
2306 gtk_binding_entry_remove(bindings
, GDK_Page_Up
, GDK_CONTROL_MASK
);
2307 gtk_binding_entry_remove(bindings
, GDK_Page_Down
, GDK_CONTROL_MASK
);
2311 if (HasFlag(wxALWAYS_SHOW_SB
))
2313 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
2315 scrolledWindow
->hscrollbar_visible
= TRUE
;
2316 scrolledWindow
->vscrollbar_visible
= TRUE
;
2320 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2323 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2324 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2325 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2326 gtk_range_set_inverted( m_scrollBar
[ScrollDir_Horz
], TRUE
);
2328 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2330 // connect various scroll-related events
2331 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2333 // these handlers block mouse events to any window during scrolling
2334 // such as motion events and prevent GTK and wxWidgets from fighting
2335 // over where the slider should be
2336 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2337 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2338 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2339 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2341 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2342 G_CALLBACK(gtk_scrollbar_event_after
), this);
2343 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2345 // these handlers get notified when scrollbar slider moves
2346 g_signal_connect_after(m_scrollBar
[dir
], "value_changed",
2347 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2350 gtk_widget_show( m_wxwindow
);
2354 m_parent
->DoAddChild( this );
2356 m_focusWidget
= m_wxwindow
;
2363 wxWindowGTK::~wxWindowGTK()
2367 if (g_focusWindow
== this)
2368 g_focusWindow
= NULL
;
2370 if ( g_delayedFocus
== this )
2371 g_delayedFocus
= NULL
;
2373 m_isBeingDeleted
= true;
2376 // destroy children before destroying this window itself
2379 // unhook focus handlers to prevent stray events being
2380 // propagated to this (soon to be) dead object
2381 if (m_focusWidget
!= NULL
)
2383 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2384 (gpointer
) gtk_window_focus_in_callback
,
2386 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2387 (gpointer
) gtk_window_focus_out_callback
,
2394 // delete before the widgets to avoid a crash on solaris
2397 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2399 gtk_widget_destroy( m_wxwindow
);
2400 m_wxwindow
= (GtkWidget
*) NULL
;
2405 gtk_widget_destroy( m_widget
);
2406 m_widget
= (GtkWidget
*) NULL
;
2410 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2412 if ( GTKNeedsParent() )
2414 wxCHECK_MSG( parent
, false, wxT("Must have non-NULL parent") );
2417 // Use either the given size, or the default if -1 is given.
2418 // See wxWindowBase for these functions.
2419 m_width
= WidthDefault(size
.x
) ;
2420 m_height
= HeightDefault(size
.y
);
2428 void wxWindowGTK::PostCreation()
2430 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2436 // these get reported to wxWidgets -> wxPaintEvent
2438 g_signal_connect (m_wxwindow
, "expose_event",
2439 G_CALLBACK (gtk_window_expose_callback
), this);
2441 if (GetLayoutDirection() == wxLayout_LeftToRight
)
2442 gtk_widget_set_redraw_on_allocate(m_wxwindow
, HasFlag(wxFULL_REPAINT_ON_RESIZE
));
2445 // Create input method handler
2446 m_imData
= new wxGtkIMData
;
2448 // Cannot handle drawing preedited text yet
2449 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2451 g_signal_connect (m_imData
->context
, "commit",
2452 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2455 #ifndef __WXUNIVERSAL__
2456 if (HasFlag(wxBORDER_SIMPLE
| wxBORDER_RAISED
| wxBORDER_SUNKEN
))
2458 g_signal_connect(m_widget
, "expose_event",
2459 G_CALLBACK(expose_event_border
), this);
2466 if (!GTK_IS_WINDOW(m_widget
))
2468 if (m_focusWidget
== NULL
)
2469 m_focusWidget
= m_widget
;
2473 g_signal_connect (m_focusWidget
, "focus_in_event",
2474 G_CALLBACK (gtk_window_focus_in_callback
), this);
2475 g_signal_connect (m_focusWidget
, "focus_out_event",
2476 G_CALLBACK (gtk_window_focus_out_callback
), this);
2480 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2481 G_CALLBACK (gtk_window_focus_in_callback
), this);
2482 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2483 G_CALLBACK (gtk_window_focus_out_callback
), this);
2487 if ( !AcceptsFocusFromKeyboard() )
2491 g_signal_connect(m_widget
, "focus",
2492 G_CALLBACK(wx_window_focus_callback
), this);
2495 // connect to the various key and mouse handlers
2497 GtkWidget
*connect_widget
= GetConnectWidget();
2499 ConnectWidget( connect_widget
);
2501 /* We cannot set colours, fonts and cursors before the widget has
2502 been realized, so we do this directly after realization */
2503 g_signal_connect (connect_widget
, "realize",
2504 G_CALLBACK (gtk_window_realized_callback
), this);
2508 g_signal_connect(m_wxwindow
? m_wxwindow
: m_widget
, "size_allocate",
2509 G_CALLBACK(size_allocate
), this);
2514 #if GTK_CHECK_VERSION(2, 8, 0)
2515 if (!gtk_check_version(2,8,0))
2517 // Make sure we can notify the app when mouse capture is lost
2518 g_signal_connect (m_wxwindow
, "grab_broken_event",
2519 G_CALLBACK (gtk_window_grab_broken
), this);
2524 if ( connect_widget
!= m_wxwindow
)
2526 #if GTK_CHECK_VERSION(2, 8, 0)
2527 if (!gtk_check_version(2,8,0))
2529 // Make sure we can notify app code when mouse capture is lost
2530 g_signal_connect (connect_widget
, "grab_broken_event",
2531 G_CALLBACK (gtk_window_grab_broken
), this);
2537 if (GTK_IS_COMBO(m_widget
))
2539 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2541 g_signal_connect (gcombo
->entry
, "size_request",
2542 G_CALLBACK (wxgtk_combo_size_request_callback
),
2545 #endif // wxUSE_COMBOBOX
2546 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2547 if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2549 // If we connect to the "size_request" signal of a GtkFileChooserButton
2550 // then that control won't be sized properly when placed inside sizers
2551 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2552 // FIXME: what should be done here ?
2555 if ( !IsTopLevel() ) // top level windows use their own callback
2557 // This is needed if we want to add our windows into native
2558 // GTK controls, such as the toolbar. With this callback, the
2559 // toolbar gets to know the correct size (the one set by the
2560 // programmer). Sadly, it misbehaves for wxComboBox.
2561 g_signal_connect (m_widget
, "size_request",
2562 G_CALLBACK (wxgtk_window_size_request_callback
),
2566 InheritAttributes();
2570 SetLayoutDirection(wxLayout_Default
);
2572 // unless the window was created initially hidden (i.e. Hide() had been
2573 // called before Create()), we should show it at GTK+ level as well
2575 gtk_widget_show( m_widget
);
2578 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2580 g_signal_connect (widget
, "key_press_event",
2581 G_CALLBACK (gtk_window_key_press_callback
), this);
2582 g_signal_connect (widget
, "key_release_event",
2583 G_CALLBACK (gtk_window_key_release_callback
), this);
2584 g_signal_connect (widget
, "button_press_event",
2585 G_CALLBACK (gtk_window_button_press_callback
), this);
2586 g_signal_connect (widget
, "button_release_event",
2587 G_CALLBACK (gtk_window_button_release_callback
), this);
2588 g_signal_connect (widget
, "motion_notify_event",
2589 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2590 g_signal_connect (widget
, "scroll_event",
2591 G_CALLBACK (window_scroll_event
), this);
2592 g_signal_connect (widget
, "popup_menu",
2593 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2594 g_signal_connect (widget
, "enter_notify_event",
2595 G_CALLBACK (gtk_window_enter_callback
), this);
2596 g_signal_connect (widget
, "leave_notify_event",
2597 G_CALLBACK (gtk_window_leave_callback
), this);
2599 if (IsTopLevel() && m_wxwindow
)
2600 g_signal_connect (m_wxwindow
, "style_set",
2601 G_CALLBACK (gtk_window_style_set_callback
), this);
2604 bool wxWindowGTK::Destroy()
2606 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2610 return wxWindowBase::Destroy();
2613 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2615 gtk_widget_set_size_request(m_widget
, width
, height
);
2616 // inform the parent to perform the move
2617 WX_PIZZA(m_parent
->m_wxwindow
)->move(m_widget
, x
, y
);
2620 void wxWindowGTK::ConstrainSize()
2623 // GPE's window manager doesn't like size hints at all, esp. when the user
2624 // has to use the virtual keyboard, so don't constrain size there
2628 const wxSize minSize
= GetMinSize();
2629 const wxSize maxSize
= GetMaxSize();
2630 if (minSize
.x
> 0 && m_width
< minSize
.x
) m_width
= minSize
.x
;
2631 if (minSize
.y
> 0 && m_height
< minSize
.y
) m_height
= minSize
.y
;
2632 if (maxSize
.x
> 0 && m_width
> maxSize
.x
) m_width
= maxSize
.x
;
2633 if (maxSize
.y
> 0 && m_height
> maxSize
.y
) m_height
= maxSize
.y
;
2637 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2639 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2640 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2642 int currentX
, currentY
;
2643 GetPosition(¤tX
, ¤tY
);
2644 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2646 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2648 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2650 // calculate the best size if we should auto size the window
2651 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2652 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2654 const wxSize sizeBest
= GetBestSize();
2655 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2657 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2658 height
= sizeBest
.y
;
2661 const wxSize
oldSize(m_width
, m_height
);
2669 if (m_parent
->m_wxwindow
)
2671 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2672 m_x
= x
+ pizza
->m_scroll_x
;
2673 m_y
= y
+ pizza
->m_scroll_y
;
2675 int left_border
= 0;
2676 int right_border
= 0;
2678 int bottom_border
= 0;
2680 /* the default button has a border around it */
2681 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2683 GtkBorder
*default_border
= NULL
;
2684 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2687 left_border
+= default_border
->left
;
2688 right_border
+= default_border
->right
;
2689 top_border
+= default_border
->top
;
2690 bottom_border
+= default_border
->bottom
;
2691 gtk_border_free( default_border
);
2695 DoMoveWindow( m_x
- left_border
,
2697 m_width
+left_border
+right_border
,
2698 m_height
+top_border
+bottom_border
);
2701 if (m_width
!= oldSize
.x
|| m_height
!= oldSize
.y
)
2703 // update these variables to keep size_allocate handler
2704 // from sending another size event for this change
2705 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2707 gtk_widget_queue_resize(m_widget
);
2708 if (!m_nativeSizeEvent
)
2710 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2711 event
.SetEventObject( this );
2712 GetEventHandler()->ProcessEvent( event
);
2717 bool wxWindowGTK::GtkShowFromOnIdle()
2719 if (IsShown() && m_showOnIdle
&& !GTK_WIDGET_VISIBLE (m_widget
))
2721 GtkAllocation alloc
;
2724 alloc
.width
= m_width
;
2725 alloc
.height
= m_height
;
2726 gtk_widget_size_allocate( m_widget
, &alloc
);
2727 gtk_widget_show( m_widget
);
2728 wxShowEvent
eventShow(GetId(), true);
2729 eventShow
.SetEventObject(this);
2730 GetEventHandler()->ProcessEvent(eventShow
);
2731 m_showOnIdle
= false;
2738 void wxWindowGTK::OnInternalIdle()
2740 // Check if we have to show window now
2741 if (GtkShowFromOnIdle()) return;
2743 if ( m_dirtyTabOrder
)
2745 m_dirtyTabOrder
= false;
2749 // Update style if the window was not yet realized
2750 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2751 if (m_needsStyleChange
)
2753 SetBackgroundStyle(GetBackgroundStyle());
2754 m_needsStyleChange
= false;
2757 wxCursor cursor
= m_cursor
;
2758 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2762 /* I now set the cursor anew in every OnInternalIdle call
2763 as setting the cursor in a parent window also effects the
2764 windows above so that checking for the current cursor is
2767 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2769 GdkWindow
*window
= m_wxwindow
->window
;
2771 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2773 if (!g_globalCursor
.Ok())
2774 cursor
= *wxSTANDARD_CURSOR
;
2776 window
= m_widget
->window
;
2777 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2778 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2781 else if ( m_widget
)
2783 GdkWindow
*window
= m_widget
->window
;
2784 if ( window
&& !GTK_WIDGET_NO_WINDOW(m_widget
) )
2785 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2789 if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
2790 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2793 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2795 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2797 if (width
) (*width
) = m_width
;
2798 if (height
) (*height
) = m_height
;
2801 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2803 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2805 const wxSize size
= GetSize();
2806 const wxSize clientSize
= GetClientSize();
2807 SetSize(width
+ (size
.x
- clientSize
.x
), height
+ (size
.y
- clientSize
.y
));
2810 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2812 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2823 GetScrollbarWidth(m_widget
, dw
, dh
);
2825 int border_x
, border_y
;
2826 WX_PIZZA(m_wxwindow
)->get_border_widths(border_x
, border_y
);
2838 if (width
) *width
= w
;
2839 if (height
) *height
= h
;
2842 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2844 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2848 if (!IsTopLevel() && m_parent
&& m_parent
->m_wxwindow
)
2850 wxPizza
* pizza
= WX_PIZZA(m_parent
->m_wxwindow
);
2851 dx
= pizza
->m_scroll_x
;
2852 dy
= pizza
->m_scroll_y
;
2855 if (m_x
== -1 && m_y
== -1)
2857 GdkWindow
*source
= (GdkWindow
*) NULL
;
2859 source
= m_wxwindow
->window
;
2861 source
= m_widget
->window
;
2867 gdk_window_get_origin( source
, &org_x
, &org_y
);
2870 m_parent
->ScreenToClient(&org_x
, &org_y
);
2872 wx_const_cast(wxWindowGTK
*, this)->m_x
= org_x
;
2873 wx_const_cast(wxWindowGTK
*, this)->m_y
= org_y
;
2877 if (x
) (*x
) = m_x
- dx
;
2878 if (y
) (*y
) = m_y
- dy
;
2881 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2883 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2885 if (!m_widget
->window
) return;
2887 GdkWindow
*source
= (GdkWindow
*) NULL
;
2889 source
= m_wxwindow
->window
;
2891 source
= m_widget
->window
;
2895 gdk_window_get_origin( source
, &org_x
, &org_y
);
2899 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2901 org_x
+= m_widget
->allocation
.x
;
2902 org_y
+= m_widget
->allocation
.y
;
2909 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2910 *x
= (GetClientSize().x
- *x
) + org_x
;
2918 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
2920 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2922 if (!m_widget
->window
) return;
2924 GdkWindow
*source
= (GdkWindow
*) NULL
;
2926 source
= m_wxwindow
->window
;
2928 source
= m_widget
->window
;
2932 gdk_window_get_origin( source
, &org_x
, &org_y
);
2936 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2938 org_x
+= m_widget
->allocation
.x
;
2939 org_y
+= m_widget
->allocation
.y
;
2945 if (GetLayoutDirection() == wxLayout_RightToLeft
)
2946 *x
= (GetClientSize().x
- *x
) - org_x
;
2953 bool wxWindowGTK::Show( bool show
)
2955 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
2957 if (!wxWindowBase::Show(show
))
2967 gtk_widget_show( m_widget
);
2968 wxShowEvent
eventShow(GetId(), show
);
2969 eventShow
.SetEventObject(this);
2970 GetEventHandler()->ProcessEvent(eventShow
);
2975 gtk_widget_hide( m_widget
);
2976 wxShowEvent
eventShow(GetId(), show
);
2977 eventShow
.SetEventObject(this);
2978 GetEventHandler()->ProcessEvent(eventShow
);
2984 void wxWindowGTK::DoEnable( bool enable
)
2986 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2988 gtk_widget_set_sensitive( m_widget
, enable
);
2989 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
2990 gtk_widget_set_sensitive( m_wxwindow
, enable
);
2993 int wxWindowGTK::GetCharHeight() const
2995 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
2997 wxFont font
= GetFont();
2998 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3000 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
3005 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3006 PangoLayout
*layout
= pango_layout_new(context
);
3007 pango_layout_set_font_description(layout
, desc
);
3008 pango_layout_set_text(layout
, "H", 1);
3009 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3011 PangoRectangle rect
;
3012 pango_layout_line_get_extents(line
, NULL
, &rect
);
3014 g_object_unref (layout
);
3016 return (int) PANGO_PIXELS(rect
.height
);
3019 int wxWindowGTK::GetCharWidth() const
3021 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3023 wxFont font
= GetFont();
3024 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3026 PangoContext
* context
= gtk_widget_get_pango_context(m_widget
);
3031 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3032 PangoLayout
*layout
= pango_layout_new(context
);
3033 pango_layout_set_font_description(layout
, desc
);
3034 pango_layout_set_text(layout
, "g", 1);
3035 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3037 PangoRectangle rect
;
3038 pango_layout_line_get_extents(line
, NULL
, &rect
);
3040 g_object_unref (layout
);
3042 return (int) PANGO_PIXELS(rect
.width
);
3045 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3049 int *externalLeading
,
3050 const wxFont
*theFont
) const
3052 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3054 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3063 PangoContext
*context
= NULL
;
3065 context
= gtk_widget_get_pango_context( m_widget
);
3074 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3075 PangoLayout
*layout
= pango_layout_new(context
);
3076 pango_layout_set_font_description(layout
, desc
);
3078 const wxCharBuffer data
= wxGTK_CONV( string
);
3080 pango_layout_set_text(layout
, data
, strlen(data
));
3083 PangoRectangle rect
;
3084 pango_layout_get_extents(layout
, NULL
, &rect
);
3086 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3087 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3090 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3091 int baseline
= pango_layout_iter_get_baseline(iter
);
3092 pango_layout_iter_free(iter
);
3093 *descent
= *y
- PANGO_PIXELS(baseline
);
3095 if (externalLeading
) (*externalLeading
) = 0; // ??
3097 g_object_unref (layout
);
3100 bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
3102 if ( g_delayedFocus
== this )
3104 if ( GTK_WIDGET_REALIZED(m_widget
) )
3106 gtk_widget_grab_focus(m_widget
);
3107 g_delayedFocus
= NULL
;
3116 void wxWindowGTK::SetFocus()
3118 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3121 // don't do anything if we already have focus
3127 // wxWindow::SetFocus() should really set the focus to
3128 // this control, whatever the flags are
3129 if (!GTK_WIDGET_CAN_FOCUS(m_wxwindow
))
3130 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3132 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3134 gtk_widget_grab_focus (m_wxwindow
);
3139 // wxWindow::SetFocus() should really set the focus to
3140 // this control, whatever the flags are
3141 if (!GTK_WIDGET_CAN_FOCUS(m_widget
))
3142 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3144 if (GTK_IS_CONTAINER(m_widget
))
3146 if (GTK_IS_RADIO_BUTTON(m_widget
))
3148 gtk_widget_grab_focus (m_widget
);
3152 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3155 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3158 if (!GTK_WIDGET_REALIZED(m_widget
))
3160 // we can't set the focus to the widget now so we remember that
3161 // it should be focused and will do it later, during the idle
3162 // time, as soon as we can
3163 wxLogTrace(TRACE_FOCUS
,
3164 _T("Delaying setting focus to %s(%s)"),
3165 GetClassInfo()->GetClassName(), GetLabel().c_str());
3167 g_delayedFocus
= this;
3171 wxLogTrace(TRACE_FOCUS
,
3172 _T("Setting focus to %s(%s)"),
3173 GetClassInfo()->GetClassName(), GetLabel().c_str());
3175 gtk_widget_grab_focus (m_widget
);
3180 wxLogTrace(TRACE_FOCUS
,
3181 _T("Can't set focus to %s(%s)"),
3182 GetClassInfo()->GetClassName(), GetLabel().c_str());
3187 void wxWindowGTK::SetCanFocus(bool canFocus
)
3190 GTK_WIDGET_SET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3192 GTK_WIDGET_UNSET_FLAGS(m_widget
, GTK_CAN_FOCUS
);
3194 if ( m_wxwindow
&& (m_widget
!= m_wxwindow
) )
3197 GTK_WIDGET_SET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3199 GTK_WIDGET_UNSET_FLAGS(m_wxwindow
, GTK_CAN_FOCUS
);
3203 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3205 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3207 wxWindowGTK
*oldParent
= m_parent
,
3208 *newParent
= (wxWindowGTK
*)newParentBase
;
3210 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3212 if ( !wxWindowBase::Reparent(newParent
) )
3215 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3217 /* prevent GTK from deleting the widget arbitrarily */
3218 gtk_widget_ref( m_widget
);
3222 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3225 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3229 if (GTK_WIDGET_VISIBLE (newParent
->m_widget
))
3231 m_showOnIdle
= true;
3232 gtk_widget_hide( m_widget
);
3235 /* insert GTK representation */
3236 (*(newParent
->m_insertCallback
))(newParent
, this);
3239 /* reverse: prevent GTK from deleting the widget arbitrarily */
3240 gtk_widget_unref( m_widget
);
3242 SetLayoutDirection(wxLayout_Default
);
3247 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3249 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3250 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3255 /* insert GTK representation */
3256 (*m_insertCallback
)(this, child
);
3259 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3261 wxWindowBase::AddChild(child
);
3262 m_dirtyTabOrder
= true;
3263 wxTheApp
->WakeUpIdle();
3266 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3268 wxWindowBase::RemoveChild(child
);
3269 m_dirtyTabOrder
= true;
3270 wxTheApp
->WakeUpIdle();
3274 wxLayoutDirection
wxWindowGTK::GTKGetLayout(GtkWidget
*widget
)
3276 return gtk_widget_get_direction(widget
) == GTK_TEXT_DIR_RTL
3277 ? wxLayout_RightToLeft
3278 : wxLayout_LeftToRight
;
3282 void wxWindowGTK::GTKSetLayout(GtkWidget
*widget
, wxLayoutDirection dir
)
3284 wxASSERT_MSG( dir
!= wxLayout_Default
, _T("invalid layout direction") );
3286 gtk_widget_set_direction(widget
,
3287 dir
== wxLayout_RightToLeft
? GTK_TEXT_DIR_RTL
3288 : GTK_TEXT_DIR_LTR
);
3291 wxLayoutDirection
wxWindowGTK::GetLayoutDirection() const
3293 return GTKGetLayout(m_widget
);
3296 void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir
)
3298 if ( dir
== wxLayout_Default
)
3300 const wxWindow
*const parent
= GetParent();
3303 // inherit layout from parent.
3304 dir
= parent
->GetLayoutDirection();
3306 else // no parent, use global default layout
3308 dir
= wxTheApp
->GetLayoutDirection();
3312 if ( dir
== wxLayout_Default
)
3315 GTKSetLayout(m_widget
, dir
);
3317 if (m_wxwindow
&& (m_wxwindow
!= m_widget
))
3318 GTKSetLayout(m_wxwindow
, dir
);
3322 wxWindowGTK::AdjustForLayoutDirection(wxCoord x
,
3323 wxCoord
WXUNUSED(width
),
3324 wxCoord
WXUNUSED(widthTotal
)) const
3326 // We now mirror the coordinates of RTL windows in wxPizza
3330 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3332 wxWindowBase::DoMoveInTabOrder(win
, move
);
3333 m_dirtyTabOrder
= true;
3334 wxTheApp
->WakeUpIdle();
3337 bool wxWindowGTK::DoNavigateIn(int flags
)
3339 if ( flags
& wxNavigationKeyEvent::WinChange
)
3341 wxFAIL_MSG( _T("not implemented") );
3345 else // navigate inside the container
3347 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3348 wxCHECK_MSG( parent
, false, _T("every window must have a TLW parent") );
3350 GtkDirectionType dir
;
3351 dir
= flags
& wxNavigationKeyEvent::IsForward
? GTK_DIR_TAB_FORWARD
3352 : GTK_DIR_TAB_BACKWARD
;
3355 g_signal_emit_by_name(parent
->m_widget
, "focus", dir
, &rc
);
3361 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3363 // none needed by default
3367 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3369 // nothing to do by default since none is needed
3372 void wxWindowGTK::RealizeTabOrder()
3376 if ( !m_children
.empty() )
3378 // we don't only construct the correct focus chain but also use
3379 // this opportunity to update the mnemonic widgets for the widgets
3382 GList
*chain
= NULL
;
3383 wxWindowGTK
* mnemonicWindow
= NULL
;
3385 for ( wxWindowList::const_iterator i
= m_children
.begin();
3386 i
!= m_children
.end();
3389 wxWindowGTK
*win
= *i
;
3391 if ( mnemonicWindow
)
3393 if ( win
->AcceptsFocusFromKeyboard() )
3395 // wxComboBox et al. needs to focus on on a different
3396 // widget than m_widget, so if the main widget isn't
3397 // focusable try the connect widget
3398 GtkWidget
* w
= win
->m_widget
;
3399 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3401 w
= win
->GetConnectWidget();
3402 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3408 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3409 mnemonicWindow
= NULL
;
3413 else if ( win
->GTKWidgetNeedsMnemonic() )
3415 mnemonicWindow
= win
;
3418 chain
= g_list_prepend(chain
, win
->m_widget
);
3421 chain
= g_list_reverse(chain
);
3423 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3428 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3433 void wxWindowGTK::Raise()
3435 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3437 if (m_wxwindow
&& m_wxwindow
->window
)
3439 gdk_window_raise( m_wxwindow
->window
);
3441 else if (m_widget
->window
)
3443 gdk_window_raise( m_widget
->window
);
3447 void wxWindowGTK::Lower()
3449 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3451 if (m_wxwindow
&& m_wxwindow
->window
)
3453 gdk_window_lower( m_wxwindow
->window
);
3455 else if (m_widget
->window
)
3457 gdk_window_lower( m_widget
->window
);
3461 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3463 if ( !wxWindowBase::SetCursor(cursor
.Ok() ? cursor
: *wxSTANDARD_CURSOR
) )
3471 void wxWindowGTK::GTKUpdateCursor()
3473 wxCursor
cursor(g_globalCursor
.Ok() ? g_globalCursor
: GetCursor());
3476 wxArrayGdkWindows windowsThis
;
3477 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3480 gdk_window_set_cursor(winThis
, cursor
.GetCursor());
3484 const size_t count
= windowsThis
.size();
3485 for ( size_t n
= 0; n
< count
; n
++ )
3487 GdkWindow
*win
= windowsThis
[n
];
3490 wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?"));
3494 gdk_window_set_cursor(win
, cursor
.GetCursor());
3500 void wxWindowGTK::WarpPointer( int x
, int y
)
3502 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3504 // We provide this function ourselves as it is
3505 // missing in GDK (top of this file).
3507 GdkWindow
*window
= (GdkWindow
*) NULL
;
3509 window
= m_wxwindow
->window
;
3511 window
= GetConnectWidget()->window
;
3514 gdk_window_warp_pointer( window
, x
, y
);
3517 wxWindowGTK::ScrollDir
wxWindowGTK::ScrollDirFromRange(GtkRange
*range
) const
3519 // find the scrollbar which generated the event
3520 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3522 if ( range
== m_scrollBar
[dir
] )
3523 return (ScrollDir
)dir
;
3526 wxFAIL_MSG( _T("event from unknown scrollbar received") );
3528 return ScrollDir_Max
;
3531 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3533 bool changed
= false;
3534 GtkRange
* range
= m_scrollBar
[dir
];
3535 if ( range
&& units
)
3537 GtkAdjustment
* adj
= range
->adjustment
;
3538 gdouble inc
= unit
== ScrollUnit_Line
? adj
->step_increment
3539 : adj
->page_increment
;
3541 const int posOld
= int(adj
->value
+ 0.5);
3542 gtk_range_set_value(range
, posOld
+ units
*inc
);
3544 changed
= int(adj
->value
+ 0.5) != posOld
;
3550 bool wxWindowGTK::ScrollLines(int lines
)
3552 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3555 bool wxWindowGTK::ScrollPages(int pages
)
3557 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3560 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground
),
3565 if (!m_widget
->window
)
3570 if (m_wxwindow
->window
== NULL
) return;
3572 GdkRectangle gdk_rect
,
3576 gdk_rect
.x
= rect
->x
;
3577 gdk_rect
.y
= rect
->y
;
3578 gdk_rect
.width
= rect
->width
;
3579 gdk_rect
.height
= rect
->height
;
3580 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3581 gdk_rect
.x
= GetClientSize().x
- gdk_rect
.x
- gdk_rect
.width
;
3585 else // invalidate everything
3590 gdk_window_invalidate_rect(m_wxwindow
->window
, p
, true);
3594 void wxWindowGTK::Update()
3598 // when we call Update() we really want to update the window immediately on
3599 // screen, even if it means flushing the entire queue and hence slowing down
3600 // everything -- but it should still be done, it's just that Update() should
3601 // be called very rarely
3605 void wxWindowGTK::GtkUpdate()
3607 if (m_wxwindow
&& m_wxwindow
->window
)
3608 gdk_window_process_updates(m_wxwindow
->window
, false);
3609 if (m_widget
&& m_widget
->window
&& (m_wxwindow
!= m_widget
))
3610 gdk_window_process_updates( m_widget
->window
, FALSE
);
3612 // for consistency with other platforms (and also because it's convenient
3613 // to be able to update an entire TLW by calling Update() only once), we
3614 // should also update all our children here
3615 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3617 node
= node
->GetNext() )
3619 node
->GetData()->GtkUpdate();
3623 bool wxWindowGTK::DoIsExposed( int x
, int y
) const
3625 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
3629 bool wxWindowGTK::DoIsExposed( int x
, int y
, int w
, int h
) const
3631 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3632 return m_updateRegion
.Contains(x
-w
, y
, w
, h
) != wxOutRegion
;
3634 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
3637 void wxWindowGTK::GtkSendPaintEvents()
3641 m_updateRegion
.Clear();
3645 // Clip to paint region in wxClientDC
3646 m_clipPaintRegion
= true;
3648 m_nativeUpdateRegion
= m_updateRegion
;
3650 if (GetLayoutDirection() == wxLayout_RightToLeft
)
3652 // Transform m_updateRegion under RTL
3653 m_updateRegion
.Clear();
3656 gdk_drawable_get_size(m_wxwindow
->window
, &width
, NULL
);
3658 wxRegionIterator
upd( m_nativeUpdateRegion
);
3662 rect
.x
= upd
.GetX();
3663 rect
.y
= upd
.GetY();
3664 rect
.width
= upd
.GetWidth();
3665 rect
.height
= upd
.GetHeight();
3667 rect
.x
= width
- rect
.x
- rect
.width
;
3668 m_updateRegion
.Union( rect
);
3674 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3676 // find ancestor from which to steal background
3677 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3679 parent
= (wxWindow
*)this;
3681 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3683 wxRegionIterator
upd( m_nativeUpdateRegion
);
3687 rect
.x
= upd
.GetX();
3688 rect
.y
= upd
.GetY();
3689 rect
.width
= upd
.GetWidth();
3690 rect
.height
= upd
.GetHeight();
3692 gtk_paint_flat_box( parent
->m_widget
->style
,
3694 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3707 wxWindowDC
dc( (wxWindow
*)this );
3708 dc
.SetClippingRegion( m_updateRegion
);
3710 // Work around gtk-qt <= 0.60 bug whereby the window colour
3712 if (GetBackgroundStyle() == wxBG_STYLE_COLOUR
&& GetBackgroundColour().Ok() && wxSystemOptions::GetOptionInt(wxT("gtk.window.force-background-colour")) == 1)
3714 dc
.SetBackground(wxBrush(GetBackgroundColour()));
3718 wxEraseEvent
erase_event( GetId(), &dc
);
3719 erase_event
.SetEventObject( this );
3721 GetEventHandler()->ProcessEvent(erase_event
);
3724 wxNcPaintEvent
nc_paint_event( GetId() );
3725 nc_paint_event
.SetEventObject( this );
3726 GetEventHandler()->ProcessEvent( nc_paint_event
);
3728 wxPaintEvent
paint_event( GetId() );
3729 paint_event
.SetEventObject( this );
3730 GetEventHandler()->ProcessEvent( paint_event
);
3732 m_clipPaintRegion
= false;
3734 m_updateRegion
.Clear();
3735 m_nativeUpdateRegion
.Clear();
3738 void wxWindowGTK::SetDoubleBuffered( bool on
)
3740 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3743 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3746 bool wxWindowGTK::IsDoubleBuffered() const
3748 return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow
);
3751 void wxWindowGTK::ClearBackground()
3753 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3757 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3759 wxWindowBase::DoSetToolTip(tip
);
3762 m_tooltip
->Apply( (wxWindow
*)this );
3765 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const gchar
*tip
)
3767 gtk_tooltips_set_tip(tips
, GetConnectWidget(), tip
, NULL
);
3769 #endif // wxUSE_TOOLTIPS
3771 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3773 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3775 if (!wxWindowBase::SetBackgroundColour(colour
))
3780 // We need the pixel value e.g. for background clearing.
3781 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3784 // apply style change (forceStyle=true so that new style is applied
3785 // even if the bg colour changed from valid to wxNullColour)
3786 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3787 ApplyWidgetStyle(true);
3792 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3794 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3796 if (!wxWindowBase::SetForegroundColour(colour
))
3803 // We need the pixel value e.g. for background clearing.
3804 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3807 // apply style change (forceStyle=true so that new style is applied
3808 // even if the bg colour changed from valid to wxNullColour):
3809 ApplyWidgetStyle(true);
3814 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3816 return gtk_widget_get_pango_context( m_widget
);
3819 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3821 // do we need to apply any changes at all?
3824 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3829 GtkRcStyle
*style
= gtk_rc_style_new();
3834 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3837 int flagsNormal
= 0,
3840 flagsInsensitive
= 0;
3842 if ( m_foregroundColour
.Ok() )
3844 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3846 style
->fg
[GTK_STATE_NORMAL
] =
3847 style
->text
[GTK_STATE_NORMAL
] = *fg
;
3848 flagsNormal
|= GTK_RC_FG
| GTK_RC_TEXT
;
3850 style
->fg
[GTK_STATE_PRELIGHT
] =
3851 style
->text
[GTK_STATE_PRELIGHT
] = *fg
;
3852 flagsPrelight
|= GTK_RC_FG
| GTK_RC_TEXT
;
3854 style
->fg
[GTK_STATE_ACTIVE
] =
3855 style
->text
[GTK_STATE_ACTIVE
] = *fg
;
3856 flagsActive
|= GTK_RC_FG
| GTK_RC_TEXT
;
3859 if ( m_backgroundColour
.Ok() )
3861 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3863 style
->bg
[GTK_STATE_NORMAL
] =
3864 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3865 flagsNormal
|= GTK_RC_BG
| GTK_RC_BASE
;
3867 style
->bg
[GTK_STATE_PRELIGHT
] =
3868 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3869 flagsPrelight
|= GTK_RC_BG
| GTK_RC_BASE
;
3871 style
->bg
[GTK_STATE_ACTIVE
] =
3872 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3873 flagsActive
|= GTK_RC_BG
| GTK_RC_BASE
;
3875 style
->bg
[GTK_STATE_INSENSITIVE
] =
3876 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3877 flagsInsensitive
|= GTK_RC_BG
| GTK_RC_BASE
;
3880 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)flagsNormal
;
3881 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)flagsPrelight
;
3882 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)flagsActive
;
3883 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)flagsInsensitive
;
3888 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3890 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3893 DoApplyWidgetStyle(style
);
3894 gtk_rc_style_unref(style
);
3897 // Style change may affect GTK+'s size calculation:
3898 InvalidateBestSize();
3901 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3903 wxSuspendStyleEvents
s(static_cast<wxWindow
*>(this));
3906 gtk_widget_modify_style(m_wxwindow
, style
);
3908 gtk_widget_modify_style(m_widget
, style
);
3911 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3913 wxWindowBase::SetBackgroundStyle(style
);
3915 if (style
== wxBG_STYLE_CUSTOM
)
3920 window
= m_wxwindow
->window
;
3924 GtkWidget
* const w
= GetConnectWidget();
3925 window
= w
? w
->window
: NULL
;
3930 // Make sure GDK/X11 doesn't refresh the window
3932 gdk_window_set_back_pixmap( window
, None
, False
);
3934 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3937 m_needsStyleChange
= false;
3939 else // window not realized yet
3941 // Do in OnIdle, because the window is not yet available
3942 m_needsStyleChange
= true;
3945 // Don't apply widget style, or we get a grey background
3949 // apply style change (forceStyle=true so that new style is applied
3950 // even if the bg colour changed from valid to wxNullColour):
3951 ApplyWidgetStyle(true);
3956 #if wxUSE_DRAG_AND_DROP
3958 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3960 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3962 GtkWidget
*dnd_widget
= GetConnectWidget();
3964 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3966 if (m_dropTarget
) delete m_dropTarget
;
3967 m_dropTarget
= dropTarget
;
3969 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3972 #endif // wxUSE_DRAG_AND_DROP
3974 GtkWidget
* wxWindowGTK::GetConnectWidget()
3976 GtkWidget
*connect_widget
= m_widget
;
3977 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3979 return connect_widget
;
3982 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow
*window
) const
3984 wxArrayGdkWindows windowsThis
;
3985 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3987 return winThis
? window
== winThis
3988 : windowsThis
.Index(window
) != wxNOT_FOUND
;
3991 GdkWindow
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
3993 return m_wxwindow
? m_wxwindow
->window
: m_widget
->window
;
3996 bool wxWindowGTK::SetFont( const wxFont
&font
)
3998 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4000 if (!wxWindowBase::SetFont(font
))
4003 // apply style change (forceStyle=true so that new style is applied
4004 // even if the font changed from valid to wxNullFont):
4005 ApplyWidgetStyle(true);
4010 void wxWindowGTK::DoCaptureMouse()
4012 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4014 GdkWindow
*window
= (GdkWindow
*) NULL
;
4016 window
= m_wxwindow
->window
;
4018 window
= GetConnectWidget()->window
;
4020 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4022 const wxCursor
* cursor
= &m_cursor
;
4024 cursor
= wxSTANDARD_CURSOR
;
4026 gdk_pointer_grab( window
, FALSE
,
4028 (GDK_BUTTON_PRESS_MASK
|
4029 GDK_BUTTON_RELEASE_MASK
|
4030 GDK_POINTER_MOTION_HINT_MASK
|
4031 GDK_POINTER_MOTION_MASK
),
4033 cursor
->GetCursor(),
4034 (guint32
)GDK_CURRENT_TIME
);
4035 g_captureWindow
= this;
4036 g_captureWindowHasMouse
= true;
4039 void wxWindowGTK::DoReleaseMouse()
4041 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4043 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4045 g_captureWindow
= (wxWindowGTK
*) NULL
;
4047 GdkWindow
*window
= (GdkWindow
*) NULL
;
4049 window
= m_wxwindow
->window
;
4051 window
= GetConnectWidget()->window
;
4056 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4059 void wxWindowGTK::GTKReleaseMouseAndNotify()
4062 wxMouseCaptureLostEvent
evt(GetId());
4063 evt
.SetEventObject( this );
4064 GetEventHandler()->ProcessEvent( evt
);
4068 wxWindow
*wxWindowBase::GetCapture()
4070 return (wxWindow
*)g_captureWindow
;
4073 bool wxWindowGTK::IsRetained() const
4078 void wxWindowGTK::SetScrollbar(int orient
,
4082 bool WXUNUSED(update
))
4084 const int dir
= ScrollDirFromOrient(orient
);
4085 GtkRange
* const sb
= m_scrollBar
[dir
];
4086 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4090 m_hasScrolling
= true;
4094 // GtkRange requires upper > lower
4099 GtkAdjustment
* const adj
= sb
->adjustment
;
4100 adj
->step_increment
= 1;
4101 adj
->page_increment
=
4102 adj
->page_size
= thumbVisible
;
4105 g_signal_handlers_block_by_func(
4106 sb
, (void*)gtk_scrollbar_value_changed
, this);
4108 gtk_range_set_range(sb
, 0, range
);
4109 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4111 g_signal_handlers_unblock_by_func(
4112 sb
, (void*)gtk_scrollbar_value_changed
, this);
4115 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4117 const int dir
= ScrollDirFromOrient(orient
);
4118 GtkRange
* const sb
= m_scrollBar
[dir
];
4119 wxCHECK_RET( sb
, _T("this window is not scrollable") );
4121 // This check is more than an optimization. Without it, the slider
4122 // will not move smoothly while tracking when using wxScrollHelper.
4123 if (GetScrollPos(orient
) != pos
)
4125 g_signal_handlers_block_by_func(
4126 sb
, (void*)gtk_scrollbar_value_changed
, this);
4128 gtk_range_set_value(sb
, pos
);
4129 m_scrollPos
[dir
] = sb
->adjustment
->value
;
4131 g_signal_handlers_unblock_by_func(
4132 sb
, (void*)gtk_scrollbar_value_changed
, this);
4136 int wxWindowGTK::GetScrollThumb(int orient
) const
4138 GtkRange
* const sb
= m_scrollBar
[ScrollDirFromOrient(orient
)];
4139 wxCHECK_MSG( sb
, 0, _T("this window is not scrollable") );
4141 return int(sb
->adjustment
->page_size
);
4144 int wxWindowGTK::GetScrollPos( 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
->value
+ 0.5);
4152 int wxWindowGTK::GetScrollRange( 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
->upper
);
4160 // Determine if increment is the same as +/-x, allowing for some small
4161 // difference due to possible inexactness in floating point arithmetic
4162 static inline bool IsScrollIncrement(double increment
, double x
)
4164 wxASSERT(increment
> 0);
4165 const double tolerance
= 1.0 / 1024;
4166 return fabs(increment
- fabs(x
)) < tolerance
;
4169 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4173 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4175 const int barIndex
= range
== m_scrollBar
[1];
4176 GtkAdjustment
* adj
= range
->adjustment
;
4178 const int value
= int(adj
->value
+ 0.5);
4180 // save previous position
4181 const double oldPos
= m_scrollPos
[barIndex
];
4182 // update current position
4183 m_scrollPos
[barIndex
] = adj
->value
;
4184 // If event should be ignored, or integral position has not changed
4185 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4190 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4193 // Difference from last change event
4194 const double diff
= adj
->value
- oldPos
;
4195 const bool isDown
= diff
> 0;
4197 if (IsScrollIncrement(adj
->step_increment
, diff
))
4199 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4201 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4203 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4205 else if (m_mouseButtonDown
)
4207 // Assume track event
4208 m_isScrolling
= true;
4214 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4216 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4218 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4220 // No scrolling requested.
4221 if ((dx
== 0) && (dy
== 0)) return;
4223 m_clipPaintRegion
= true;
4225 WX_PIZZA(m_wxwindow
)->scroll(dx
, dy
);
4227 m_clipPaintRegion
= false;
4230 bool restoreCaret
= (GetCaret() != NULL
&& GetCaret()->IsVisible());
4233 wxRect
caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4235 caretRect
.width
+= dx
;
4238 caretRect
.x
+= dx
; caretRect
.width
-= dx
;
4241 caretRect
.height
+= dy
;
4244 caretRect
.y
+= dy
; caretRect
.height
-= dy
;
4247 RefreshRect(caretRect
);
4249 #endif // wxUSE_CARET
4252 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4254 //RN: Note that static controls usually have no border on gtk, so maybe
4255 //it makes sense to treat that as simply no border at the wx level
4257 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4259 GtkShadowType gtkstyle
;
4261 if(wxstyle
& wxBORDER_RAISED
)
4262 gtkstyle
= GTK_SHADOW_OUT
;
4263 else if (wxstyle
& wxBORDER_SUNKEN
)
4264 gtkstyle
= GTK_SHADOW_IN
;
4267 else if (wxstyle
& wxBORDER_DOUBLE
)
4268 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4271 gtkstyle
= GTK_SHADOW_IN
;
4273 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4278 void wxWindowGTK::SetWindowStyleFlag( long style
)
4280 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4281 wxWindowBase::SetWindowStyleFlag(style
);
4284 // Find the wxWindow at the current mouse position, also returning the mouse
4286 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4288 pt
= wxGetMousePosition();
4289 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4293 // Get the current mouse position.
4294 wxPoint
wxGetMousePosition()
4296 /* This crashes when used within wxHelpContext,
4297 so we have to use the X-specific implementation below.
4299 GdkModifierType *mask;
4300 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4302 return wxPoint(x, y);
4306 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4308 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4309 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4310 Window rootReturn
, childReturn
;
4311 int rootX
, rootY
, winX
, winY
;
4312 unsigned int maskReturn
;
4314 XQueryPointer (display
,
4318 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4319 return wxPoint(rootX
, rootY
);
4323 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4324 void wxAddGrab(wxWindow
* window
)
4326 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4329 void wxRemoveGrab(wxWindow
* window
)
4331 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4334 GdkWindow
* wxWindowGTK::GTKGetDrawingWindow() const
4336 GdkWindow
* window
= NULL
;
4338 window
= m_wxwindow
->window
;