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"
25 #include "wx/dcclient.h"
27 #include "wx/dialog.h"
28 #include "wx/settings.h"
29 #include "wx/msgdlg.h"
30 #include "wx/textctrl.h"
31 #include "wx/toolbar.h"
32 #include "wx/combobox.h"
33 #include "wx/layout.h"
34 #include "wx/statusbr.h"
38 #include "wx/module.h"
40 #if wxUSE_DRAG_AND_DROP
45 #include "wx/tooltip.h"
52 #include "wx/fontutil.h"
55 #include "wx/thread.h"
60 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
61 #include <gtk/gtkversion.h>
62 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
63 #undef GTK_DISABLE_DEPRECATED
66 #include "wx/gtk/private.h"
67 #include <gdk/gdkprivate.h>
68 #include <gdk/gdkkeysyms.h>
72 #include <gtk/gtkprivate.h>
74 #include "wx/gtk/win_gtk.h"
76 #include <pango/pangox.h>
82 extern GtkContainerClass
*pizza_parent_class
;
84 //-----------------------------------------------------------------------------
85 // documentation on internals
86 //-----------------------------------------------------------------------------
89 I have been asked several times about writing some documentation about
90 the GTK port of wxWidgets, especially its internal structures. Obviously,
91 you cannot understand wxGTK without knowing a little about the GTK, but
92 some more information about what the wxWindow, which is the base class
93 for all other window classes, does seems required as well.
97 What does wxWindow do? It contains the common interface for the following
98 jobs of its descendants:
100 1) Define the rudimentary behaviour common to all window classes, such as
101 resizing, intercepting user input (so as to make it possible to use these
102 events for special purposes in a derived class), window names etc.
104 2) Provide the possibility to contain and manage children, if the derived
105 class is allowed to contain children, which holds true for those window
106 classes which do not display a native GTK widget. To name them, these
107 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
108 work classes are a special case and are handled a bit differently from
109 the rest. The same holds true for the wxNotebook class.
111 3) Provide the possibility to draw into a client area of a window. This,
112 too, only holds true for classes that do not display a native GTK widget
115 4) Provide the entire mechanism for scrolling widgets. This actual inter-
116 face for this is usually in wxScrolledWindow, but the GTK implementation
119 5) A multitude of helper or extra methods for special purposes, such as
120 Drag'n'Drop, managing validators etc.
122 6) Display a border (sunken, raised, simple or none).
124 Normally one might expect, that one wxWidgets window would always correspond
125 to one GTK widget. Under GTK, there is no such all-round widget that has all
126 the functionality. Moreover, the GTK defines a client area as a different
127 widget from the actual widget you are handling. Last but not least some
128 special classes (e.g. wxFrame) handle different categories of widgets and
129 still have the possibility to draw something in the client area.
130 It was therefore required to write a special purpose GTK widget, that would
131 represent a client area in the sense of wxWidgets capable to do the jobs
132 2), 3) and 4). I have written this class and it resides in win_gtk.c of
135 All windows must have a widget, with which they interact with other under-
136 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
137 the wxWindow class has a member variable called m_widget which holds a
138 pointer to this widget. When the window class represents a GTK native widget,
139 this is (in most cases) the only GTK widget the class manages. E.g. the
140 wxStaticText class handles only a GtkLabel widget a pointer to which you
141 can find in m_widget (defined in wxWindow)
143 When the class has a client area for drawing into and for containing children
144 it has to handle the client area widget (of the type GtkPizza, defined in
145 win_gtk.c), but there could be any number of widgets, handled by a class
146 The common rule for all windows is only, that the widget that interacts with
147 the rest of GTK must be referenced in m_widget and all other widgets must be
148 children of this widget on the GTK level. The top-most widget, which also
149 represents the client area, must be in the m_wxwindow field and must be of
152 As I said, the window classes that display a GTK native widget only have
153 one widget, so in the case of e.g. the wxButton class m_widget holds a
154 pointer to a GtkButton widget. But windows with client areas (for drawing
155 and children) have a m_widget field that is a pointer to a GtkScrolled-
156 Window and a m_wxwindow field that is pointer to a GtkPizza and this
157 one is (in the GTK sense) a child of the GtkScrolledWindow.
159 If the m_wxwindow field is set, then all input to this widget is inter-
160 cepted and sent to the wxWidgets class. If not, all input to the widget
161 that gets pointed to by m_widget gets intercepted and sent to the class.
165 The design of scrolling in wxWidgets is markedly different from that offered
166 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
167 clicking on a scrollbar belonging to scrolled window will inevitably move
168 the window. In wxWidgets, the scrollbar will only emit an event, send this
169 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
170 which actually moves the window and its sub-windows. Note that GtkPizza
171 memorizes how much it has been scrolled but that wxWidgets forgets this
172 so that the two coordinates systems have to be kept in synch. This is done
173 in various places using the pizza->xoffset and pizza->yoffset values.
177 Singularly the most broken code in GTK is the code that is supposed to
178 inform subwindows (child windows) about new positions. Very often, duplicate
179 events are sent without changes in size or position, equally often no
180 events are sent at all (All this is due to a bug in the GtkContainer code
181 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
182 GTK's own system and it simply waits for size events for toplevel windows
183 and then iterates down the respective size events to all window. This has
184 the disadvantage that windows might get size events before the GTK widget
185 actually has the reported size. This doesn't normally pose any problem, but
186 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
187 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
188 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
189 window that is used for OpenGL output really has that size (as reported by
194 If someone at some point of time feels the immense desire to have a look at,
195 change or attempt to optimise the Refresh() logic, this person will need an
196 intimate understanding of what "draw" and "expose" events are and what
197 they are used for, in particular when used in connection with GTK's
198 own windowless widgets. Beware.
202 Cursors, too, have been a constant source of pleasure. The main difficulty
203 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
204 for the parent. To prevent this from doing too much harm, I use idle time
205 to set the cursor over and over again, starting from the toplevel windows
206 and ending with the youngest generation (speaking of parent and child windows).
207 Also don't forget that cursors (like much else) are connected to GdkWindows,
208 not GtkWidgets and that the "window" field of a GtkWidget might very well
209 point to the GdkWindow of the parent widget (-> "window-less widget") and
210 that the two obviously have very different meanings.
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 extern bool g_blockEventsOnDrag
;
219 extern bool g_blockEventsOnScroll
;
220 extern wxCursor g_globalCursor
;
222 static GdkGC
*g_eraseGC
= NULL
;
224 // mouse capture state: the window which has it and if the mouse is currently
226 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
227 static bool g_captureWindowHasMouse
= false;
229 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
231 // the last window which had the focus - this is normally never NULL (except
232 // if we never had focus at all) as even when g_focusWindow is NULL it still
233 // keeps its previous value
234 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
236 // If a window get the focus set but has not been realized
237 // yet, defer setting the focus to idle time.
238 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
240 extern bool g_mainThreadLocked
;
242 //-----------------------------------------------------------------------------
244 //-----------------------------------------------------------------------------
249 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
251 # define DEBUG_MAIN_THREAD
254 #define DEBUG_MAIN_THREAD
257 // the trace mask used for the focus debugging messages
258 #define TRACE_FOCUS _T("focus")
260 //-----------------------------------------------------------------------------
261 // missing gdk functions
262 //-----------------------------------------------------------------------------
265 gdk_window_warp_pointer (GdkWindow
*window
,
270 window
= gdk_get_default_root_window();
272 if (!GDK_WINDOW_DESTROYED(window
))
274 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
275 None
, /* not source window -> move from anywhere */
276 GDK_WINDOW_XID(window
), /* dest window */
277 0, 0, 0, 0, /* not source window -> move from anywhere */
282 //-----------------------------------------------------------------------------
283 // local code (see below)
284 //-----------------------------------------------------------------------------
286 // returns the child of win which currently has focus or NULL if not found
288 // Note: can't be static, needed by textctrl.cpp.
289 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
291 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
293 return (wxWindow
*)NULL
;
295 if ( winFocus
== win
)
296 return (wxWindow
*)win
;
298 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
300 node
= node
->GetNext() )
302 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
307 return (wxWindow
*)NULL
;
310 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
)
312 GtkScrolledWindow
* scroll_window
= GTK_SCROLLED_WINDOW(widget
);
313 GtkScrolledWindowClass
* scroll_class
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
));
314 GtkRequisition scroll_req
;
317 if (scroll_window
->vscrollbar_visible
)
319 scroll_req
.width
= 2;
320 scroll_req
.height
= 2;
321 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
322 (scroll_window
->vscrollbar
, &scroll_req
);
323 w
= scroll_req
.width
+
324 scroll_class
->scrollbar_spacing
;
328 if (scroll_window
->hscrollbar_visible
)
330 scroll_req
.width
= 2;
331 scroll_req
.height
= 2;
332 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
333 (scroll_window
->hscrollbar
, &scroll_req
);
334 h
= scroll_req
.height
+
335 scroll_class
->scrollbar_spacing
;
339 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
341 // wxUniversal widgets draw the borders and scrollbars themselves
342 #ifndef __WXUNIVERSAL__
349 if (win
->m_hasScrolling
)
351 GetScrollbarWidth(widget
, dw
, dh
);
356 if (GTK_WIDGET_NO_WINDOW (widget
))
358 dx
+= widget
->allocation
.x
;
359 dy
+= widget
->allocation
.y
;
362 if (win
->HasFlag(wxRAISED_BORDER
))
364 gtk_paint_shadow (widget
->style
,
368 NULL
, NULL
, NULL
, // FIXME: No clipping?
370 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
374 if (win
->HasFlag(wxSUNKEN_BORDER
))
376 gtk_paint_shadow (widget
->style
,
380 NULL
, NULL
, NULL
, // FIXME: No clipping?
382 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
386 if (win
->HasFlag(wxSIMPLE_BORDER
))
389 gc
= gdk_gc_new( widget
->window
);
390 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
391 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
393 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
397 #endif // __WXUNIVERSAL__
400 //-----------------------------------------------------------------------------
401 // "expose_event" of m_widget
402 //-----------------------------------------------------------------------------
406 gtk_window_own_expose_callback( GtkWidget
*widget
,
407 GdkEventExpose
*gdk_event
,
410 if (gdk_event
->count
> 0) return FALSE
;
412 draw_frame( widget
, win
);
414 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
420 //-----------------------------------------------------------------------------
421 // "size_request" of m_widget
422 //-----------------------------------------------------------------------------
424 // make it extern because wxStaticText needs to disconnect this one
426 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
427 GtkRequisition
*requisition
,
431 win
->GetSize( &w
, &h
);
437 requisition
->height
= h
;
438 requisition
->width
= w
;
444 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
445 GtkRequisition
*requisition
,
448 // This callback is actually hooked into the text entry
449 // of the combo box, not the GtkHBox.
452 win
->GetSize( &w
, &h
);
458 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
460 GtkRequisition entry_req
;
462 entry_req
.height
= 2;
463 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
464 (gcombo
->button
, &entry_req
);
466 requisition
->width
= w
- entry_req
.width
;
467 requisition
->height
= entry_req
.height
;
471 //-----------------------------------------------------------------------------
472 // "expose_event" of m_wxwindow
473 //-----------------------------------------------------------------------------
477 gtk_window_expose_callback( GtkWidget
*widget
,
478 GdkEventExpose
*gdk_event
,
483 // don't need to install idle handler, its done from "event" signal
485 // This callback gets called in drawing-idle time under
486 // GTK 2.0, so we don't need to defer anything to idle
489 GtkPizza
*pizza
= GTK_PIZZA( widget
);
490 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
495 wxPrintf( wxT("OnExpose from ") );
496 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
497 wxPrintf( win
->GetClassInfo()->GetClassName() );
498 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
499 (int)gdk_event
->area
.y
,
500 (int)gdk_event
->area
.width
,
501 (int)gdk_event
->area
.height
);
506 win
->m_wxwindow
->style
,
510 (GdkRectangle
*) NULL
,
512 (char *)"button", // const_cast
517 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
519 win
->GtkSendPaintEvents();
522 // Let parent window draw window-less widgets
523 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
529 //-----------------------------------------------------------------------------
530 // "key_press_event" from any window
531 //-----------------------------------------------------------------------------
533 // These are used when transforming Ctrl-alpha to ascii values 1-26
534 inline bool wxIsLowerChar(int code
)
536 return (code
>= 'a' && code
<= 'z' );
539 inline bool wxIsUpperChar(int code
)
541 return (code
>= 'A' && code
<= 'Z' );
545 // set WXTRACE to this to see the key event codes on the console
546 #define TRACE_KEYS _T("keyevent")
548 // translates an X key symbol to WXK_XXX value
550 // if isChar is true it means that the value returned will be used for EVT_CHAR
551 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
552 // for example, while if it is false it means that the value is going to be
553 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
555 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
561 // Shift, Control and Alt don't generate the CHAR events at all
564 key_code
= isChar
? 0 : WXK_SHIFT
;
568 key_code
= isChar
? 0 : WXK_CONTROL
;
576 key_code
= isChar
? 0 : WXK_ALT
;
579 // neither do the toggle modifies
580 case GDK_Scroll_Lock
:
581 key_code
= isChar
? 0 : WXK_SCROLL
;
585 key_code
= isChar
? 0 : WXK_CAPITAL
;
589 key_code
= isChar
? 0 : WXK_NUMLOCK
;
593 // various other special keys
606 case GDK_ISO_Left_Tab
:
613 key_code
= WXK_RETURN
;
617 key_code
= WXK_CLEAR
;
621 key_code
= WXK_PAUSE
;
625 key_code
= WXK_SELECT
;
629 key_code
= WXK_PRINT
;
633 key_code
= WXK_EXECUTE
;
637 key_code
= WXK_ESCAPE
;
640 // cursor and other extended keyboard keys
642 key_code
= WXK_DELETE
;
658 key_code
= WXK_RIGHT
;
665 case GDK_Prior
: // == GDK_Page_Up
666 key_code
= WXK_PAGEUP
;
669 case GDK_Next
: // == GDK_Page_Down
670 key_code
= WXK_PAGEDOWN
;
682 key_code
= WXK_INSERT
;
697 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
701 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
705 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
709 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
713 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
717 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
721 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
725 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
729 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
733 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
737 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
741 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
745 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
748 case GDK_KP_Prior
: // == GDK_KP_Page_Up
749 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
752 case GDK_KP_Next
: // == GDK_KP_Page_Down
753 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
757 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
761 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
765 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
769 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
773 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
776 case GDK_KP_Multiply
:
777 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
781 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
784 case GDK_KP_Separator
:
785 // FIXME: what is this?
786 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
789 case GDK_KP_Subtract
:
790 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
794 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
798 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
815 key_code
= WXK_F1
+ keysym
- GDK_F1
;
825 static inline bool wxIsAsciiKeysym(KeySym ks
)
830 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
832 GdkEventKey
*gdk_event
)
836 GdkModifierType state
;
837 if (gdk_event
->window
)
838 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
840 event
.SetTimestamp( gdk_event
->time
);
841 event
.SetId(win
->GetId());
842 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
843 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
844 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
845 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
846 event
.m_scanCode
= gdk_event
->keyval
;
847 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
848 event
.m_rawFlags
= 0;
850 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
852 wxGetMousePosition( &x
, &y
);
853 win
->ScreenToClient( &x
, &y
);
856 event
.SetEventObject( win
);
861 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
863 GdkEventKey
*gdk_event
)
865 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
866 // but only event->keyval which is quite useless to us, so remember
867 // the last character from GDK_KEY_PRESS and reuse it as last resort
869 // NB: should be MT-safe as we're always called from the main thread only
874 } s_lastKeyPress
= { 0, 0 };
876 KeySym keysym
= gdk_event
->keyval
;
878 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
879 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
883 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
887 // do we have the translation or is it a plain ASCII character?
888 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
890 // we should use keysym if it is ASCII as X does some translations
891 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
892 // which we don't want here (but which we do use for OnChar())
893 if ( !wxIsAsciiKeysym(keysym
) )
895 keysym
= (KeySym
)gdk_event
->string
[0];
898 // we want to always get the same key code when the same key is
899 // pressed regardless of the state of the modifiers, i.e. on a
900 // standard US keyboard pressing '5' or '%' ('5' key with
901 // Shift) should result in the same key code in OnKeyDown():
902 // '5' (although OnChar() will get either '5' or '%').
904 // to do it we first translate keysym to keycode (== scan code)
905 // and then back but always using the lower register
906 Display
*dpy
= (Display
*)wxGetDisplay();
907 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
909 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
911 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
913 // use the normalized, i.e. lower register, keysym if we've
915 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
917 // as explained above, we want to have lower register key codes
918 // normally but for the letter keys we want to have the upper ones
920 // NB: don't use XConvertCase() here, we want to do it for letters
922 key_code
= toupper(key_code
);
924 else // non ASCII key, what to do?
926 // by default, ignore it
929 // but if we have cached information from the last KEY_PRESS
930 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
933 if ( keysym
== s_lastKeyPress
.keysym
)
935 key_code
= s_lastKeyPress
.keycode
;
940 if ( gdk_event
->type
== GDK_KEY_PRESS
)
942 // remember it to be reused for KEY_UP event later
943 s_lastKeyPress
.keysym
= keysym
;
944 s_lastKeyPress
.keycode
= key_code
;
948 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
950 // sending unknown key events doesn't really make sense
954 // now fill all the other fields
955 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
957 event
.m_keyCode
= key_code
;
959 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
961 event
.m_uniChar
= key_code
;
971 GtkIMContext
*context
;
972 GdkEventKey
*lastKeyEvent
;
976 context
= gtk_im_multicontext_new();
981 g_object_unref (context
);
987 gtk_window_key_press_callback( GtkWidget
*widget
,
988 GdkEventKey
*gdk_event
,
993 // don't need to install idle handler, its done from "event" signal
997 if (g_blockEventsOnDrag
)
1001 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1003 bool return_after_IM
= false;
1005 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1007 // Emit KEY_DOWN event
1008 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1012 // Return after IM processing as we cannot do
1013 // anything with it anyhow.
1014 return_after_IM
= true;
1017 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1018 // When we get a key_press event here, it could be originate
1019 // from the current widget or its child widgets. However, only the widget
1020 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1021 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1022 // originated from its child widgets and shouldn't be passed to IM context.
1023 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1024 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1025 // widgets has both IM context and input focus, the event should be filtered
1026 // by gtk_im_context_filter_keypress().
1027 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1028 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1030 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1031 // docs, if IM filter returns true, no further processing should be done.
1032 // we should send the key_down event anyway.
1033 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1034 win
->m_imData
->lastKeyEvent
= NULL
;
1035 if (intercepted_by_IM
)
1037 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1042 if (return_after_IM
)
1048 wxWindowGTK
*ancestor
= win
;
1051 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1054 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1055 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1058 if (ancestor
->IsTopLevel())
1060 ancestor
= ancestor
->GetParent();
1063 #endif // wxUSE_ACCEL
1065 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1066 // will only be sent if it is not in an accelerator table.
1070 KeySym keysym
= gdk_event
->keyval
;
1071 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1072 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1075 if ( wxIsAsciiKeysym(keysym
) )
1078 key_code
= (unsigned char)keysym
;
1080 // gdk_event->string is actually deprecated
1081 else if ( gdk_event
->length
== 1 )
1083 key_code
= (unsigned char)gdk_event
->string
[0];
1089 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1091 event
.m_keyCode
= key_code
;
1093 // To conform to the docs we need to translate Ctrl-alpha
1094 // characters to values in the range 1-26.
1095 if ( event
.ControlDown() &&
1096 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
1098 if ( wxIsLowerChar(key_code
) )
1099 event
.m_keyCode
= key_code
- 'a' + 1;
1100 if ( wxIsUpperChar(key_code
) )
1101 event
.m_keyCode
= key_code
- 'A' + 1;
1103 event
.m_uniChar
= event
.m_keyCode
;
1107 // Implement OnCharHook by checking ancestor top level windows
1108 wxWindow
*parent
= win
;
1109 while (parent
&& !parent
->IsTopLevel())
1110 parent
= parent
->GetParent();
1113 event
.SetEventType( wxEVT_CHAR_HOOK
);
1114 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1119 event
.SetEventType(wxEVT_CHAR
);
1120 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1129 // win is a control: tab can be propagated up
1131 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1132 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1133 // have this style, yet choose not to process this particular TAB in which
1134 // case TAB must still work as a navigational character
1135 // JS: enabling again to make consistent with other platforms
1136 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1137 // navigation behaviour)
1139 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1141 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1143 wxNavigationKeyEvent new_event
;
1144 new_event
.SetEventObject( win
->GetParent() );
1145 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1146 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1147 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1148 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1149 new_event
.SetCurrentFocus( win
);
1150 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1155 g_signal_stop_emission_by_name (widget
, "key_press_event");
1165 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1169 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1171 // take modifiers, cursor position, timestamp etc. from the last
1172 // key_press_event that was fed into Input Method:
1173 if (window
->m_imData
->lastKeyEvent
)
1175 wxFillOtherKeyEventFields(event
,
1176 window
, window
->m_imData
->lastKeyEvent
);
1179 const wxWxCharBuffer
data(wxGTK_CONV_BACK(str
));
1185 // Implement OnCharHook by checking ancestor top level windows
1186 wxWindow
*parent
= window
;
1187 while (parent
&& !parent
->IsTopLevel())
1188 parent
= parent
->GetParent();
1190 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1193 event
.m_uniChar
= *pstr
;
1194 // Backward compatible for ISO-8859-1
1195 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1196 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1198 event
.m_keyCode
= *pstr
;
1199 #endif // wxUSE_UNICODE
1201 // To conform to the docs we need to translate Ctrl-alpha
1202 // characters to values in the range 1-26.
1203 if ( event
.ControlDown() &&
1204 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
1206 if ( wxIsLowerChar(*pstr
) )
1207 event
.m_keyCode
= *pstr
- 'a' + 1;
1208 if ( wxIsUpperChar(*pstr
) )
1209 event
.m_keyCode
= *pstr
- 'A' + 1;
1211 event
.m_keyCode
= *pstr
- 'a' + 1;
1213 event
.m_uniChar
= event
.m_keyCode
;
1219 event
.SetEventType( wxEVT_CHAR_HOOK
);
1220 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1225 event
.SetEventType(wxEVT_CHAR
);
1226 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1233 //-----------------------------------------------------------------------------
1234 // "key_release_event" from any window
1235 //-----------------------------------------------------------------------------
1239 gtk_window_key_release_callback( GtkWidget
*widget
,
1240 GdkEventKey
*gdk_event
,
1245 // don't need to install idle handler, its done from "event" signal
1250 if (g_blockEventsOnDrag
)
1253 wxKeyEvent
event( wxEVT_KEY_UP
);
1254 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1256 // unknown key pressed, ignore (the event would be useless anyhow)
1260 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1263 g_signal_stop_emission_by_name (widget
, "key_release_event");
1268 // ============================================================================
1270 // ============================================================================
1272 // ----------------------------------------------------------------------------
1273 // mouse event processing helpers
1274 // ----------------------------------------------------------------------------
1276 // init wxMouseEvent with the info from GdkEventXXX struct
1277 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1278 wxMouseEvent
& event
,
1281 event
.SetTimestamp( gdk_event
->time
);
1282 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1283 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1284 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1285 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1286 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1287 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1288 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1289 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1291 event
.m_linesPerAction
= 3;
1292 event
.m_wheelDelta
= 120;
1293 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1294 event
.m_wheelRotation
= 120;
1295 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1296 event
.m_wheelRotation
= -120;
1299 wxPoint pt
= win
->GetClientAreaOrigin();
1300 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1301 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1303 event
.SetEventObject( win
);
1304 event
.SetId( win
->GetId() );
1305 event
.SetTimestamp( gdk_event
->time
);
1308 static void AdjustEventButtonState(wxMouseEvent
& event
)
1310 // GDK reports the old state of the button for a button press event, but
1311 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1312 // for a LEFT_DOWN event, not FALSE, so we will invert
1313 // left/right/middleDown for the corresponding click events
1315 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1316 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1317 (event
.GetEventType() == wxEVT_LEFT_UP
))
1319 event
.m_leftDown
= !event
.m_leftDown
;
1323 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1324 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1325 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1327 event
.m_middleDown
= !event
.m_middleDown
;
1331 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1332 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1333 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1335 event
.m_rightDown
= !event
.m_rightDown
;
1340 // find the window to send the mouse event too
1342 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1347 if (win
->m_wxwindow
)
1349 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1350 xx
+= pizza
->xoffset
;
1351 yy
+= pizza
->yoffset
;
1354 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1357 wxWindowGTK
*child
= node
->GetData();
1359 node
= node
->GetNext();
1360 if (!child
->IsShown())
1363 if (child
->IsTransparentForMouse())
1365 // wxStaticBox is transparent in the box itself
1366 int xx1
= child
->m_x
;
1367 int yy1
= child
->m_y
;
1368 int xx2
= child
->m_x
+ child
->m_width
;
1369 int yy2
= child
->m_y
+ child
->m_height
;
1372 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1374 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1376 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1378 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1389 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1390 (child
->m_x
<= xx
) &&
1391 (child
->m_y
<= yy
) &&
1392 (child
->m_x
+child
->m_width
>= xx
) &&
1393 (child
->m_y
+child
->m_height
>= yy
))
1406 // ----------------------------------------------------------------------------
1407 // common event handlers helpers
1408 // ----------------------------------------------------------------------------
1410 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny
*event
) const
1414 // don't need to install idle handler, its done from "event" signal
1418 if (g_blockEventsOnDrag
)
1420 if (g_blockEventsOnScroll
)
1423 if (!GTKIsOwnWindow(event
->window
))
1429 // overloads for all GDK event types we use here: we need to have this as
1430 // GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1431 // derives from it in the sense that the structs have the same layout
1432 #define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
1433 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
1435 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1438 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton
)
1439 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion
)
1440 wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing
)
1442 #undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1444 #define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1445 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1449 // send the wxChildFocusEvent and wxFocusEvent, common code of
1450 // gtk_window_focus_in_callback() and SetFocus()
1451 static bool DoSendFocusEvents(wxWindow
*win
)
1453 // Notify the parent keeping track of focus for the kbd navigation
1454 // purposes that we got it.
1455 wxChildFocusEvent
eventChildFocus(win
);
1456 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1458 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1459 eventFocus
.SetEventObject(win
);
1461 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1464 // all event handlers must have C linkage as they're called from GTK+ C code
1468 //-----------------------------------------------------------------------------
1469 // "button_press_event"
1470 //-----------------------------------------------------------------------------
1473 gtk_window_button_press_callback( GtkWidget
*widget
,
1474 GdkEventButton
*gdk_event
,
1477 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1479 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1481 gtk_widget_grab_focus( win
->m_wxwindow
);
1484 // GDK sends surplus button down events
1485 // before a double click event. We
1486 // need to filter these out.
1487 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1489 GdkEvent
*peek_event
= gdk_event_peek();
1492 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1493 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1495 gdk_event_free( peek_event
);
1500 gdk_event_free( peek_event
);
1505 wxEventType event_type
= wxEVT_NULL
;
1507 // GdkDisplay is a GTK+ 2.2.0 thing
1508 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1509 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1510 !gtk_check_version(2,2,0) &&
1511 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1513 // Reset GDK internal timestamp variables in order to disable GDK
1514 // triple click events. GDK will then next time believe no button has
1515 // been clicked just before, and send a normal button click event.
1516 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1517 display
->button_click_time
[1] = 0;
1518 display
->button_click_time
[0] = 0;
1522 if (gdk_event
->button
== 1)
1524 // note that GDK generates triple click events which are not supported
1525 // by wxWidgets but still have to be passed to the app as otherwise
1526 // clicks would simply go missing
1527 switch (gdk_event
->type
)
1529 // we shouldn't get triple clicks at all for GTK2 because we
1530 // suppress them artificially using the code above but we still
1531 // should map them to something for GTK1 and not just ignore them
1532 // as this would lose clicks
1533 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1534 case GDK_BUTTON_PRESS
:
1535 event_type
= wxEVT_LEFT_DOWN
;
1538 case GDK_2BUTTON_PRESS
:
1539 event_type
= wxEVT_LEFT_DCLICK
;
1543 // just to silence gcc warnings
1547 else if (gdk_event
->button
== 2)
1549 switch (gdk_event
->type
)
1551 case GDK_3BUTTON_PRESS
:
1552 case GDK_BUTTON_PRESS
:
1553 event_type
= wxEVT_MIDDLE_DOWN
;
1556 case GDK_2BUTTON_PRESS
:
1557 event_type
= wxEVT_MIDDLE_DCLICK
;
1564 else if (gdk_event
->button
== 3)
1566 switch (gdk_event
->type
)
1568 case GDK_3BUTTON_PRESS
:
1569 case GDK_BUTTON_PRESS
:
1570 event_type
= wxEVT_RIGHT_DOWN
;
1573 case GDK_2BUTTON_PRESS
:
1574 event_type
= wxEVT_RIGHT_DCLICK
;
1581 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1583 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1585 event_type
= wxEVT_MOUSEWHEEL
;
1589 if ( event_type
== wxEVT_NULL
)
1591 // unknown mouse button or click type
1595 wxMouseEvent
event( event_type
);
1596 InitMouseEvent( win
, event
, gdk_event
);
1598 AdjustEventButtonState(event
);
1600 // wxListBox actually gets mouse events from the item, so we need to give it
1601 // a chance to correct this
1602 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1604 // find the correct window to send the event to: it may be a different one
1605 // from the one which got it at GTK+ level because some controls don't have
1606 // their own X window and thus cannot get any events.
1607 if ( !g_captureWindow
)
1608 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1610 // reset the event object and id in case win changed.
1611 event
.SetEventObject( win
);
1612 event
.SetId( win
->GetId() );
1614 if (win
->GetEventHandler()->ProcessEvent( event
))
1616 g_signal_stop_emission_by_name (widget
, "button_press_event");
1620 if (event_type
== wxEVT_RIGHT_DOWN
)
1622 // generate a "context menu" event: this is similar to right mouse
1623 // click under many GUIs except that it is generated differently
1624 // (right up under MSW, ctrl-click under Mac, right down here) and
1626 // (a) it's a command event and so is propagated to the parent
1627 // (b) under some ports it can be generated from kbd too
1628 // (c) it uses screen coords (because of (a))
1629 wxContextMenuEvent
evtCtx(
1632 win
->ClientToScreen(event
.GetPosition()));
1633 evtCtx
.SetEventObject(win
);
1634 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1640 //-----------------------------------------------------------------------------
1641 // "button_release_event"
1642 //-----------------------------------------------------------------------------
1645 gtk_window_button_release_callback( GtkWidget
*widget
,
1646 GdkEventButton
*gdk_event
,
1649 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1651 wxEventType event_type
= wxEVT_NULL
;
1653 switch (gdk_event
->button
)
1656 event_type
= wxEVT_LEFT_UP
;
1660 event_type
= wxEVT_MIDDLE_UP
;
1664 event_type
= wxEVT_RIGHT_UP
;
1668 // unknown button, don't process
1672 wxMouseEvent
event( event_type
);
1673 InitMouseEvent( win
, event
, gdk_event
);
1675 AdjustEventButtonState(event
);
1677 // same wxListBox hack as above
1678 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1680 if ( !g_captureWindow
)
1681 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1683 // reset the event object and id in case win changed.
1684 event
.SetEventObject( win
);
1685 event
.SetId( win
->GetId() );
1687 if (win
->GetEventHandler()->ProcessEvent( event
))
1689 g_signal_stop_emission_by_name (widget
, "button_release_event");
1696 //-----------------------------------------------------------------------------
1697 // "motion_notify_event"
1698 //-----------------------------------------------------------------------------
1701 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1702 GdkEventMotion
*gdk_event
,
1705 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1707 if (gdk_event
->is_hint
)
1711 GdkModifierType state
;
1712 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1717 wxMouseEvent
event( wxEVT_MOTION
);
1718 InitMouseEvent(win
, event
, gdk_event
);
1720 if ( g_captureWindow
)
1722 // synthesise a mouse enter or leave event if needed
1723 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1724 // This seems to be necessary and actually been added to
1725 // GDK itself in version 2.0.X
1728 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1729 if ( hasMouse
!= g_captureWindowHasMouse
)
1731 // the mouse changed window
1732 g_captureWindowHasMouse
= hasMouse
;
1734 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1735 : wxEVT_LEAVE_WINDOW
);
1736 InitMouseEvent(win
, eventM
, gdk_event
);
1737 eventM
.SetEventObject(win
);
1738 win
->GetEventHandler()->ProcessEvent(eventM
);
1743 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1745 // reset the event object and id in case win changed.
1746 event
.SetEventObject( win
);
1747 event
.SetId( win
->GetId() );
1750 if ( !g_captureWindow
)
1752 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1753 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1755 // Rewrite cursor handling here (away from idle).
1759 if (win
->GetEventHandler()->ProcessEvent( event
))
1761 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1768 //-----------------------------------------------------------------------------
1769 // "scroll_event", (mouse wheel event)
1770 //-----------------------------------------------------------------------------
1773 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1777 // don't need to install idle handler, its done from "event" signal
1779 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1780 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1785 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1786 // Can't use InitMouse macro because scroll events don't have button
1787 event
.SetTimestamp( gdk_event
->time
);
1788 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1789 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1790 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1791 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1792 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1793 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1794 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1795 event
.m_linesPerAction
= 3;
1796 event
.m_wheelDelta
= 120;
1797 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1798 event
.m_wheelRotation
= 120;
1800 event
.m_wheelRotation
= -120;
1802 wxPoint pt
= win
->GetClientAreaOrigin();
1803 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1804 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1806 event
.SetEventObject( win
);
1807 event
.SetId( win
->GetId() );
1808 event
.SetTimestamp( gdk_event
->time
);
1810 return win
->GetEventHandler()->ProcessEvent(event
);
1813 //-----------------------------------------------------------------------------
1815 //-----------------------------------------------------------------------------
1817 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1819 wxContextMenuEvent
event(wxEVT_CONTEXT_MENU
, win
->GetId(), wxPoint(-1, -1));
1820 event
.SetEventObject(win
);
1821 return win
->GetEventHandler()->ProcessEvent(event
);
1824 //-----------------------------------------------------------------------------
1826 //-----------------------------------------------------------------------------
1829 gtk_window_focus_in_callback( GtkWidget
*widget
,
1830 GdkEventFocus
*WXUNUSED(event
),
1835 // don't need to install idle handler, its done from "event" signal
1838 gtk_im_context_focus_in(win
->m_imData
->context
);
1841 g_focusWindow
= win
;
1843 wxLogTrace(TRACE_FOCUS
,
1844 _T("%s: focus in"), win
->GetName().c_str());
1848 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1852 // caret needs to be informed about focus change
1853 wxCaret
*caret
= win
->GetCaret();
1856 caret
->OnSetFocus();
1858 #endif // wxUSE_CARET
1860 gboolean ret
= FALSE
;
1862 // does the window itself think that it has the focus?
1863 if ( !win
->m_hasFocus
)
1865 // not yet, notify it
1866 win
->m_hasFocus
= true;
1868 (void)DoSendFocusEvents(win
);
1873 // Disable default focus handling for custom windows
1874 // since the default GTK+ handler issues a repaint
1875 if (win
->m_wxwindow
)
1881 //-----------------------------------------------------------------------------
1882 // "focus_out_event"
1883 //-----------------------------------------------------------------------------
1886 gtk_window_focus_out_callback( GtkWidget
*widget
,
1887 GdkEventFocus
*gdk_event
,
1892 // don't need to install idle handler, its done from "event" signal
1895 gtk_im_context_focus_out(win
->m_imData
->context
);
1897 wxLogTrace( TRACE_FOCUS
,
1898 _T("%s: focus out"), win
->GetName().c_str() );
1901 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1905 g_focusWindow
= (wxWindowGTK
*)NULL
;
1913 // caret needs to be informed about focus change
1914 wxCaret
*caret
= win
->GetCaret();
1917 caret
->OnKillFocus();
1919 #endif // wxUSE_CARET
1921 gboolean ret
= FALSE
;
1923 // don't send the window a kill focus event if it thinks that it doesn't
1924 // have focus already
1925 if ( win
->m_hasFocus
)
1927 win
->m_hasFocus
= false;
1929 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1930 event
.SetEventObject( win
);
1932 (void)win
->GetEventHandler()->ProcessEvent( event
);
1937 // Disable default focus handling for custom windows
1938 // since the default GTK+ handler issues a repaint
1939 if (win
->m_wxwindow
)
1945 //-----------------------------------------------------------------------------
1946 // "enter_notify_event"
1947 //-----------------------------------------------------------------------------
1950 gtk_window_enter_callback( GtkWidget
*widget
,
1951 GdkEventCrossing
*gdk_event
,
1954 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
1956 // Event was emitted after a grab
1957 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1961 GdkModifierType state
= (GdkModifierType
)0;
1963 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1965 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1966 InitMouseEvent(win
, event
, gdk_event
);
1967 wxPoint pt
= win
->GetClientAreaOrigin();
1968 event
.m_x
= x
+ pt
.x
;
1969 event
.m_y
= y
+ pt
.y
;
1971 if ( !g_captureWindow
)
1973 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1974 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1976 // Rewrite cursor handling here (away from idle).
1980 if (win
->GetEventHandler()->ProcessEvent( event
))
1982 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
1989 //-----------------------------------------------------------------------------
1990 // "leave_notify_event"
1991 //-----------------------------------------------------------------------------
1994 gtk_window_leave_callback( GtkWidget
*widget
,
1995 GdkEventCrossing
*gdk_event
,
1998 wxCOMMON_CALLBACK_PROLOGUE(gdk_event
, win
);
2000 // Event was emitted after an ungrab
2001 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2003 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2004 event
.SetTimestamp( gdk_event
->time
);
2005 event
.SetEventObject( win
);
2009 GdkModifierType state
= (GdkModifierType
)0;
2011 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2013 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2014 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2015 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2016 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2017 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2018 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2019 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2021 wxPoint pt
= win
->GetClientAreaOrigin();
2022 event
.m_x
= x
+ pt
.x
;
2023 event
.m_y
= y
+ pt
.y
;
2025 if (win
->GetEventHandler()->ProcessEvent( event
))
2027 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2034 //-----------------------------------------------------------------------------
2035 // "value_changed" from scrollbar
2036 //-----------------------------------------------------------------------------
2039 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
2041 wxEventType eventType
= win
->GetScrollEventType(range
);
2042 if (eventType
!= wxEVT_NULL
)
2044 // Convert scroll event type to scrollwin event type
2045 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
2047 // find the scrollbar which generated the event
2048 wxWindowGTK::ScrollDir dir
= win
->ScrollDirFromRange(range
);
2050 // generate the corresponding wx event
2051 const int orient
= win
->OrientFromScrollDir(dir
);
2052 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
2053 event
.SetEventObject(win
);
2055 win
->m_blockValueChanged
[dir
] = true;
2056 win
->GetEventHandler()->ProcessEvent(event
);
2057 win
->m_blockValueChanged
[dir
] = false;
2061 //-----------------------------------------------------------------------------
2062 // "button_press_event" from scrollbar
2063 //-----------------------------------------------------------------------------
2066 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
2070 // don't need to install idle handler, its done from "event" signal
2072 g_blockEventsOnScroll
= true;
2073 win
->m_mouseButtonDown
= true;
2078 //-----------------------------------------------------------------------------
2079 // "event_after" from scrollbar
2080 //-----------------------------------------------------------------------------
2083 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
2085 if (event
->type
== GDK_BUTTON_RELEASE
)
2087 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
2089 const int orient
= win
->OrientFromScrollDir(
2090 win
->ScrollDirFromRange(range
));
2091 wxScrollWinEvent
event(wxEVT_SCROLLWIN_THUMBRELEASE
, win
->GetScrollPos(orient
), orient
);
2092 event
.SetEventObject(win
);
2093 win
->GetEventHandler()->ProcessEvent(event
);
2097 //-----------------------------------------------------------------------------
2098 // "button_release_event" from scrollbar
2099 //-----------------------------------------------------------------------------
2102 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
2106 g_blockEventsOnScroll
= false;
2107 win
->m_mouseButtonDown
= false;
2108 // If thumb tracking
2109 if (win
->m_isScrolling
)
2111 win
->m_isScrolling
= false;
2112 // Hook up handler to send thumb release event after this emission is finished.
2113 // To allow setting scroll position from event handler, sending event must
2114 // be deferred until after the GtkRange handler for this signal has run
2115 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
2121 //-----------------------------------------------------------------------------
2122 // "realize" from m_widget
2123 //-----------------------------------------------------------------------------
2125 /* We cannot set colours and fonts before the widget has
2126 been realized, so we do this directly after realization. */
2129 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2134 wxapp_install_idle_handler();
2138 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2139 gtk_im_context_set_client_window( win
->m_imData
->context
,
2140 pizza
->bin_window
);
2143 wxWindowCreateEvent
event( win
);
2144 event
.SetEventObject( win
);
2145 win
->GetEventHandler()->ProcessEvent( event
);
2148 //-----------------------------------------------------------------------------
2150 //-----------------------------------------------------------------------------
2153 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2154 GtkAllocation
*WXUNUSED(alloc
),
2158 wxapp_install_idle_handler();
2160 int client_width
= 0;
2161 int client_height
= 0;
2162 win
->GetClientSize( &client_width
, &client_height
);
2163 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2166 win
->m_oldClientWidth
= client_width
;
2167 win
->m_oldClientHeight
= client_height
;
2169 if (!win
->m_nativeSizeEvent
)
2171 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2172 event
.SetEventObject( win
);
2173 win
->GetEventHandler()->ProcessEvent( event
);
2179 #define WXUNUSED_UNLESS_XIM(param) param
2181 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2184 /* Resize XIM window */
2186 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2187 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2188 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2191 wxapp_install_idle_handler();
2197 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2201 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2202 win
->m_icattr
->preedit_area
.width
= width
;
2203 win
->m_icattr
->preedit_area
.height
= height
;
2204 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2209 //-----------------------------------------------------------------------------
2210 // "realize" from m_wxwindow
2211 //-----------------------------------------------------------------------------
2213 /* Initialize XIM support */
2216 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2217 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2220 wxapp_install_idle_handler();
2223 if (win
->m_ic
) return;
2224 if (!widget
) return;
2225 if (!gdk_im_ready()) return;
2227 win
->m_icattr
= gdk_ic_attr_new();
2228 if (!win
->m_icattr
) return;
2232 GdkColormap
*colormap
;
2233 GdkICAttr
*attr
= win
->m_icattr
;
2234 unsigned attrmask
= GDK_IC_ALL_REQ
;
2236 GdkIMStyle supported_style
= (GdkIMStyle
)
2237 (GDK_IM_PREEDIT_NONE
|
2238 GDK_IM_PREEDIT_NOTHING
|
2239 GDK_IM_PREEDIT_POSITION
|
2240 GDK_IM_STATUS_NONE
|
2241 GDK_IM_STATUS_NOTHING
);
2243 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2244 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2246 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2247 attr
->client_window
= widget
->window
;
2249 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2250 gtk_widget_get_default_colormap ())
2252 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2253 attr
->preedit_colormap
= colormap
;
2256 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2257 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2258 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2259 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2261 switch (style
& GDK_IM_PREEDIT_MASK
)
2263 case GDK_IM_PREEDIT_POSITION
:
2264 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2266 g_warning ("over-the-spot style requires fontset");
2270 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2272 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2273 attr
->spot_location
.x
= 0;
2274 attr
->spot_location
.y
= height
;
2275 attr
->preedit_area
.x
= 0;
2276 attr
->preedit_area
.y
= 0;
2277 attr
->preedit_area
.width
= width
;
2278 attr
->preedit_area
.height
= height
;
2279 attr
->preedit_fontset
= widget
->style
->font
;
2284 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2286 if (win
->m_ic
== NULL
)
2287 g_warning ("Can't create input context.");
2290 mask
= gdk_window_get_events (widget
->window
);
2291 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2292 gdk_window_set_events (widget
->window
, mask
);
2294 if (GTK_WIDGET_HAS_FOCUS(widget
))
2295 gdk_im_begin (win
->m_ic
, widget
->window
);
2302 // ----------------------------------------------------------------------------
2303 // this wxWindowBase function is implemented here (in platform-specific file)
2304 // because it is static and so couldn't be made virtual
2305 // ----------------------------------------------------------------------------
2307 wxWindow
*wxWindowBase::DoFindFocus()
2309 // the cast is necessary when we compile in wxUniversal mode
2310 return (wxWindow
*)g_focusWindow
;
2313 //-----------------------------------------------------------------------------
2314 // InsertChild for wxWindowGTK.
2315 //-----------------------------------------------------------------------------
2317 /* Callback for wxWindowGTK. This very strange beast has to be used because
2318 * C++ has no virtual methods in a constructor. We have to emulate a
2319 * virtual function here as wxNotebook requires a different way to insert
2320 * a child in it. I had opted for creating a wxNotebookPage window class
2321 * which would have made this superfluous (such in the MDI window system),
2322 * but no-one was listening to me... */
2324 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2326 /* the window might have been scrolled already, do we
2327 have to adapt the position */
2328 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2329 child
->m_x
+= pizza
->xoffset
;
2330 child
->m_y
+= pizza
->yoffset
;
2332 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2333 GTK_WIDGET(child
->m_widget
),
2340 //-----------------------------------------------------------------------------
2342 //-----------------------------------------------------------------------------
2344 wxWindow
*wxGetActiveWindow()
2346 return wxWindow::FindFocus();
2350 wxMouseState
wxGetMouseState()
2356 GdkModifierType mask
;
2358 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2362 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2363 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2364 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2366 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2367 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2368 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2369 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2374 //-----------------------------------------------------------------------------
2376 //-----------------------------------------------------------------------------
2378 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2380 #ifdef __WXUNIVERSAL__
2381 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2383 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2384 #endif // __WXUNIVERSAL__/__WXGTK__
2386 void wxWindowGTK::Init()
2389 m_widget
= (GtkWidget
*) NULL
;
2390 m_wxwindow
= (GtkWidget
*) NULL
;
2391 m_focusWidget
= (GtkWidget
*) NULL
;
2401 m_needParent
= true;
2402 m_isBeingDeleted
= false;
2404 m_showOnIdle
= false;
2407 m_nativeSizeEvent
= false;
2409 m_hasScrolling
= false;
2410 m_isScrolling
= false;
2411 m_mouseButtonDown
= false;
2412 m_blockScrollEvent
= false;
2414 // initialize scrolling stuff
2415 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2417 m_scrollBar
[dir
] = NULL
;
2418 m_scrollPos
[dir
] = 0;
2419 m_blockValueChanged
[dir
] = false;
2423 m_oldClientHeight
= 0;
2427 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2429 m_acceptsFocus
= false;
2432 m_clipPaintRegion
= false;
2434 m_needsStyleChange
= false;
2436 m_cursor
= *wxSTANDARD_CURSOR
;
2439 m_dirtyTabOrder
= false;
2442 wxWindowGTK::wxWindowGTK()
2447 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2452 const wxString
&name
)
2456 Create( parent
, id
, pos
, size
, style
, name
);
2459 bool wxWindowGTK::Create( wxWindow
*parent
,
2464 const wxString
&name
)
2466 if (!PreCreation( parent
, pos
, size
) ||
2467 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2469 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2473 m_insertCallback
= wxInsertChildInWindow
;
2475 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2476 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2478 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2480 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2481 scroll_class
->scrollbar_spacing
= 0;
2483 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2485 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2486 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2488 m_wxwindow
= gtk_pizza_new();
2490 #ifndef __WXUNIVERSAL__
2491 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2493 if (HasFlag(wxRAISED_BORDER
))
2495 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2497 else if (HasFlag(wxSUNKEN_BORDER
))
2499 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2501 else if (HasFlag(wxSIMPLE_BORDER
))
2503 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2507 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2509 #endif // __WXUNIVERSAL__
2511 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2513 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2514 m_acceptsFocus
= true;
2516 // connect various scroll-related events
2517 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2519 // these handlers block mouse events to any window during scrolling
2520 // such as motion events and prevent GTK and wxWidgets from fighting
2521 // over where the slider should be
2522 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2523 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2524 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2525 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2527 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2528 G_CALLBACK(gtk_scrollbar_event_after
), this);
2529 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2531 // these handlers get notified when scrollbar slider moves
2532 g_signal_connect(m_scrollBar
[dir
], "value_changed",
2533 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2536 gtk_widget_show( m_wxwindow
);
2539 m_parent
->DoAddChild( this );
2541 m_focusWidget
= m_wxwindow
;
2548 wxWindowGTK::~wxWindowGTK()
2552 if (g_focusWindow
== this)
2553 g_focusWindow
= NULL
;
2555 if ( g_delayedFocus
== this )
2556 g_delayedFocus
= NULL
;
2558 m_isBeingDeleted
= true;
2561 // destroy children before destroying this window itself
2564 // unhook focus handlers to prevent stray events being
2565 // propagated to this (soon to be) dead object
2566 if (m_focusWidget
!= NULL
)
2568 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2569 (gpointer
) gtk_window_focus_in_callback
,
2571 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2572 (gpointer
) gtk_window_focus_out_callback
,
2581 gdk_ic_destroy (m_ic
);
2583 gdk_ic_attr_destroy (m_icattr
);
2586 // delete before the widgets to avoid a crash on solaris
2591 gtk_widget_destroy( m_wxwindow
);
2592 m_wxwindow
= (GtkWidget
*) NULL
;
2597 gtk_widget_destroy( m_widget
);
2598 m_widget
= (GtkWidget
*) NULL
;
2602 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2604 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2606 // Use either the given size, or the default if -1 is given.
2607 // See wxWindowBase for these functions.
2608 m_width
= WidthDefault(size
.x
) ;
2609 m_height
= HeightDefault(size
.y
);
2617 void wxWindowGTK::PostCreation()
2619 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2625 // these get reported to wxWidgets -> wxPaintEvent
2627 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2629 g_signal_connect (m_wxwindow
, "expose_event",
2630 G_CALLBACK (gtk_window_expose_callback
), this);
2632 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2635 // Create input method handler
2636 m_imData
= new wxGtkIMData
;
2638 // Cannot handle drawing preedited text yet
2639 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2641 g_signal_connect (m_imData
->context
, "commit",
2642 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2644 // these are called when the "sunken" or "raised" borders are drawn
2645 g_signal_connect (m_widget
, "expose_event",
2646 G_CALLBACK (gtk_window_own_expose_callback
), this);
2651 if (!GTK_IS_WINDOW(m_widget
))
2653 if (m_focusWidget
== NULL
)
2654 m_focusWidget
= m_widget
;
2658 g_signal_connect (m_focusWidget
, "focus_in_event",
2659 G_CALLBACK (gtk_window_focus_in_callback
), this);
2660 g_signal_connect (m_focusWidget
, "focus_out_event",
2661 G_CALLBACK (gtk_window_focus_out_callback
), this);
2665 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2666 G_CALLBACK (gtk_window_focus_in_callback
), this);
2667 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2668 G_CALLBACK (gtk_window_focus_out_callback
), this);
2672 // connect to the various key and mouse handlers
2674 GtkWidget
*connect_widget
= GetConnectWidget();
2676 ConnectWidget( connect_widget
);
2678 /* We cannot set colours, fonts and cursors before the widget has
2679 been realized, so we do this directly after realization */
2680 g_signal_connect (connect_widget
, "realize",
2681 G_CALLBACK (gtk_window_realized_callback
), this);
2685 // Catch native resize events
2686 g_signal_connect (m_wxwindow
, "size_allocate",
2687 G_CALLBACK (gtk_window_size_callback
), this);
2689 // Initialize XIM support
2690 g_signal_connect (m_wxwindow
, "realize",
2691 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2693 // And resize XIM window
2694 g_signal_connect (m_wxwindow
, "size_allocate",
2695 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2698 if (GTK_IS_COMBO(m_widget
))
2700 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2702 g_signal_connect (gcombo
->entry
, "size_request",
2703 G_CALLBACK (wxgtk_combo_size_request_callback
),
2706 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2707 else if (GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2709 // If we connect to the "size_request" signal of a GtkFileChooserButton
2710 // then that control won't be sized properly when placed inside sizers
2711 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2712 // FIXME: what should be done here ?
2717 // This is needed if we want to add our windows into native
2718 // GTK controls, such as the toolbar. With this callback, the
2719 // toolbar gets to know the correct size (the one set by the
2720 // programmer). Sadly, it misbehaves for wxComboBox.
2721 g_signal_connect (m_widget
, "size_request",
2722 G_CALLBACK (wxgtk_window_size_request_callback
),
2726 InheritAttributes();
2730 // unless the window was created initially hidden (i.e. Hide() had been
2731 // called before Create()), we should show it at GTK+ level as well
2733 gtk_widget_show( m_widget
);
2736 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2738 g_signal_connect (widget
, "key_press_event",
2739 G_CALLBACK (gtk_window_key_press_callback
), this);
2740 g_signal_connect (widget
, "key_release_event",
2741 G_CALLBACK (gtk_window_key_release_callback
), this);
2742 g_signal_connect (widget
, "button_press_event",
2743 G_CALLBACK (gtk_window_button_press_callback
), this);
2744 g_signal_connect (widget
, "button_release_event",
2745 G_CALLBACK (gtk_window_button_release_callback
), this);
2746 g_signal_connect (widget
, "motion_notify_event",
2747 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2748 g_signal_connect (widget
, "scroll_event",
2749 G_CALLBACK (window_scroll_event
), this);
2750 g_signal_connect (widget
, "popup_menu",
2751 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2752 g_signal_connect (widget
, "enter_notify_event",
2753 G_CALLBACK (gtk_window_enter_callback
), this);
2754 g_signal_connect (widget
, "leave_notify_event",
2755 G_CALLBACK (gtk_window_leave_callback
), this);
2758 bool wxWindowGTK::Destroy()
2760 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2764 return wxWindowBase::Destroy();
2767 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2769 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2772 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2774 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2775 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2778 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2781 if (m_resizing
) return; /* I don't like recursions */
2784 int currentX
, currentY
;
2785 GetPosition(¤tX
, ¤tY
);
2786 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2788 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2790 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2792 // calculate the best size if we should auto size the window
2793 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2794 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2796 const wxSize sizeBest
= GetBestSize();
2797 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2799 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2800 height
= sizeBest
.y
;
2808 int minWidth
= GetMinWidth(),
2809 minHeight
= GetMinHeight(),
2810 maxWidth
= GetMaxWidth(),
2811 maxHeight
= GetMaxHeight();
2813 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2814 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2815 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2816 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2818 #if wxUSE_TOOLBAR_NATIVE
2819 if (wxDynamicCast(GetParent(), wxToolBar
))
2821 // don't take the x,y values, they're wrong because toolbar sets them
2822 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2823 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2824 if (GTK_WIDGET_VISIBLE (widget
))
2825 gtk_widget_queue_resize (widget
);
2829 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2831 // don't set the size for children of wxNotebook, just take the values.
2839 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2840 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2842 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2843 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2847 m_x
= x
+ pizza
->xoffset
;
2848 m_y
= y
+ pizza
->yoffset
;
2851 int left_border
= 0;
2852 int right_border
= 0;
2854 int bottom_border
= 0;
2856 /* the default button has a border around it */
2857 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2859 GtkBorder
*default_border
= NULL
;
2860 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2863 left_border
+= default_border
->left
;
2864 right_border
+= default_border
->right
;
2865 top_border
+= default_border
->top
;
2866 bottom_border
+= default_border
->bottom
;
2867 g_free( default_border
);
2871 DoMoveWindow( m_x
-top_border
,
2873 m_width
+left_border
+right_border
,
2874 m_height
+top_border
+bottom_border
);
2879 /* Sometimes the client area changes size without the
2880 whole windows's size changing, but if the whole
2881 windows's size doesn't change, no wxSizeEvent will
2882 normally be sent. Here we add an extra test if
2883 the client test has been changed and this will
2885 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2889 wxPrintf( "OnSize sent from " );
2890 if (GetClassInfo() && GetClassInfo()->GetClassName())
2891 wxPrintf( GetClassInfo()->GetClassName() );
2892 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2895 if (!m_nativeSizeEvent
)
2897 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2898 event
.SetEventObject( this );
2899 GetEventHandler()->ProcessEvent( event
);
2905 bool wxWindowGTK::GtkShowFromOnIdle()
2907 if (IsShown() && m_showOnIdle
&& !GTK_WIDGET_VISIBLE (m_widget
))
2909 GtkAllocation alloc
;
2912 alloc
.width
= m_width
;
2913 alloc
.height
= m_height
;
2914 gtk_widget_size_allocate( m_widget
, &alloc
);
2915 gtk_widget_show( m_widget
);
2916 wxShowEvent
eventShow(GetId(), true);
2917 eventShow
.SetEventObject(this);
2918 GetEventHandler()->ProcessEvent(eventShow
);
2919 m_showOnIdle
= false;
2926 void wxWindowGTK::OnInternalIdle()
2928 // Check if we have to show window now
2929 if (GtkShowFromOnIdle()) return;
2931 if ( m_dirtyTabOrder
)
2933 m_dirtyTabOrder
= false;
2937 // Update style if the window was not yet realized
2938 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2939 if (m_needsStyleChange
)
2941 SetBackgroundStyle(GetBackgroundStyle());
2942 m_needsStyleChange
= false;
2945 // Update invalidated regions.
2948 wxCursor cursor
= m_cursor
;
2949 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2953 /* I now set the cursor anew in every OnInternalIdle call
2954 as setting the cursor in a parent window also effects the
2955 windows above so that checking for the current cursor is
2960 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2962 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2964 if (!g_globalCursor
.Ok())
2965 cursor
= *wxSTANDARD_CURSOR
;
2967 window
= m_widget
->window
;
2968 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2969 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2972 else if ( m_widget
)
2974 GdkWindow
*window
= m_widget
->window
;
2975 if ( window
&& !GTK_WIDGET_NO_WINDOW(m_widget
) )
2976 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2980 if (wxUpdateUIEvent::CanUpdate(this))
2981 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2984 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2986 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2988 if (width
) (*width
) = m_width
;
2989 if (height
) (*height
) = m_height
;
2992 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2994 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3003 GetScrollbarWidth(m_widget
, dw
, dh
);
3006 #ifndef __WXUNIVERSAL__
3007 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3009 // shadow border size is 2
3013 if (HasFlag(wxSIMPLE_BORDER
))
3015 // simple border size is 1
3019 #endif // __WXUNIVERSAL__
3025 SetSize(width
, height
);
3028 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3030 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3042 GetScrollbarWidth(m_widget
, dw
, dh
);
3045 #ifndef __WXUNIVERSAL__
3046 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3048 // shadow border size is 2
3052 if (HasFlag(wxSIMPLE_BORDER
))
3054 // simple border size is 1
3058 #endif // __WXUNIVERSAL__
3064 if (width
) *width
= w
;
3065 if (height
) *height
= h
;
3068 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3070 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3074 if (m_parent
&& m_parent
->m_wxwindow
)
3076 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3077 dx
= pizza
->xoffset
;
3078 dy
= pizza
->yoffset
;
3081 if (x
) (*x
) = m_x
- dx
;
3082 if (y
) (*y
) = m_y
- dy
;
3085 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3087 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3089 if (!m_widget
->window
) return;
3091 GdkWindow
*source
= (GdkWindow
*) NULL
;
3093 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3095 source
= m_widget
->window
;
3099 gdk_window_get_origin( source
, &org_x
, &org_y
);
3103 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3105 org_x
+= m_widget
->allocation
.x
;
3106 org_y
+= m_widget
->allocation
.y
;
3114 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3116 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3118 if (!m_widget
->window
) return;
3120 GdkWindow
*source
= (GdkWindow
*) NULL
;
3122 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3124 source
= m_widget
->window
;
3128 gdk_window_get_origin( source
, &org_x
, &org_y
);
3132 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3134 org_x
+= m_widget
->allocation
.x
;
3135 org_y
+= m_widget
->allocation
.y
;
3143 bool wxWindowGTK::Show( bool show
)
3145 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3147 if (!wxWindowBase::Show(show
))
3157 gtk_widget_show( m_widget
);
3158 wxShowEvent
eventShow(GetId(), show
);
3159 eventShow
.SetEventObject(this);
3160 GetEventHandler()->ProcessEvent(eventShow
);
3165 gtk_widget_hide( m_widget
);
3166 wxShowEvent
eventShow(GetId(), show
);
3167 eventShow
.SetEventObject(this);
3168 GetEventHandler()->ProcessEvent(eventShow
);
3174 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3176 win
->OnParentEnable(enable
);
3178 // Recurse, so that children have the opportunity to Do The Right Thing
3179 // and reset colours that have been messed up by a parent's (really ancestor's)
3181 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3183 node
= node
->GetNext() )
3185 wxWindow
*child
= node
->GetData();
3186 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3187 wxWindowNotifyEnable(child
, enable
);
3191 bool wxWindowGTK::Enable( bool enable
)
3193 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3195 if (!wxWindowBase::Enable(enable
))
3201 gtk_widget_set_sensitive( m_widget
, enable
);
3203 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3205 wxWindowNotifyEnable(this, enable
);
3210 int wxWindowGTK::GetCharHeight() const
3212 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3214 wxFont font
= GetFont();
3215 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3217 PangoContext
*context
= NULL
;
3219 context
= gtk_widget_get_pango_context( m_widget
);
3224 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3225 PangoLayout
*layout
= pango_layout_new(context
);
3226 pango_layout_set_font_description(layout
, desc
);
3227 pango_layout_set_text(layout
, "H", 1);
3228 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3230 PangoRectangle rect
;
3231 pango_layout_line_get_extents(line
, NULL
, &rect
);
3233 g_object_unref (layout
);
3235 return (int) PANGO_PIXELS(rect
.height
);
3238 int wxWindowGTK::GetCharWidth() const
3240 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3242 wxFont font
= GetFont();
3243 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3245 PangoContext
*context
= NULL
;
3247 context
= gtk_widget_get_pango_context( m_widget
);
3252 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3253 PangoLayout
*layout
= pango_layout_new(context
);
3254 pango_layout_set_font_description(layout
, desc
);
3255 pango_layout_set_text(layout
, "g", 1);
3256 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3258 PangoRectangle rect
;
3259 pango_layout_line_get_extents(line
, NULL
, &rect
);
3261 g_object_unref (layout
);
3263 return (int) PANGO_PIXELS(rect
.width
);
3266 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3270 int *externalLeading
,
3271 const wxFont
*theFont
) const
3273 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3275 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3284 PangoContext
*context
= NULL
;
3286 context
= gtk_widget_get_pango_context( m_widget
);
3295 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3296 PangoLayout
*layout
= pango_layout_new(context
);
3297 pango_layout_set_font_description(layout
, desc
);
3299 const wxCharBuffer data
= wxGTK_CONV( string
);
3301 pango_layout_set_text(layout
, data
, strlen(data
));
3304 PangoRectangle rect
;
3305 pango_layout_get_extents(layout
, NULL
, &rect
);
3307 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3308 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3311 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3312 int baseline
= pango_layout_iter_get_baseline(iter
);
3313 pango_layout_iter_free(iter
);
3314 *descent
= *y
- PANGO_PIXELS(baseline
);
3316 if (externalLeading
) (*externalLeading
) = 0; // ??
3318 g_object_unref (layout
);
3321 bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
3323 if ( g_delayedFocus
== this )
3325 if ( GTK_WIDGET_REALIZED(m_widget
) )
3327 gtk_widget_grab_focus(m_widget
);
3328 g_delayedFocus
= NULL
;
3337 void wxWindowGTK::SetFocus()
3339 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3342 // don't do anything if we already have focus
3348 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3350 gtk_widget_grab_focus (m_wxwindow
);
3355 if (GTK_IS_CONTAINER(m_widget
))
3357 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3360 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3363 if (!GTK_WIDGET_REALIZED(m_widget
))
3365 // we can't set the focus to the widget now so we remember that
3366 // it should be focused and will do it later, during the idle
3367 // time, as soon as we can
3368 wxLogTrace(TRACE_FOCUS
,
3369 _T("Delaying setting focus to %s(%s)"),
3370 GetClassInfo()->GetClassName(), GetLabel().c_str());
3372 g_delayedFocus
= this;
3376 wxLogTrace(TRACE_FOCUS
,
3377 _T("Setting focus to %s(%s)"),
3378 GetClassInfo()->GetClassName(), GetLabel().c_str());
3380 gtk_widget_grab_focus (m_widget
);
3385 wxLogTrace(TRACE_FOCUS
,
3386 _T("Can't set focus to %s(%s)"),
3387 GetClassInfo()->GetClassName(), GetLabel().c_str());
3392 bool wxWindowGTK::AcceptsFocus() const
3394 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3397 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3399 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3401 wxWindowGTK
*oldParent
= m_parent
,
3402 *newParent
= (wxWindowGTK
*)newParentBase
;
3404 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3406 if ( !wxWindowBase::Reparent(newParent
) )
3409 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3411 /* prevent GTK from deleting the widget arbitrarily */
3412 gtk_widget_ref( m_widget
);
3416 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3419 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3423 if (GTK_WIDGET_VISIBLE (newParent
->m_widget
))
3425 m_showOnIdle
= true;
3426 gtk_widget_hide( m_widget
);
3429 /* insert GTK representation */
3430 (*(newParent
->m_insertCallback
))(newParent
, this);
3433 /* reverse: prevent GTK from deleting the widget arbitrarily */
3434 gtk_widget_unref( m_widget
);
3439 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3441 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3443 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3445 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3450 /* insert GTK representation */
3451 (*m_insertCallback
)(this, child
);
3454 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3456 wxWindowBase::AddChild(child
);
3457 m_dirtyTabOrder
= true;
3459 wxapp_install_idle_handler();
3462 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3464 wxWindowBase::RemoveChild(child
);
3465 m_dirtyTabOrder
= true;
3467 wxapp_install_idle_handler();
3470 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3472 wxWindowBase::DoMoveInTabOrder(win
, move
);
3473 m_dirtyTabOrder
= true;
3475 wxapp_install_idle_handler();
3478 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3480 // none needed by default
3484 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3486 // nothing to do by default since none is needed
3489 void wxWindowGTK::RealizeTabOrder()
3493 if ( !m_children
.empty() )
3495 // we don't only construct the correct focus chain but also use
3496 // this opportunity to update the mnemonic widgets for the widgets
3499 GList
*chain
= NULL
;
3500 wxWindowGTK
* mnemonicWindow
= NULL
;
3502 for ( wxWindowList::const_iterator i
= m_children
.begin();
3503 i
!= m_children
.end();
3506 wxWindowGTK
*win
= *i
;
3508 if ( mnemonicWindow
)
3510 if ( win
->AcceptsFocusFromKeyboard() )
3512 // wxComboBox et al. needs to focus on on a different
3513 // widget than m_widget, so if the main widget isn't
3514 // focusable try the connect widget
3515 GtkWidget
* w
= win
->m_widget
;
3516 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3518 w
= win
->GetConnectWidget();
3519 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3525 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3526 mnemonicWindow
= NULL
;
3530 else if ( win
->GTKWidgetNeedsMnemonic() )
3532 mnemonicWindow
= win
;
3535 chain
= g_list_prepend(chain
, win
->m_widget
);
3538 chain
= g_list_reverse(chain
);
3540 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3545 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3550 void wxWindowGTK::Raise()
3552 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3554 if (m_wxwindow
&& m_wxwindow
->window
)
3556 gdk_window_raise( m_wxwindow
->window
);
3558 else if (m_widget
->window
)
3560 gdk_window_raise( m_widget
->window
);
3564 void wxWindowGTK::Lower()
3566 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3568 if (m_wxwindow
&& m_wxwindow
->window
)
3570 gdk_window_lower( m_wxwindow
->window
);
3572 else if (m_widget
->window
)
3574 gdk_window_lower( m_widget
->window
);
3578 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3580 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3582 if (cursor
== m_cursor
)
3586 wxapp_install_idle_handler();
3588 return wxWindowBase::SetCursor( cursor
.Ok() ? cursor
: *wxSTANDARD_CURSOR
);
3591 void wxWindowGTK::GTKUpdateCursor()
3593 wxCursor
cursor(g_globalCursor
.Ok() ? g_globalCursor
: GetCursor());
3596 wxArrayGdkWindows windowsThis
;
3597 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
3600 gdk_window_set_cursor(winThis
, cursor
.GetCursor());
3604 const size_t count
= windowsThis
.size();
3605 for ( size_t n
= 0; n
< count
; n
++ )
3607 gdk_window_set_cursor(windowsThis
[n
], cursor
.GetCursor());
3613 void wxWindowGTK::WarpPointer( int x
, int y
)
3615 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3617 // We provide this function ourselves as it is
3618 // missing in GDK (top of this file).
3620 GdkWindow
*window
= (GdkWindow
*) NULL
;
3622 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3624 window
= GetConnectWidget()->window
;
3627 gdk_window_warp_pointer( window
, x
, y
);
3630 wxWindowGTK::ScrollDir
wxWindowGTK::ScrollDirFromRange(GtkRange
*range
) const
3632 // find the scrollbar which generated the event
3633 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3635 if ( range
== m_scrollBar
[dir
] )
3636 return (ScrollDir
)dir
;
3639 wxFAIL_MSG( _T("event from unknown scrollbar received") );
3641 return ScrollDir_Max
;
3644 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3646 bool changed
= false;
3647 GtkRange
* range
= m_scrollBar
[dir
];
3648 if ( range
&& units
)
3650 GtkAdjustment
* adj
= range
->adjustment
;
3651 gdouble inc
= unit
== ScrollUnit_Line
? adj
->step_increment
3652 : adj
->page_increment
;
3654 const int posOld
= int(adj
->value
+ 0.5);
3655 gtk_range_set_value(range
, posOld
+ units
*inc
);
3657 changed
= int(adj
->value
+ 0.5) != posOld
;
3663 bool wxWindowGTK::ScrollLines(int lines
)
3665 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3668 bool wxWindowGTK::ScrollPages(int pages
)
3670 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3673 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3677 if (!m_widget
->window
)
3682 if (!GTK_PIZZA(m_wxwindow
)->bin_window
) return;
3684 GdkRectangle gdk_rect
,
3688 gdk_rect
.x
= rect
->x
;
3689 gdk_rect
.y
= rect
->y
;
3690 gdk_rect
.width
= rect
->width
;
3691 gdk_rect
.height
= rect
->height
;
3694 else // invalidate everything
3699 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3703 void wxWindowGTK::Update()
3707 // when we call Update() we really want to update the window immediately on
3708 // screen, even if it means flushing the entire queue and hence slowing down
3709 // everything -- but it should still be done, it's just that Update() should
3710 // be called very rarely
3714 void wxWindowGTK::GtkUpdate()
3716 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3717 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3718 if (m_widget
&& m_widget
->window
)
3719 gdk_window_process_updates( m_widget
->window
, FALSE
);
3721 // for consistency with other platforms (and also because it's convenient
3722 // to be able to update an entire TLW by calling Update() only once), we
3723 // should also update all our children here
3724 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3726 node
= node
->GetNext() )
3728 node
->GetData()->GtkUpdate();
3732 void wxWindowGTK::GtkSendPaintEvents()
3736 m_updateRegion
.Clear();
3740 // Clip to paint region in wxClientDC
3741 m_clipPaintRegion
= true;
3743 // widget to draw on
3744 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3746 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3748 // find ancestor from which to steal background
3749 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3751 parent
= (wxWindow
*)this;
3753 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3755 wxRegionIterator
upd( m_updateRegion
);
3759 rect
.x
= upd
.GetX();
3760 rect
.y
= upd
.GetY();
3761 rect
.width
= upd
.GetWidth();
3762 rect
.height
= upd
.GetHeight();
3764 gtk_paint_flat_box( parent
->m_widget
->style
,
3766 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3780 wxWindowDC
dc( (wxWindow
*)this );
3781 dc
.SetClippingRegion( m_updateRegion
);
3783 wxEraseEvent
erase_event( GetId(), &dc
);
3784 erase_event
.SetEventObject( this );
3786 GetEventHandler()->ProcessEvent(erase_event
);
3789 wxNcPaintEvent
nc_paint_event( GetId() );
3790 nc_paint_event
.SetEventObject( this );
3791 GetEventHandler()->ProcessEvent( nc_paint_event
);
3793 wxPaintEvent
paint_event( GetId() );
3794 paint_event
.SetEventObject( this );
3795 GetEventHandler()->ProcessEvent( paint_event
);
3797 m_clipPaintRegion
= false;
3799 m_updateRegion
.Clear();
3802 void wxWindowGTK::SetDoubleBuffered( bool on
)
3804 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3807 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3810 void wxWindowGTK::ClearBackground()
3812 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3816 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3818 wxWindowBase::DoSetToolTip(tip
);
3821 m_tooltip
->Apply( (wxWindow
*)this );
3824 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3826 wxString
tmp( tip
);
3827 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3829 #endif // wxUSE_TOOLTIPS
3831 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3833 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3835 if (!wxWindowBase::SetBackgroundColour(colour
))
3840 // We need the pixel value e.g. for background clearing.
3841 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3844 // apply style change (forceStyle=true so that new style is applied
3845 // even if the bg colour changed from valid to wxNullColour)
3846 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3847 ApplyWidgetStyle(true);
3852 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3854 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3856 if (!wxWindowBase::SetForegroundColour(colour
))
3863 // We need the pixel value e.g. for background clearing.
3864 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3867 // apply style change (forceStyle=true so that new style is applied
3868 // even if the bg colour changed from valid to wxNullColour):
3869 ApplyWidgetStyle(true);
3874 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3876 return gtk_widget_get_pango_context( m_widget
);
3879 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3881 // do we need to apply any changes at all?
3884 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3889 GtkRcStyle
*style
= gtk_rc_style_new();
3894 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3897 if ( m_foregroundColour
.Ok() )
3899 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3901 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3902 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3904 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3905 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3907 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3908 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3911 if ( m_backgroundColour
.Ok() )
3913 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3915 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3916 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3917 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3918 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3920 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3921 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3922 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3923 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3925 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3926 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3927 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3928 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3930 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3931 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3932 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3933 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3939 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3941 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3944 DoApplyWidgetStyle(style
);
3945 gtk_rc_style_unref(style
);
3948 // Style change may affect GTK+'s size calculation:
3949 InvalidateBestSize();
3952 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3955 gtk_widget_modify_style(m_wxwindow
, style
);
3957 gtk_widget_modify_style(m_widget
, style
);
3960 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3962 wxWindowBase::SetBackgroundStyle(style
);
3964 if (style
== wxBG_STYLE_CUSTOM
)
3966 GdkWindow
*window
= (GdkWindow
*) NULL
;
3968 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3970 window
= GetConnectWidget()->window
;
3974 // Make sure GDK/X11 doesn't refresh the window
3976 gdk_window_set_back_pixmap( window
, None
, False
);
3978 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3981 m_needsStyleChange
= false;
3984 // Do in OnIdle, because the window is not yet available
3985 m_needsStyleChange
= true;
3987 // Don't apply widget style, or we get a grey background
3991 // apply style change (forceStyle=true so that new style is applied
3992 // even if the bg colour changed from valid to wxNullColour):
3993 ApplyWidgetStyle(true);
3998 #if wxUSE_DRAG_AND_DROP
4000 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4002 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4004 GtkWidget
*dnd_widget
= GetConnectWidget();
4006 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4008 if (m_dropTarget
) delete m_dropTarget
;
4009 m_dropTarget
= dropTarget
;
4011 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4014 #endif // wxUSE_DRAG_AND_DROP
4016 GtkWidget
* wxWindowGTK::GetConnectWidget()
4018 GtkWidget
*connect_widget
= m_widget
;
4019 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4021 return connect_widget
;
4024 bool wxWindowGTK::GTKIsOwnWindow(GdkWindow
*window
) const
4026 wxArrayGdkWindows windowsThis
;
4027 GdkWindow
* const winThis
= GTKGetWindow(windowsThis
);
4029 return winThis
? window
== winThis
4030 : windowsThis
.Index(window
) != wxNOT_FOUND
;
4033 GdkWindow
*wxWindowGTK::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
4035 return m_wxwindow
? GTK_PIZZA(m_wxwindow
)->bin_window
: m_widget
->window
;
4038 bool wxWindowGTK::SetFont( const wxFont
&font
)
4040 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4042 if (!wxWindowBase::SetFont(font
))
4045 // apply style change (forceStyle=true so that new style is applied
4046 // even if the font changed from valid to wxNullFont):
4047 ApplyWidgetStyle(true);
4052 void wxWindowGTK::DoCaptureMouse()
4054 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4056 GdkWindow
*window
= (GdkWindow
*) NULL
;
4058 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4060 window
= GetConnectWidget()->window
;
4062 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4064 const wxCursor
* cursor
= &m_cursor
;
4066 cursor
= wxSTANDARD_CURSOR
;
4068 gdk_pointer_grab( window
, FALSE
,
4070 (GDK_BUTTON_PRESS_MASK
|
4071 GDK_BUTTON_RELEASE_MASK
|
4072 GDK_POINTER_MOTION_HINT_MASK
|
4073 GDK_POINTER_MOTION_MASK
),
4075 cursor
->GetCursor(),
4076 (guint32
)GDK_CURRENT_TIME
);
4077 g_captureWindow
= this;
4078 g_captureWindowHasMouse
= true;
4081 void wxWindowGTK::DoReleaseMouse()
4083 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4085 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4087 g_captureWindow
= (wxWindowGTK
*) NULL
;
4089 GdkWindow
*window
= (GdkWindow
*) NULL
;
4091 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4093 window
= GetConnectWidget()->window
;
4098 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4102 wxWindow
*wxWindowBase::GetCapture()
4104 return (wxWindow
*)g_captureWindow
;
4107 bool wxWindowGTK::IsRetained() const
4112 void wxWindowGTK::BlockScrollEvent()
4114 wxASSERT(!m_blockScrollEvent
);
4115 m_blockScrollEvent
= true;
4118 void wxWindowGTK::UnblockScrollEvent()
4120 wxASSERT(m_blockScrollEvent
);
4121 m_blockScrollEvent
= false;
4124 void wxWindowGTK::SetScrollbar(int orient
,
4128 bool WXUNUSED(update
))
4130 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4131 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4135 m_hasScrolling
= true;
4139 // GtkRange requires upper > lower
4144 if (pos
> range
- thumbVisible
)
4145 pos
= range
- thumbVisible
;
4148 GtkAdjustment
* adj
= m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
;
4149 adj
->step_increment
= 1;
4150 adj
->page_increment
=
4151 adj
->page_size
= thumbVisible
;
4153 SetScrollPos(orient
, pos
);
4154 gtk_adjustment_changed(adj
);
4157 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4159 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4160 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4162 // This check is more than an optimization. Without it, the slider
4163 // will not move smoothly while tracking when using wxScrollHelper.
4164 if (GetScrollPos(orient
) != pos
)
4166 const int dir
= ScrollDirFromOrient(orient
);
4167 GtkAdjustment
* adj
= m_scrollBar
[dir
]->adjustment
;
4168 const int max
= int(adj
->upper
- adj
->page_size
);
4175 // If a "value_changed" signal emission is not already in progress
4176 if (!m_blockValueChanged
[dir
])
4178 gtk_adjustment_value_changed(adj
);
4183 int wxWindowGTK::GetScrollThumb(int orient
) const
4185 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4186 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4188 return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->page_size
);
4191 int wxWindowGTK::GetScrollPos( int orient
) const
4193 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4194 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4196 return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->value
+ 0.5);
4199 int wxWindowGTK::GetScrollRange( int orient
) const
4201 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4202 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4204 return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->upper
);
4207 // Determine if increment is the same as +/-x, allowing for some small
4208 // difference due to possible inexactness in floating point arithmetic
4209 static inline bool IsScrollIncrement(double increment
, double x
)
4211 wxASSERT(increment
> 0);
4212 const double tolerance
= 1.0 / 1024;
4213 return fabs(increment
- fabs(x
)) < tolerance
;
4216 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4221 wxapp_install_idle_handler();
4223 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4225 const int barIndex
= range
== m_scrollBar
[1];
4226 GtkAdjustment
* adj
= range
->adjustment
;
4227 const int value
= int(adj
->value
+ 0.5);
4228 // save previous position
4229 const double oldPos
= m_scrollPos
[barIndex
];
4230 // update current position
4231 m_scrollPos
[barIndex
] = adj
->value
;
4232 // If event should be ignored, or integral position has not changed
4233 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4238 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4241 // Difference from last change event
4242 const double diff
= adj
->value
- oldPos
;
4243 const bool isDown
= diff
> 0;
4245 if (IsScrollIncrement(adj
->step_increment
, diff
))
4247 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4249 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4251 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4253 else if (m_mouseButtonDown
)
4255 // Assume track event
4256 m_isScrolling
= true;
4262 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4264 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4266 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4268 // No scrolling requested.
4269 if ((dx
== 0) && (dy
== 0)) return;
4271 m_clipPaintRegion
= true;
4273 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4275 m_clipPaintRegion
= false;
4278 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4280 //RN: Note that static controls usually have no border on gtk, so maybe
4281 //it makes sense to treat that as simply no border at the wx level
4283 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4285 GtkShadowType gtkstyle
;
4287 if(wxstyle
& wxBORDER_RAISED
)
4288 gtkstyle
= GTK_SHADOW_OUT
;
4289 else if (wxstyle
& wxBORDER_SUNKEN
)
4290 gtkstyle
= GTK_SHADOW_IN
;
4291 else if (wxstyle
& wxBORDER_DOUBLE
)
4292 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4294 gtkstyle
= GTK_SHADOW_IN
;
4296 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4301 void wxWindowGTK::SetWindowStyleFlag( long style
)
4303 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4304 wxWindowBase::SetWindowStyleFlag(style
);
4307 // Find the wxWindow at the current mouse position, also returning the mouse
4309 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4311 pt
= wxGetMousePosition();
4312 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4316 // Get the current mouse position.
4317 wxPoint
wxGetMousePosition()
4319 /* This crashes when used within wxHelpContext,
4320 so we have to use the X-specific implementation below.
4322 GdkModifierType *mask;
4323 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4325 return wxPoint(x, y);
4329 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4331 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4332 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4333 Window rootReturn
, childReturn
;
4334 int rootX
, rootY
, winX
, winY
;
4335 unsigned int maskReturn
;
4337 XQueryPointer (display
,
4341 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4342 return wxPoint(rootX
, rootY
);
4346 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4347 void wxAddGrab(wxWindow
* window
)
4349 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4352 void wxRemoveGrab(wxWindow
* window
)
4354 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4357 // ----------------------------------------------------------------------------
4359 // ----------------------------------------------------------------------------
4361 class wxWinModule
: public wxModule
4368 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4371 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4373 bool wxWinModule::OnInit()
4375 // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() );
4376 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4381 void wxWinModule::OnExit()
4384 g_object_unref (g_eraseGC
);