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"
36 #include "wx/module.h"
38 #if wxUSE_DRAG_AND_DROP
43 #include "wx/tooltip.h"
50 #include "wx/statusbr.h"
51 #include "wx/fontutil.h"
54 #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 allround 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 subchildren. 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 Singularily 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
,
484 wxapp_install_idle_handler();
486 // This callback gets called in drawing-idle time under
487 // GTK 2.0, so we don't need to defer anything to idle
490 GtkPizza
*pizza
= GTK_PIZZA( widget
);
491 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
496 wxPrintf( wxT("OnExpose from ") );
497 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
498 wxPrintf( win
->GetClassInfo()->GetClassName() );
499 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
500 (int)gdk_event
->area
.y
,
501 (int)gdk_event
->area
.width
,
502 (int)gdk_event
->area
.height
);
507 win
->m_wxwindow
->style
,
511 (GdkRectangle
*) NULL
,
513 (char *)"button", // const_cast
518 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
520 win
->GtkSendPaintEvents();
523 // Let parent window draw window-less widgets
524 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
530 //-----------------------------------------------------------------------------
531 // "key_press_event" from any window
532 //-----------------------------------------------------------------------------
534 // set WXTRACE to this to see the key event codes on the console
535 #define TRACE_KEYS _T("keyevent")
537 // translates an X key symbol to WXK_XXX value
539 // if isChar is true it means that the value returned will be used for EVT_CHAR
540 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
541 // for example, while if it is false it means that the value is going to be
542 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
544 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
550 // Shift, Control and Alt don't generate the CHAR events at all
553 key_code
= isChar
? 0 : WXK_SHIFT
;
557 key_code
= isChar
? 0 : WXK_CONTROL
;
565 key_code
= isChar
? 0 : WXK_ALT
;
568 // neither do the toggle modifies
569 case GDK_Scroll_Lock
:
570 key_code
= isChar
? 0 : WXK_SCROLL
;
574 key_code
= isChar
? 0 : WXK_CAPITAL
;
578 key_code
= isChar
? 0 : WXK_NUMLOCK
;
582 // various other special keys
595 case GDK_ISO_Left_Tab
:
602 key_code
= WXK_RETURN
;
606 key_code
= WXK_CLEAR
;
610 key_code
= WXK_PAUSE
;
614 key_code
= WXK_SELECT
;
618 key_code
= WXK_PRINT
;
622 key_code
= WXK_EXECUTE
;
626 key_code
= WXK_ESCAPE
;
629 // cursor and other extended keyboard keys
631 key_code
= WXK_DELETE
;
647 key_code
= WXK_RIGHT
;
654 case GDK_Prior
: // == GDK_Page_Up
655 key_code
= WXK_PAGEUP
;
658 case GDK_Next
: // == GDK_Page_Down
659 key_code
= WXK_PAGEDOWN
;
671 key_code
= WXK_INSERT
;
686 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
690 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
694 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
698 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
702 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
706 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
710 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
714 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
718 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
722 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
726 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
730 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
734 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
737 case GDK_KP_Prior
: // == GDK_KP_Page_Up
738 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
741 case GDK_KP_Next
: // == GDK_KP_Page_Down
742 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
746 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
750 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
754 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
758 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
762 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
765 case GDK_KP_Multiply
:
766 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
770 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
773 case GDK_KP_Separator
:
774 // FIXME: what is this?
775 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
778 case GDK_KP_Subtract
:
779 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
783 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
787 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
804 key_code
= WXK_F1
+ keysym
- GDK_F1
;
814 static inline bool wxIsAsciiKeysym(KeySym ks
)
819 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
821 GdkEventKey
*gdk_event
)
825 GdkModifierType state
;
826 if (gdk_event
->window
)
827 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
829 event
.SetTimestamp( gdk_event
->time
);
830 event
.SetId(win
->GetId());
831 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
832 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
833 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
834 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
835 event
.m_scanCode
= gdk_event
->keyval
;
836 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
837 event
.m_rawFlags
= 0;
839 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
841 wxGetMousePosition( &x
, &y
);
842 win
->ScreenToClient( &x
, &y
);
845 event
.SetEventObject( win
);
850 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
852 GdkEventKey
*gdk_event
)
854 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
855 // but only event->keyval which is quite useless to us, so remember
856 // the last character from GDK_KEY_PRESS and reuse it as last resort
858 // NB: should be MT-safe as we're always called from the main thread only
863 } s_lastKeyPress
= { 0, 0 };
865 KeySym keysym
= gdk_event
->keyval
;
867 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
868 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
872 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
876 // do we have the translation or is it a plain ASCII character?
877 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
879 // we should use keysym if it is ASCII as X does some translations
880 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
881 // which we don't want here (but which we do use for OnChar())
882 if ( !wxIsAsciiKeysym(keysym
) )
884 keysym
= (KeySym
)gdk_event
->string
[0];
887 // we want to always get the same key code when the same key is
888 // pressed regardless of the state of the modifiers, i.e. on a
889 // standard US keyboard pressing '5' or '%' ('5' key with
890 // Shift) should result in the same key code in OnKeyDown():
891 // '5' (although OnChar() will get either '5' or '%').
893 // to do it we first translate keysym to keycode (== scan code)
894 // and then back but always using the lower register
895 Display
*dpy
= (Display
*)wxGetDisplay();
896 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
898 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
900 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
902 // use the normalized, i.e. lower register, keysym if we've
904 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
906 // as explained above, we want to have lower register key codes
907 // normally but for the letter keys we want to have the upper ones
909 // NB: don't use XConvertCase() here, we want to do it for letters
911 key_code
= toupper(key_code
);
913 else // non ASCII key, what to do?
915 // by default, ignore it
918 // but if we have cached information from the last KEY_PRESS
919 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
922 if ( keysym
== s_lastKeyPress
.keysym
)
924 key_code
= s_lastKeyPress
.keycode
;
929 if ( gdk_event
->type
== GDK_KEY_PRESS
)
931 // remember it to be reused for KEY_UP event later
932 s_lastKeyPress
.keysym
= keysym
;
933 s_lastKeyPress
.keycode
= key_code
;
937 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
939 // sending unknown key events doesn't really make sense
943 // now fill all the other fields
944 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
946 event
.m_keyCode
= key_code
;
948 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
950 event
.m_uniChar
= key_code
;
960 GtkIMContext
*context
;
961 GdkEventKey
*lastKeyEvent
;
965 context
= gtk_im_multicontext_new();
970 g_object_unref (context
);
976 gtk_window_key_press_callback( GtkWidget
*widget
,
977 GdkEventKey
*gdk_event
,
983 wxapp_install_idle_handler();
987 if (g_blockEventsOnDrag
)
991 wxKeyEvent
event( wxEVT_KEY_DOWN
);
993 bool return_after_IM
= false;
995 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
997 // Emit KEY_DOWN event
998 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1002 // Return after IM processing as we cannot do
1003 // anything with it anyhow.
1004 return_after_IM
= true;
1007 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1008 // When we get a key_press event here, it could be originate
1009 // from the current widget or its child widgets. However, only the widget
1010 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1011 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1012 // originated from its child widgets and shouldn't be passed to IM context.
1013 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1014 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1015 // widgets has both IM context and input focus, the event should be filtered
1016 // by gtk_im_context_filter_keypress().
1017 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1018 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1020 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1021 // docs, if IM filter returns true, no further processing should be done.
1022 // we should send the key_down event anyway.
1023 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1024 win
->m_imData
->lastKeyEvent
= NULL
;
1025 if (intercepted_by_IM
)
1027 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1032 if (return_after_IM
)
1038 wxWindowGTK
*ancestor
= win
;
1041 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1044 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1045 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1048 if (ancestor
->IsTopLevel())
1050 ancestor
= ancestor
->GetParent();
1053 #endif // wxUSE_ACCEL
1055 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1056 // will only be sent if it is not in an accelerator table.
1060 KeySym keysym
= gdk_event
->keyval
;
1061 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1062 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1065 if ( wxIsAsciiKeysym(keysym
) )
1068 key_code
= (unsigned char)keysym
;
1070 // gdk_event->string is actually deprecated
1071 else if ( gdk_event
->length
== 1 )
1073 key_code
= (unsigned char)gdk_event
->string
[0];
1079 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1081 event
.m_keyCode
= key_code
;
1083 // To conform to the docs we need to translate Ctrl-alpha
1084 // characters to values in the range 1-26.
1085 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1087 event
.m_keyCode
= key_code
- 'a' + 1;
1089 event
.m_uniChar
= event
.m_keyCode
;
1093 // Implement OnCharHook by checking ancestor top level windows
1094 wxWindow
*parent
= win
;
1095 while (parent
&& !parent
->IsTopLevel())
1096 parent
= parent
->GetParent();
1099 event
.SetEventType( wxEVT_CHAR_HOOK
);
1100 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1105 event
.SetEventType(wxEVT_CHAR
);
1106 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1115 // win is a control: tab can be propagated up
1117 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1118 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1119 // have this style, yet choose not to process this particular TAB in which
1120 // case TAB must still work as a navigational character
1121 // JS: enabling again to make consistent with other platforms
1122 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1123 // navigation behaviour)
1125 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1127 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1129 wxNavigationKeyEvent new_event
;
1130 new_event
.SetEventObject( win
->GetParent() );
1131 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1132 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1133 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1134 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1135 new_event
.SetCurrentFocus( win
);
1136 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1139 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1141 (gdk_event
->keyval
== GDK_Escape
) )
1143 // however only do it if we have a Cancel button in the dialog,
1144 // otherwise the user code may get confused by the events from a
1145 // non-existing button and, worse, a wxButton might get button event
1146 // from another button which is not really expected
1147 wxWindow
*winForCancel
= win
,
1149 while ( winForCancel
)
1151 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1154 // found a cancel button
1158 if ( winForCancel
->IsTopLevel() )
1160 // no need to look further
1164 // maybe our parent has a cancel button?
1165 winForCancel
= winForCancel
->GetParent();
1170 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1171 eventClick
.SetEventObject(btnCancel
);
1172 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1178 g_signal_stop_emission_by_name (widget
, "key_press_event");
1188 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1192 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1194 // take modifiers, cursor position, timestamp etc. from the last
1195 // key_press_event that was fed into Input Method:
1196 if (window
->m_imData
->lastKeyEvent
)
1198 wxFillOtherKeyEventFields(event
,
1199 window
, window
->m_imData
->lastKeyEvent
);
1202 const wxWxCharBuffer
data(wxGTK_CONV_BACK(str
));
1208 // Implement OnCharHook by checking ancestor top level windows
1209 wxWindow
*parent
= window
;
1210 while (parent
&& !parent
->IsTopLevel())
1211 parent
= parent
->GetParent();
1213 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1216 event
.m_uniChar
= *pstr
;
1217 // Backward compatible for ISO-8859-1
1218 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1219 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1221 event
.m_keyCode
= *pstr
;
1222 #endif // wxUSE_UNICODE
1224 // To conform to the docs we need to translate Ctrl-alpha
1225 // characters to values in the range 1-26.
1226 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1228 event
.m_keyCode
= *pstr
- 'a' + 1;
1230 event
.m_uniChar
= event
.m_keyCode
;
1236 event
.SetEventType( wxEVT_CHAR_HOOK
);
1237 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1242 event
.SetEventType(wxEVT_CHAR
);
1243 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1250 //-----------------------------------------------------------------------------
1251 // "key_release_event" from any window
1252 //-----------------------------------------------------------------------------
1256 gtk_window_key_release_callback( GtkWidget
*widget
,
1257 GdkEventKey
*gdk_event
,
1263 wxapp_install_idle_handler();
1268 if (g_blockEventsOnDrag
)
1271 wxKeyEvent
event( wxEVT_KEY_UP
);
1272 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1274 // unknown key pressed, ignore (the event would be useless anyhow)
1278 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1281 g_signal_stop_emission_by_name (widget
, "key_release_event");
1286 // ============================================================================
1288 // ============================================================================
1290 // ----------------------------------------------------------------------------
1291 // mouse event processing helpers
1292 // ----------------------------------------------------------------------------
1294 // init wxMouseEvent with the info from GdkEventXXX struct
1295 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1296 wxMouseEvent
& event
,
1299 event
.SetTimestamp( gdk_event
->time
);
1300 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1301 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1302 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1303 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1304 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1305 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1306 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1307 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1309 event
.m_linesPerAction
= 3;
1310 event
.m_wheelDelta
= 120;
1311 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1312 event
.m_wheelRotation
= 120;
1313 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1314 event
.m_wheelRotation
= -120;
1317 wxPoint pt
= win
->GetClientAreaOrigin();
1318 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1319 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1321 event
.SetEventObject( win
);
1322 event
.SetId( win
->GetId() );
1323 event
.SetTimestamp( gdk_event
->time
);
1326 static void AdjustEventButtonState(wxMouseEvent
& event
)
1328 // GDK reports the old state of the button for a button press event, but
1329 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1330 // for a LEFT_DOWN event, not FALSE, so we will invert
1331 // left/right/middleDown for the corresponding click events
1333 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1334 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1335 (event
.GetEventType() == wxEVT_LEFT_UP
))
1337 event
.m_leftDown
= !event
.m_leftDown
;
1341 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1342 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1343 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1345 event
.m_middleDown
= !event
.m_middleDown
;
1349 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1350 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1351 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1353 event
.m_rightDown
= !event
.m_rightDown
;
1358 // find the window to send the mouse event too
1360 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1365 if (win
->m_wxwindow
)
1367 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1368 xx
+= pizza
->xoffset
;
1369 yy
+= pizza
->yoffset
;
1372 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1375 wxWindowGTK
*child
= node
->GetData();
1377 node
= node
->GetNext();
1378 if (!child
->IsShown())
1381 if (child
->IsTransparentForMouse())
1383 // wxStaticBox is transparent in the box itself
1384 int xx1
= child
->m_x
;
1385 int yy1
= child
->m_y
;
1386 int xx2
= child
->m_x
+ child
->m_width
;
1387 int yy2
= child
->m_y
+ child
->m_height
;
1390 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1392 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1394 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1396 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1407 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1408 (child
->m_x
<= xx
) &&
1409 (child
->m_y
<= yy
) &&
1410 (child
->m_x
+child
->m_width
>= xx
) &&
1411 (child
->m_y
+child
->m_height
>= yy
))
1424 //-----------------------------------------------------------------------------
1425 // "button_press_event"
1426 //-----------------------------------------------------------------------------
1430 gtk_window_button_press_callback( GtkWidget
*widget
,
1431 GdkEventButton
*gdk_event
,
1437 wxapp_install_idle_handler();
1440 wxPrintf( wxT("1) OnButtonPress from ") );
1441 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1442 wxPrintf( win->GetClassInfo()->GetClassName() );
1443 wxPrintf( wxT(".\n") );
1445 if (!win
->m_hasVMT
) return FALSE
;
1446 if (g_blockEventsOnDrag
) return TRUE
;
1447 if (g_blockEventsOnScroll
) return TRUE
;
1449 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1451 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1453 gtk_widget_grab_focus( win
->m_wxwindow
);
1455 wxPrintf( wxT("GrabFocus from ") );
1456 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1457 wxPrintf( win->GetClassInfo()->GetClassName() );
1458 wxPrintf( wxT(".\n") );
1462 // GDK sends surplus button down events
1463 // before a double click event. We
1464 // need to filter these out.
1465 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1467 GdkEvent
*peek_event
= gdk_event_peek();
1470 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1471 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1473 gdk_event_free( peek_event
);
1478 gdk_event_free( peek_event
);
1483 wxEventType event_type
= wxEVT_NULL
;
1485 // GdkDisplay is a GTK+ 2.2.0 thing
1486 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1487 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1488 !gtk_check_version(2,2,0) &&
1489 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1491 // Reset GDK internal timestamp variables in order to disable GDK
1492 // triple click events. GDK will then next time believe no button has
1493 // been clicked just before, and send a normal button click event.
1494 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1495 display
->button_click_time
[1] = 0;
1496 display
->button_click_time
[0] = 0;
1500 if (gdk_event
->button
== 1)
1502 // note that GDK generates triple click events which are not supported
1503 // by wxWidgets but still have to be passed to the app as otherwise
1504 // clicks would simply go missing
1505 switch (gdk_event
->type
)
1507 // we shouldn't get triple clicks at all for GTK2 because we
1508 // suppress them artificially using the code above but we still
1509 // should map them to something for GTK1 and not just ignore them
1510 // as this would lose clicks
1511 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1512 case GDK_BUTTON_PRESS
:
1513 event_type
= wxEVT_LEFT_DOWN
;
1516 case GDK_2BUTTON_PRESS
:
1517 event_type
= wxEVT_LEFT_DCLICK
;
1521 // just to silence gcc warnings
1525 else if (gdk_event
->button
== 2)
1527 switch (gdk_event
->type
)
1529 case GDK_3BUTTON_PRESS
:
1530 case GDK_BUTTON_PRESS
:
1531 event_type
= wxEVT_MIDDLE_DOWN
;
1534 case GDK_2BUTTON_PRESS
:
1535 event_type
= wxEVT_MIDDLE_DCLICK
;
1542 else if (gdk_event
->button
== 3)
1544 switch (gdk_event
->type
)
1546 case GDK_3BUTTON_PRESS
:
1547 case GDK_BUTTON_PRESS
:
1548 event_type
= wxEVT_RIGHT_DOWN
;
1551 case GDK_2BUTTON_PRESS
:
1552 event_type
= wxEVT_RIGHT_DCLICK
;
1559 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1561 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1563 event_type
= wxEVT_MOUSEWHEEL
;
1567 if ( event_type
== wxEVT_NULL
)
1569 // unknown mouse button or click type
1573 wxMouseEvent
event( event_type
);
1574 InitMouseEvent( win
, event
, gdk_event
);
1576 AdjustEventButtonState(event
);
1578 // wxListBox actually gets mouse events from the item, so we need to give it
1579 // a chance to correct this
1580 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1582 // find the correct window to send the event to: it may be a different one
1583 // from the one which got it at GTK+ level because some controls don't have
1584 // their own X window and thus cannot get any events.
1585 if ( !g_captureWindow
)
1586 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1588 // reset the event object and id in case win changed.
1589 event
.SetEventObject( win
);
1590 event
.SetId( win
->GetId() );
1592 if (win
->GetEventHandler()->ProcessEvent( event
))
1594 g_signal_stop_emission_by_name (widget
, "button_press_event");
1598 if (event_type
== wxEVT_RIGHT_DOWN
)
1600 // generate a "context menu" event: this is similar to right mouse
1601 // click under many GUIs except that it is generated differently
1602 // (right up under MSW, ctrl-click under Mac, right down here) and
1604 // (a) it's a command event and so is propagated to the parent
1605 // (b) under some ports it can be generated from kbd too
1606 // (c) it uses screen coords (because of (a))
1607 wxContextMenuEvent
evtCtx(
1610 win
->ClientToScreen(event
.GetPosition()));
1611 evtCtx
.SetEventObject(win
);
1612 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1619 //-----------------------------------------------------------------------------
1620 // "button_release_event"
1621 //-----------------------------------------------------------------------------
1625 gtk_window_button_release_callback( GtkWidget
*widget
,
1626 GdkEventButton
*gdk_event
,
1632 wxapp_install_idle_handler();
1634 if (!win
->m_hasVMT
) return FALSE
;
1635 if (g_blockEventsOnDrag
) return FALSE
;
1636 if (g_blockEventsOnScroll
) return FALSE
;
1638 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1640 wxEventType event_type
= wxEVT_NULL
;
1642 switch (gdk_event
->button
)
1645 event_type
= wxEVT_LEFT_UP
;
1649 event_type
= wxEVT_MIDDLE_UP
;
1653 event_type
= wxEVT_RIGHT_UP
;
1657 // unknwon button, don't process
1661 wxMouseEvent
event( event_type
);
1662 InitMouseEvent( win
, event
, gdk_event
);
1664 AdjustEventButtonState(event
);
1666 // same wxListBox hack as above
1667 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1669 if ( !g_captureWindow
)
1670 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1672 // reset the event object and id in case win changed.
1673 event
.SetEventObject( win
);
1674 event
.SetId( win
->GetId() );
1676 if (win
->GetEventHandler()->ProcessEvent( event
))
1678 g_signal_stop_emission_by_name (widget
, "button_release_event");
1686 //-----------------------------------------------------------------------------
1687 // "motion_notify_event"
1688 //-----------------------------------------------------------------------------
1692 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1693 GdkEventMotion
*gdk_event
,
1699 wxapp_install_idle_handler();
1701 if (!win
->m_hasVMT
) return FALSE
;
1702 if (g_blockEventsOnDrag
) return FALSE
;
1703 if (g_blockEventsOnScroll
) return FALSE
;
1705 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1707 if (gdk_event
->is_hint
)
1711 GdkModifierType state
;
1712 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1718 printf( "OnMotion from " );
1719 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1720 printf( win->GetClassInfo()->GetClassName() );
1724 wxMouseEvent
event( wxEVT_MOTION
);
1725 InitMouseEvent(win
, event
, gdk_event
);
1727 if ( g_captureWindow
)
1729 // synthetize a mouse enter or leave event if needed
1730 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1731 // This seems to be necessary and actually been added to
1732 // GDK itself in version 2.0.X
1735 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1736 if ( hasMouse
!= g_captureWindowHasMouse
)
1738 // the mouse changed window
1739 g_captureWindowHasMouse
= hasMouse
;
1741 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1742 : wxEVT_LEAVE_WINDOW
);
1743 InitMouseEvent(win
, eventM
, gdk_event
);
1744 eventM
.SetEventObject(win
);
1745 win
->GetEventHandler()->ProcessEvent(eventM
);
1750 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1752 // reset the event object and id in case win changed.
1753 event
.SetEventObject( win
);
1754 event
.SetId( win
->GetId() );
1757 if ( !g_captureWindow
)
1759 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1760 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1762 // Rewrite cursor handling here (away from idle).
1766 if (win
->GetEventHandler()->ProcessEvent( event
))
1768 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1776 //-----------------------------------------------------------------------------
1777 // "scroll_event", (mouse wheel event)
1778 //-----------------------------------------------------------------------------
1782 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1787 wxapp_install_idle_handler();
1789 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1790 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1795 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1796 // Can't use InitMouse macro because scroll events don't have button
1797 event
.SetTimestamp( gdk_event
->time
);
1798 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1799 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1800 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1801 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1802 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1803 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1804 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1805 event
.m_linesPerAction
= 3;
1806 event
.m_wheelDelta
= 120;
1807 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1808 event
.m_wheelRotation
= 120;
1810 event
.m_wheelRotation
= -120;
1812 wxPoint pt
= win
->GetClientAreaOrigin();
1813 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1814 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1816 event
.SetEventObject( win
);
1817 event
.SetId( win
->GetId() );
1818 event
.SetTimestamp( gdk_event
->time
);
1820 return win
->GetEventHandler()->ProcessEvent(event
);
1824 //-----------------------------------------------------------------------------
1826 //-----------------------------------------------------------------------------
1828 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1830 wxContextMenuEvent
event(
1834 event
.SetEventObject(win
);
1835 return win
->GetEventHandler()->ProcessEvent(event
);
1839 //-----------------------------------------------------------------------------
1841 //-----------------------------------------------------------------------------
1843 // send the wxChildFocusEvent and wxFocusEvent, common code of
1844 // gtk_window_focus_in_callback() and SetFocus()
1845 static bool DoSendFocusEvents(wxWindow
*win
)
1847 // Notify the parent keeping track of focus for the kbd navigation
1848 // purposes that we got it.
1849 wxChildFocusEvent
eventChildFocus(win
);
1850 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1852 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1853 eventFocus
.SetEventObject(win
);
1855 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1860 gtk_window_focus_in_callback( GtkWidget
*widget
,
1861 GdkEventFocus
*WXUNUSED(event
),
1867 wxapp_install_idle_handler();
1870 gtk_im_context_focus_in(win
->m_imData
->context
);
1873 g_focusWindow
= win
;
1875 wxLogTrace(TRACE_FOCUS
,
1876 _T("%s: focus in"), win
->GetName().c_str());
1880 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1884 // caret needs to be informed about focus change
1885 wxCaret
*caret
= win
->GetCaret();
1888 caret
->OnSetFocus();
1890 #endif // wxUSE_CARET
1892 gboolean ret
= FALSE
;
1894 // does the window itself think that it has the focus?
1895 if ( !win
->m_hasFocus
)
1897 // not yet, notify it
1898 win
->m_hasFocus
= true;
1900 (void)DoSendFocusEvents(win
);
1905 // Disable default focus handling for custom windows
1906 // since the default GTK+ handler issues a repaint
1907 if (win
->m_wxwindow
)
1914 //-----------------------------------------------------------------------------
1915 // "focus_out_event"
1916 //-----------------------------------------------------------------------------
1920 gtk_window_focus_out_callback( GtkWidget
*widget
,
1921 GdkEventFocus
*gdk_event
,
1927 wxapp_install_idle_handler();
1930 gtk_im_context_focus_out(win
->m_imData
->context
);
1932 wxLogTrace( TRACE_FOCUS
,
1933 _T("%s: focus out"), win
->GetName().c_str() );
1936 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1940 g_focusWindow
= (wxWindowGTK
*)NULL
;
1948 // caret needs to be informed about focus change
1949 wxCaret
*caret
= win
->GetCaret();
1952 caret
->OnKillFocus();
1954 #endif // wxUSE_CARET
1956 gboolean ret
= FALSE
;
1958 // don't send the window a kill focus event if it thinks that it doesn't
1959 // have focus already
1960 if ( win
->m_hasFocus
)
1962 win
->m_hasFocus
= false;
1964 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1965 event
.SetEventObject( win
);
1967 (void)win
->GetEventHandler()->ProcessEvent( event
);
1972 // Disable default focus handling for custom windows
1973 // since the default GTK+ handler issues a repaint
1974 if (win
->m_wxwindow
)
1981 //-----------------------------------------------------------------------------
1982 // "enter_notify_event"
1983 //-----------------------------------------------------------------------------
1987 gtk_window_enter_callback( GtkWidget
*widget
,
1988 GdkEventCrossing
*gdk_event
,
1994 wxapp_install_idle_handler();
1996 if (!win
->m_hasVMT
) return FALSE
;
1997 if (g_blockEventsOnDrag
) return FALSE
;
1999 // Event was emitted after a grab
2000 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2002 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2006 GdkModifierType state
= (GdkModifierType
)0;
2008 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2010 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2011 InitMouseEvent(win
, event
, gdk_event
);
2012 wxPoint pt
= win
->GetClientAreaOrigin();
2013 event
.m_x
= x
+ pt
.x
;
2014 event
.m_y
= y
+ pt
.y
;
2016 if ( !g_captureWindow
)
2018 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2019 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2021 // Rewrite cursor handling here (away from idle).
2025 if (win
->GetEventHandler()->ProcessEvent( event
))
2027 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2035 //-----------------------------------------------------------------------------
2036 // "leave_notify_event"
2037 //-----------------------------------------------------------------------------
2041 gtk_window_leave_callback( GtkWidget
*widget
,
2042 GdkEventCrossing
*gdk_event
,
2048 wxapp_install_idle_handler();
2050 if (!win
->m_hasVMT
) return FALSE
;
2051 if (g_blockEventsOnDrag
) return FALSE
;
2053 // Event was emitted after an ungrab
2054 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2056 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2058 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2059 event
.SetTimestamp( gdk_event
->time
);
2060 event
.SetEventObject( win
);
2064 GdkModifierType state
= (GdkModifierType
)0;
2066 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2068 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2069 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2070 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2071 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2072 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2073 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2074 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2076 wxPoint pt
= win
->GetClientAreaOrigin();
2077 event
.m_x
= x
+ pt
.x
;
2078 event
.m_y
= y
+ pt
.y
;
2080 if (win
->GetEventHandler()->ProcessEvent( event
))
2082 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2090 //-----------------------------------------------------------------------------
2091 // "value_changed" from scrollbar
2092 //-----------------------------------------------------------------------------
2096 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
2098 wxEventType eventType
= win
->GetScrollEventType(range
);
2099 if (eventType
!= wxEVT_NULL
)
2101 // Convert scroll event type to scrollwin event type
2102 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
2103 const int orient
= range
== win
->m_scrollBar
[0] ? wxHORIZONTAL
: wxVERTICAL
;
2104 const int i
= orient
== wxVERTICAL
;
2105 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
2106 event
.SetEventObject(win
);
2107 win
->m_blockValueChanged
[i
] = true;
2108 win
->GetEventHandler()->ProcessEvent(event
);
2109 win
->m_blockValueChanged
[i
] = false;
2114 //-----------------------------------------------------------------------------
2115 // "button_press_event" from scrollbar
2116 //-----------------------------------------------------------------------------
2120 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
2125 wxapp_install_idle_handler();
2127 g_blockEventsOnScroll
= true;
2128 win
->m_mouseButtonDown
= true;
2134 //-----------------------------------------------------------------------------
2135 // "event_after" from scrollbar
2136 //-----------------------------------------------------------------------------
2140 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
2142 if (event
->type
== GDK_BUTTON_RELEASE
)
2144 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
2146 const int orient
= range
== win
->m_scrollBar
[0] ? wxHORIZONTAL
: wxVERTICAL
;
2147 wxScrollWinEvent
event(wxEVT_SCROLLWIN_THUMBRELEASE
, win
->GetScrollPos(orient
), orient
);
2148 event
.SetEventObject(win
);
2149 win
->GetEventHandler()->ProcessEvent(event
);
2154 //-----------------------------------------------------------------------------
2155 // "button_release_event" from scrollbar
2156 //-----------------------------------------------------------------------------
2160 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
2164 g_blockEventsOnScroll
= false;
2165 win
->m_mouseButtonDown
= false;
2166 // If thumb tracking
2167 if (win
->m_isScrolling
)
2169 win
->m_isScrolling
= false;
2170 // Hook up handler to send thumb release event after this emission is finished.
2171 // To allow setting scroll position from event handler, sending event must
2172 // be deferred until after the GtkRange handler for this signal has run
2173 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
2180 // ----------------------------------------------------------------------------
2181 // this wxWindowBase function is implemented here (in platform-specific file)
2182 // because it is static and so couldn't be made virtual
2183 // ----------------------------------------------------------------------------
2185 wxWindow
*wxWindowBase::DoFindFocus()
2187 // the cast is necessary when we compile in wxUniversal mode
2188 return (wxWindow
*)g_focusWindow
;
2191 //-----------------------------------------------------------------------------
2192 // "realize" from m_widget
2193 //-----------------------------------------------------------------------------
2195 /* We cannot set colours and fonts before the widget has
2196 been realized, so we do this directly after realization. */
2200 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2205 wxapp_install_idle_handler();
2209 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2210 gtk_im_context_set_client_window( win
->m_imData
->context
,
2211 pizza
->bin_window
);
2214 wxWindowCreateEvent
event( win
);
2215 event
.SetEventObject( win
);
2216 win
->GetEventHandler()->ProcessEvent( event
);
2220 //-----------------------------------------------------------------------------
2222 //-----------------------------------------------------------------------------
2226 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2227 GtkAllocation
*WXUNUSED(alloc
),
2231 wxapp_install_idle_handler();
2233 int client_width
= 0;
2234 int client_height
= 0;
2235 win
->GetClientSize( &client_width
, &client_height
);
2236 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2239 win
->m_oldClientWidth
= client_width
;
2240 win
->m_oldClientHeight
= client_height
;
2242 if (!win
->m_nativeSizeEvent
)
2244 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2245 event
.SetEventObject( win
);
2246 win
->GetEventHandler()->ProcessEvent( event
);
2253 #define WXUNUSED_UNLESS_XIM(param) param
2255 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2258 /* Resize XIM window */
2262 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2263 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2264 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2267 wxapp_install_idle_handler();
2273 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2277 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2278 win
->m_icattr
->preedit_area
.width
= width
;
2279 win
->m_icattr
->preedit_area
.height
= height
;
2280 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2286 //-----------------------------------------------------------------------------
2287 // "realize" from m_wxwindow
2288 //-----------------------------------------------------------------------------
2290 /* Initialize XIM support */
2294 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2295 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2298 wxapp_install_idle_handler();
2301 if (win
->m_ic
) return;
2302 if (!widget
) return;
2303 if (!gdk_im_ready()) return;
2305 win
->m_icattr
= gdk_ic_attr_new();
2306 if (!win
->m_icattr
) return;
2310 GdkColormap
*colormap
;
2311 GdkICAttr
*attr
= win
->m_icattr
;
2312 unsigned attrmask
= GDK_IC_ALL_REQ
;
2314 GdkIMStyle supported_style
= (GdkIMStyle
)
2315 (GDK_IM_PREEDIT_NONE
|
2316 GDK_IM_PREEDIT_NOTHING
|
2317 GDK_IM_PREEDIT_POSITION
|
2318 GDK_IM_STATUS_NONE
|
2319 GDK_IM_STATUS_NOTHING
);
2321 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2322 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2324 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2325 attr
->client_window
= widget
->window
;
2327 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2328 gtk_widget_get_default_colormap ())
2330 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2331 attr
->preedit_colormap
= colormap
;
2334 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2335 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2336 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2337 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2339 switch (style
& GDK_IM_PREEDIT_MASK
)
2341 case GDK_IM_PREEDIT_POSITION
:
2342 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2344 g_warning ("over-the-spot style requires fontset");
2348 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2350 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2351 attr
->spot_location
.x
= 0;
2352 attr
->spot_location
.y
= height
;
2353 attr
->preedit_area
.x
= 0;
2354 attr
->preedit_area
.y
= 0;
2355 attr
->preedit_area
.width
= width
;
2356 attr
->preedit_area
.height
= height
;
2357 attr
->preedit_fontset
= widget
->style
->font
;
2362 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2364 if (win
->m_ic
== NULL
)
2365 g_warning ("Can't create input context.");
2368 mask
= gdk_window_get_events (widget
->window
);
2369 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2370 gdk_window_set_events (widget
->window
, mask
);
2372 if (GTK_WIDGET_HAS_FOCUS(widget
))
2373 gdk_im_begin (win
->m_ic
, widget
->window
);
2379 //-----------------------------------------------------------------------------
2380 // InsertChild for wxWindowGTK.
2381 //-----------------------------------------------------------------------------
2383 /* Callback for wxWindowGTK. This very strange beast has to be used because
2384 * C++ has no virtual methods in a constructor. We have to emulate a
2385 * virtual function here as wxNotebook requires a different way to insert
2386 * a child in it. I had opted for creating a wxNotebookPage window class
2387 * which would have made this superfluous (such in the MDI window system),
2388 * but no-one was listening to me... */
2390 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2392 /* the window might have been scrolled already, do we
2393 have to adapt the position */
2394 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2395 child
->m_x
+= pizza
->xoffset
;
2396 child
->m_y
+= pizza
->yoffset
;
2398 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2399 GTK_WIDGET(child
->m_widget
),
2406 //-----------------------------------------------------------------------------
2408 //-----------------------------------------------------------------------------
2410 wxWindow
*wxGetActiveWindow()
2412 return wxWindow::FindFocus();
2416 wxMouseState
wxGetMouseState()
2422 GdkModifierType mask
;
2424 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2428 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2429 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2430 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2432 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2433 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2434 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2435 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2440 //-----------------------------------------------------------------------------
2442 //-----------------------------------------------------------------------------
2444 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2446 #ifdef __WXUNIVERSAL__
2447 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2449 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2450 #endif // __WXUNIVERSAL__/__WXGTK__
2452 void wxWindowGTK::Init()
2455 m_widget
= (GtkWidget
*) NULL
;
2456 m_wxwindow
= (GtkWidget
*) NULL
;
2457 m_focusWidget
= (GtkWidget
*) NULL
;
2467 m_needParent
= true;
2468 m_isBeingDeleted
= false;
2471 m_nativeSizeEvent
= false;
2473 m_hasScrolling
= false;
2474 m_isScrolling
= false;
2475 m_mouseButtonDown
= false;
2476 m_blockScrollEvent
= false;
2479 m_scrollBar
[1] = NULL
;
2482 m_blockValueChanged
[0] =
2483 m_blockValueChanged
[1] = false;
2486 m_oldClientHeight
= 0;
2490 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2492 m_acceptsFocus
= false;
2495 m_clipPaintRegion
= false;
2497 m_needsStyleChange
= false;
2499 m_cursor
= *wxSTANDARD_CURSOR
;
2502 m_dirtyTabOrder
= false;
2505 wxWindowGTK::wxWindowGTK()
2510 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2515 const wxString
&name
)
2519 Create( parent
, id
, pos
, size
, style
, name
);
2522 bool wxWindowGTK::Create( wxWindow
*parent
,
2527 const wxString
&name
)
2529 if (!PreCreation( parent
, pos
, size
) ||
2530 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2532 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2536 m_insertCallback
= wxInsertChildInWindow
;
2538 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2539 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2541 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2543 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2544 scroll_class
->scrollbar_spacing
= 0;
2546 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2548 m_scrollBar
[0] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2549 m_scrollBar
[1] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2551 m_wxwindow
= gtk_pizza_new();
2553 #ifndef __WXUNIVERSAL__
2554 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2556 if (HasFlag(wxRAISED_BORDER
))
2558 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2560 else if (HasFlag(wxSUNKEN_BORDER
))
2562 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2564 else if (HasFlag(wxSIMPLE_BORDER
))
2566 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2570 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2572 #endif // __WXUNIVERSAL__
2574 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2576 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2577 m_acceptsFocus
= true;
2579 // these handlers block mouse events to any window during scrolling such as
2580 // motion events and prevent GTK and wxWidgets from fighting over where the
2582 g_signal_connect(m_scrollBar
[0], "button_press_event",
2583 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2584 g_signal_connect(m_scrollBar
[1], "button_press_event",
2585 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2586 g_signal_connect(m_scrollBar
[0], "button_release_event",
2587 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2588 g_signal_connect(m_scrollBar
[1], "button_release_event",
2589 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2591 handler_id
= g_signal_connect(
2592 m_scrollBar
[0], "event_after", G_CALLBACK(gtk_scrollbar_event_after
), this);
2593 g_signal_handler_block(m_scrollBar
[0], handler_id
);
2594 handler_id
= g_signal_connect(
2595 m_scrollBar
[1], "event_after", G_CALLBACK(gtk_scrollbar_event_after
), this);
2596 g_signal_handler_block(m_scrollBar
[1], handler_id
);
2598 // these handlers get notified when scrollbar slider moves
2600 g_signal_connect(m_scrollBar
[0], "value_changed",
2601 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2602 g_signal_connect(m_scrollBar
[1], "value_changed",
2603 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2605 gtk_widget_show( m_wxwindow
);
2608 m_parent
->DoAddChild( this );
2610 m_focusWidget
= m_wxwindow
;
2617 wxWindowGTK::~wxWindowGTK()
2621 if (g_focusWindow
== this)
2622 g_focusWindow
= NULL
;
2624 if ( g_delayedFocus
== this )
2625 g_delayedFocus
= NULL
;
2627 m_isBeingDeleted
= true;
2630 // destroy children before destroying this window itself
2633 // unhook focus handlers to prevent stray events being
2634 // propagated to this (soon to be) dead object
2635 if (m_focusWidget
!= NULL
)
2637 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2638 (gpointer
) gtk_window_focus_in_callback
,
2640 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2641 (gpointer
) gtk_window_focus_out_callback
,
2650 gdk_ic_destroy (m_ic
);
2652 gdk_ic_attr_destroy (m_icattr
);
2655 // delete before the widgets to avoid a crash on solaris
2660 gtk_widget_destroy( m_wxwindow
);
2661 m_wxwindow
= (GtkWidget
*) NULL
;
2666 gtk_widget_destroy( m_widget
);
2667 m_widget
= (GtkWidget
*) NULL
;
2671 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2673 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2675 // Use either the given size, or the default if -1 is given.
2676 // See wxWindowBase for these functions.
2677 m_width
= WidthDefault(size
.x
) ;
2678 m_height
= HeightDefault(size
.y
);
2686 void wxWindowGTK::PostCreation()
2688 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2694 // these get reported to wxWidgets -> wxPaintEvent
2696 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2698 g_signal_connect (m_wxwindow
, "expose_event",
2699 G_CALLBACK (gtk_window_expose_callback
), this);
2701 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2704 // Create input method handler
2705 m_imData
= new wxGtkIMData
;
2707 // Cannot handle drawing preedited text yet
2708 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2710 g_signal_connect (m_imData
->context
, "commit",
2711 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2713 // these are called when the "sunken" or "raised" borders are drawn
2714 g_signal_connect (m_widget
, "expose_event",
2715 G_CALLBACK (gtk_window_own_expose_callback
), this);
2720 if (!GTK_IS_WINDOW(m_widget
))
2722 if (m_focusWidget
== NULL
)
2723 m_focusWidget
= m_widget
;
2727 g_signal_connect (m_focusWidget
, "focus_in_event",
2728 G_CALLBACK (gtk_window_focus_in_callback
), this);
2729 g_signal_connect (m_focusWidget
, "focus_out_event",
2730 G_CALLBACK (gtk_window_focus_out_callback
), this);
2734 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2735 G_CALLBACK (gtk_window_focus_in_callback
), this);
2736 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2737 G_CALLBACK (gtk_window_focus_out_callback
), this);
2741 // connect to the various key and mouse handlers
2743 GtkWidget
*connect_widget
= GetConnectWidget();
2745 ConnectWidget( connect_widget
);
2747 /* We cannot set colours, fonts and cursors before the widget has
2748 been realized, so we do this directly after realization */
2749 g_signal_connect (connect_widget
, "realize",
2750 G_CALLBACK (gtk_window_realized_callback
), this);
2754 // Catch native resize events
2755 g_signal_connect (m_wxwindow
, "size_allocate",
2756 G_CALLBACK (gtk_window_size_callback
), this);
2758 // Initialize XIM support
2759 g_signal_connect (m_wxwindow
, "realize",
2760 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2762 // And resize XIM window
2763 g_signal_connect (m_wxwindow
, "size_allocate",
2764 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2767 if (GTK_IS_COMBO(m_widget
))
2769 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2771 g_signal_connect (gcombo
->entry
, "size_request",
2772 G_CALLBACK (wxgtk_combo_size_request_callback
),
2775 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2776 else if (GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2778 // If we connect to the "size_request" signal of a GtkFileChooserButton
2779 // then that control won't be sized properly when placed inside sizers
2780 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2781 // FIXME: what should be done here ?
2786 // This is needed if we want to add our windows into native
2787 // GTK controls, such as the toolbar. With this callback, the
2788 // toolbar gets to know the correct size (the one set by the
2789 // programmer). Sadly, it misbehaves for wxComboBox.
2790 g_signal_connect (m_widget
, "size_request",
2791 G_CALLBACK (wxgtk_window_size_request_callback
),
2795 InheritAttributes();
2799 // unless the window was created initially hidden (i.e. Hide() had been
2800 // called before Create()), we should show it at GTK+ level as well
2802 gtk_widget_show( m_widget
);
2805 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2807 g_signal_connect (widget
, "key_press_event",
2808 G_CALLBACK (gtk_window_key_press_callback
), this);
2809 g_signal_connect (widget
, "key_release_event",
2810 G_CALLBACK (gtk_window_key_release_callback
), this);
2811 g_signal_connect (widget
, "button_press_event",
2812 G_CALLBACK (gtk_window_button_press_callback
), this);
2813 g_signal_connect (widget
, "button_release_event",
2814 G_CALLBACK (gtk_window_button_release_callback
), this);
2815 g_signal_connect (widget
, "motion_notify_event",
2816 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2817 g_signal_connect (widget
, "scroll_event",
2818 G_CALLBACK (window_scroll_event
), this);
2819 g_signal_connect (widget
, "popup_menu",
2820 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2821 g_signal_connect (widget
, "enter_notify_event",
2822 G_CALLBACK (gtk_window_enter_callback
), this);
2823 g_signal_connect (widget
, "leave_notify_event",
2824 G_CALLBACK (gtk_window_leave_callback
), this);
2827 bool wxWindowGTK::Destroy()
2829 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2833 return wxWindowBase::Destroy();
2836 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2838 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2841 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2843 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2844 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2847 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2850 if (m_resizing
) return; /* I don't like recursions */
2853 int currentX
, currentY
;
2854 GetPosition(¤tX
, ¤tY
);
2855 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2857 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2859 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2861 // calculate the best size if we should auto size the window
2862 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2863 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2865 const wxSize sizeBest
= GetBestSize();
2866 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2868 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2869 height
= sizeBest
.y
;
2877 int minWidth
= GetMinWidth(),
2878 minHeight
= GetMinHeight(),
2879 maxWidth
= GetMaxWidth(),
2880 maxHeight
= GetMaxHeight();
2882 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2883 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2884 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2885 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2887 #if wxUSE_TOOLBAR_NATIVE
2888 if (wxDynamicCast(GetParent(), wxToolBar
))
2890 // don't take the x,y values, they're wrong because toolbar sets them
2891 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2892 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2893 if (GTK_WIDGET_VISIBLE (widget
))
2894 gtk_widget_queue_resize (widget
);
2898 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2900 // don't set the size for children of wxNotebook, just take the values.
2908 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2909 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2911 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2912 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2916 m_x
= x
+ pizza
->xoffset
;
2917 m_y
= y
+ pizza
->yoffset
;
2920 int left_border
= 0;
2921 int right_border
= 0;
2923 int bottom_border
= 0;
2925 /* the default button has a border around it */
2926 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2928 GtkBorder
*default_border
= NULL
;
2929 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2932 left_border
+= default_border
->left
;
2933 right_border
+= default_border
->right
;
2934 top_border
+= default_border
->top
;
2935 bottom_border
+= default_border
->bottom
;
2936 g_free( default_border
);
2940 DoMoveWindow( m_x
-top_border
,
2942 m_width
+left_border
+right_border
,
2943 m_height
+top_border
+bottom_border
);
2948 /* Sometimes the client area changes size without the
2949 whole windows's size changing, but if the whole
2950 windows's size doesn't change, no wxSizeEvent will
2951 normally be sent. Here we add an extra test if
2952 the client test has been changed and this will
2954 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2958 wxPrintf( "OnSize sent from " );
2959 if (GetClassInfo() && GetClassInfo()->GetClassName())
2960 wxPrintf( GetClassInfo()->GetClassName() );
2961 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2964 if (!m_nativeSizeEvent
)
2966 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2967 event
.SetEventObject( this );
2968 GetEventHandler()->ProcessEvent( event
);
2974 void wxWindowGTK::OnInternalIdle()
2976 if ( m_dirtyTabOrder
)
2978 m_dirtyTabOrder
= false;
2982 // Update style if the window was not yet realized
2983 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2984 if (m_needsStyleChange
)
2986 SetBackgroundStyle(GetBackgroundStyle());
2987 m_needsStyleChange
= false;
2990 // Update invalidated regions.
2993 wxCursor cursor
= m_cursor
;
2994 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2998 /* I now set the cursor anew in every OnInternalIdle call
2999 as setting the cursor in a parent window also effects the
3000 windows above so that checking for the current cursor is
3005 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3007 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3009 if (!g_globalCursor
.Ok())
3010 cursor
= *wxSTANDARD_CURSOR
;
3012 window
= m_widget
->window
;
3013 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3014 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3020 GdkWindow
*window
= m_widget
->window
;
3021 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3022 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3027 if (wxUpdateUIEvent::CanUpdate(this))
3028 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3031 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3033 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3035 if (width
) (*width
) = m_width
;
3036 if (height
) (*height
) = m_height
;
3039 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3041 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3050 GetScrollbarWidth(m_widget
, dw
, dh
);
3053 #ifndef __WXUNIVERSAL__
3054 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3056 // shadow border size is 2
3060 if (HasFlag(wxSIMPLE_BORDER
))
3062 // simple border size is 1
3066 #endif // __WXUNIVERSAL__
3072 SetSize(width
, height
);
3075 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3077 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3089 GetScrollbarWidth(m_widget
, dw
, dh
);
3092 #ifndef __WXUNIVERSAL__
3093 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3095 // shadow border size is 2
3099 if (HasFlag(wxSIMPLE_BORDER
))
3101 // simple border size is 1
3105 #endif // __WXUNIVERSAL__
3111 if (width
) *width
= w
;
3112 if (height
) *height
= h
;
3115 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3117 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3121 if (m_parent
&& m_parent
->m_wxwindow
)
3123 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3124 dx
= pizza
->xoffset
;
3125 dy
= pizza
->yoffset
;
3128 if (x
) (*x
) = m_x
- dx
;
3129 if (y
) (*y
) = m_y
- dy
;
3132 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3134 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3136 if (!m_widget
->window
) return;
3138 GdkWindow
*source
= (GdkWindow
*) NULL
;
3140 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3142 source
= m_widget
->window
;
3146 gdk_window_get_origin( source
, &org_x
, &org_y
);
3150 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3152 org_x
+= m_widget
->allocation
.x
;
3153 org_y
+= m_widget
->allocation
.y
;
3161 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3163 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3165 if (!m_widget
->window
) return;
3167 GdkWindow
*source
= (GdkWindow
*) NULL
;
3169 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3171 source
= m_widget
->window
;
3175 gdk_window_get_origin( source
, &org_x
, &org_y
);
3179 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3181 org_x
+= m_widget
->allocation
.x
;
3182 org_y
+= m_widget
->allocation
.y
;
3190 bool wxWindowGTK::Show( bool show
)
3192 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3194 if (!wxWindowBase::Show(show
))
3201 gtk_widget_show( m_widget
);
3203 gtk_widget_hide( m_widget
);
3205 wxShowEvent
eventShow(GetId(), show
);
3206 eventShow
.SetEventObject(this);
3208 GetEventHandler()->ProcessEvent(eventShow
);
3213 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3215 win
->OnParentEnable(enable
);
3217 // Recurse, so that children have the opportunity to Do The Right Thing
3218 // and reset colours that have been messed up by a parent's (really ancestor's)
3220 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3222 node
= node
->GetNext() )
3224 wxWindow
*child
= node
->GetData();
3225 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3226 wxWindowNotifyEnable(child
, enable
);
3230 bool wxWindowGTK::Enable( bool enable
)
3232 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3234 if (!wxWindowBase::Enable(enable
))
3240 gtk_widget_set_sensitive( m_widget
, enable
);
3242 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3244 wxWindowNotifyEnable(this, enable
);
3249 int wxWindowGTK::GetCharHeight() const
3251 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3253 wxFont font
= GetFont();
3254 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3256 PangoContext
*context
= NULL
;
3258 context
= gtk_widget_get_pango_context( m_widget
);
3263 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3264 PangoLayout
*layout
= pango_layout_new(context
);
3265 pango_layout_set_font_description(layout
, desc
);
3266 pango_layout_set_text(layout
, "H", 1);
3267 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3269 PangoRectangle rect
;
3270 pango_layout_line_get_extents(line
, NULL
, &rect
);
3272 g_object_unref (layout
);
3274 return (int) PANGO_PIXELS(rect
.height
);
3277 int wxWindowGTK::GetCharWidth() const
3279 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3281 wxFont font
= GetFont();
3282 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3284 PangoContext
*context
= NULL
;
3286 context
= gtk_widget_get_pango_context( m_widget
);
3291 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3292 PangoLayout
*layout
= pango_layout_new(context
);
3293 pango_layout_set_font_description(layout
, desc
);
3294 pango_layout_set_text(layout
, "g", 1);
3295 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3297 PangoRectangle rect
;
3298 pango_layout_line_get_extents(line
, NULL
, &rect
);
3300 g_object_unref (layout
);
3302 return (int) PANGO_PIXELS(rect
.width
);
3305 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3309 int *externalLeading
,
3310 const wxFont
*theFont
) const
3312 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3314 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3323 PangoContext
*context
= NULL
;
3325 context
= gtk_widget_get_pango_context( m_widget
);
3334 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3335 PangoLayout
*layout
= pango_layout_new(context
);
3336 pango_layout_set_font_description(layout
, desc
);
3338 const wxCharBuffer data
= wxGTK_CONV( string
);
3340 pango_layout_set_text(layout
, data
, strlen(data
));
3343 PangoRectangle rect
;
3344 pango_layout_get_extents(layout
, NULL
, &rect
);
3346 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3347 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3350 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3351 int baseline
= pango_layout_iter_get_baseline(iter
);
3352 pango_layout_iter_free(iter
);
3353 *descent
= *y
- PANGO_PIXELS(baseline
);
3355 if (externalLeading
) (*externalLeading
) = 0; // ??
3357 g_object_unref (layout
);
3360 void wxWindowGTK::SetFocus()
3362 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3365 // don't do anything if we already have focus
3371 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3373 gtk_widget_grab_focus (m_wxwindow
);
3378 if (GTK_IS_CONTAINER(m_widget
))
3380 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3383 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3386 if (!GTK_WIDGET_REALIZED(m_widget
))
3388 // we can't set the focus to the widget now so we remember that
3389 // it should be focused and will do it later, during the idle
3390 // time, as soon as we can
3391 wxLogTrace(TRACE_FOCUS
,
3392 _T("Delaying setting focus to %s(%s)"),
3393 GetClassInfo()->GetClassName(), GetLabel().c_str());
3395 g_delayedFocus
= this;
3399 wxLogTrace(TRACE_FOCUS
,
3400 _T("Setting focus to %s(%s)"),
3401 GetClassInfo()->GetClassName(), GetLabel().c_str());
3403 gtk_widget_grab_focus (m_widget
);
3408 wxLogTrace(TRACE_FOCUS
,
3409 _T("Can't set focus to %s(%s)"),
3410 GetClassInfo()->GetClassName(), GetLabel().c_str());
3415 bool wxWindowGTK::AcceptsFocus() const
3417 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3420 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3422 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3424 wxWindowGTK
*oldParent
= m_parent
,
3425 *newParent
= (wxWindowGTK
*)newParentBase
;
3427 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3429 if ( !wxWindowBase::Reparent(newParent
) )
3432 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3434 /* prevent GTK from deleting the widget arbitrarily */
3435 gtk_widget_ref( m_widget
);
3439 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3442 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3446 /* insert GTK representation */
3447 (*(newParent
->m_insertCallback
))(newParent
, this);
3450 /* reverse: prevent GTK from deleting the widget arbitrarily */
3451 gtk_widget_unref( m_widget
);
3456 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3458 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3460 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3462 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3467 /* insert GTK representation */
3468 (*m_insertCallback
)(this, child
);
3471 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3473 wxWindowBase::AddChild(child
);
3474 m_dirtyTabOrder
= true;
3476 wxapp_install_idle_handler();
3479 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3481 wxWindowBase::RemoveChild(child
);
3482 m_dirtyTabOrder
= true;
3484 wxapp_install_idle_handler();
3487 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3489 wxWindowBase::DoMoveInTabOrder(win
, move
);
3490 m_dirtyTabOrder
= true;
3492 wxapp_install_idle_handler();
3495 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3497 // none needed by default
3501 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3503 // nothing to do by default since none is needed
3506 void wxWindowGTK::RealizeTabOrder()
3510 if ( !m_children
.empty() )
3512 // we don't only construct the correct focus chain but also use
3513 // this opportunity to update the mnemonic widgets for the widgets
3516 GList
*chain
= NULL
;
3517 wxWindowGTK
* mnemonicWindow
= NULL
;
3519 for ( wxWindowList::const_iterator i
= m_children
.begin();
3520 i
!= m_children
.end();
3523 wxWindowGTK
*win
= *i
;
3525 if ( mnemonicWindow
)
3527 if ( win
->AcceptsFocusFromKeyboard() )
3529 // wxComboBox et al. needs to focus on on a different
3530 // widget than m_widget, so if the main widget isn't
3531 // focusable try the connect widget
3532 GtkWidget
* w
= win
->m_widget
;
3533 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3535 w
= win
->GetConnectWidget();
3536 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3542 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3543 mnemonicWindow
= NULL
;
3547 else if ( win
->GTKWidgetNeedsMnemonic() )
3549 mnemonicWindow
= win
;
3552 chain
= g_list_prepend(chain
, win
->m_widget
);
3555 chain
= g_list_reverse(chain
);
3557 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3562 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3567 void wxWindowGTK::Raise()
3569 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3571 if (m_wxwindow
&& m_wxwindow
->window
)
3573 gdk_window_raise( m_wxwindow
->window
);
3575 else if (m_widget
->window
)
3577 gdk_window_raise( m_widget
->window
);
3581 void wxWindowGTK::Lower()
3583 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3585 if (m_wxwindow
&& m_wxwindow
->window
)
3587 gdk_window_lower( m_wxwindow
->window
);
3589 else if (m_widget
->window
)
3591 gdk_window_lower( m_widget
->window
);
3595 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3597 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3599 if (cursor
== m_cursor
)
3603 wxapp_install_idle_handler();
3605 if (cursor
== wxNullCursor
)
3606 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3608 return wxWindowBase::SetCursor( cursor
);
3611 void wxWindowGTK::WarpPointer( int x
, int y
)
3613 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3615 // We provide this function ourselves as it is
3616 // missing in GDK (top of this file).
3618 GdkWindow
*window
= (GdkWindow
*) NULL
;
3620 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3622 window
= GetConnectWidget()->window
;
3625 gdk_window_warp_pointer( window
, x
, y
);
3628 bool wxWindowGTK::ScrollLines(int lines
)
3630 bool changed
= false;
3631 GtkRange
* range
= m_scrollBar
[1];
3634 GtkAdjustment
* adj
= range
->adjustment
;
3635 const int pos
= int(adj
->value
+ 0.5);
3636 gtk_range_set_value(range
, pos
+ lines
);
3637 changed
= pos
!= int(adj
->value
+ 0.5);
3642 bool wxWindowGTK::ScrollPages(int pages
)
3644 bool changed
= false;
3645 GtkRange
* range
= m_scrollBar
[1];
3648 GtkAdjustment
* adj
= range
->adjustment
;
3649 const int pos
= int(adj
->value
+ 0.5);
3650 gtk_range_set_value(range
, pos
+ pages
* adj
->page_size
);
3651 changed
= pos
!= int(adj
->value
+ 0.5);
3656 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3660 if (!m_widget
->window
)
3665 GdkRectangle gdk_rect
,
3669 gdk_rect
.x
= rect
->x
;
3670 gdk_rect
.y
= rect
->y
;
3671 gdk_rect
.width
= rect
->width
;
3672 gdk_rect
.height
= rect
->height
;
3675 else // invalidate everything
3680 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3684 void wxWindowGTK::Update()
3688 // when we call Update() we really want to update the window immediately on
3689 // screen, even if it means flushing the entire queue and hence slowing down
3690 // everything -- but it should still be done, it's just that Update() should
3691 // be called very rarely
3695 void wxWindowGTK::GtkUpdate()
3697 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3698 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3700 // for consistency with other platforms (and also because it's convenient
3701 // to be able to update an entire TLW by calling Update() only once), we
3702 // should also update all our children here
3703 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3705 node
= node
->GetNext() )
3707 node
->GetData()->GtkUpdate();
3711 void wxWindowGTK::GtkSendPaintEvents()
3715 m_updateRegion
.Clear();
3719 // Clip to paint region in wxClientDC
3720 m_clipPaintRegion
= true;
3722 // widget to draw on
3723 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3725 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3727 // find ancestor from which to steal background
3728 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3730 parent
= (wxWindow
*)this;
3732 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3734 wxRegionIterator
upd( m_updateRegion
);
3738 rect
.x
= upd
.GetX();
3739 rect
.y
= upd
.GetY();
3740 rect
.width
= upd
.GetWidth();
3741 rect
.height
= upd
.GetHeight();
3743 gtk_paint_flat_box( parent
->m_widget
->style
,
3745 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3759 wxWindowDC
dc( (wxWindow
*)this );
3760 dc
.SetClippingRegion( m_updateRegion
);
3762 wxEraseEvent
erase_event( GetId(), &dc
);
3763 erase_event
.SetEventObject( this );
3765 GetEventHandler()->ProcessEvent(erase_event
);
3768 wxNcPaintEvent
nc_paint_event( GetId() );
3769 nc_paint_event
.SetEventObject( this );
3770 GetEventHandler()->ProcessEvent( nc_paint_event
);
3772 wxPaintEvent
paint_event( GetId() );
3773 paint_event
.SetEventObject( this );
3774 GetEventHandler()->ProcessEvent( paint_event
);
3776 m_clipPaintRegion
= false;
3778 m_updateRegion
.Clear();
3781 void wxWindowGTK::SetDoubleBuffered( bool on
)
3783 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3786 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3789 void wxWindowGTK::ClearBackground()
3791 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3795 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3797 wxWindowBase::DoSetToolTip(tip
);
3800 m_tooltip
->Apply( (wxWindow
*)this );
3803 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3805 wxString
tmp( tip
);
3806 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3808 #endif // wxUSE_TOOLTIPS
3810 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3812 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3814 if (!wxWindowBase::SetBackgroundColour(colour
))
3819 // We need the pixel value e.g. for background clearing.
3820 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3823 // apply style change (forceStyle=true so that new style is applied
3824 // even if the bg colour changed from valid to wxNullColour)
3825 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3826 ApplyWidgetStyle(true);
3831 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3833 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3835 if (!wxWindowBase::SetForegroundColour(colour
))
3842 // We need the pixel value e.g. for background clearing.
3843 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3846 // apply style change (forceStyle=true so that new style is applied
3847 // even if the bg colour changed from valid to wxNullColour):
3848 ApplyWidgetStyle(true);
3853 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3855 return gtk_widget_get_pango_context( m_widget
);
3858 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3860 // do we need to apply any changes at all?
3863 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3868 GtkRcStyle
*style
= gtk_rc_style_new();
3873 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3876 if ( m_foregroundColour
.Ok() )
3878 GdkColor
*fg
= m_foregroundColour
.GetColor();
3880 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3881 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3883 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3884 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3886 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3887 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3890 if ( m_backgroundColour
.Ok() )
3892 GdkColor
*bg
= m_backgroundColour
.GetColor();
3894 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3895 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3896 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3897 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3899 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3900 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3901 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3902 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3904 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3905 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3906 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3907 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3909 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3910 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3911 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3912 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3918 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3920 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3923 DoApplyWidgetStyle(style
);
3924 gtk_rc_style_unref(style
);
3927 // Style change may affect GTK+'s size calculation:
3928 InvalidateBestSize();
3931 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3934 gtk_widget_modify_style(m_wxwindow
, style
);
3936 gtk_widget_modify_style(m_widget
, style
);
3939 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3941 wxWindowBase::SetBackgroundStyle(style
);
3943 if (style
== wxBG_STYLE_CUSTOM
)
3945 GdkWindow
*window
= (GdkWindow
*) NULL
;
3947 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3949 window
= GetConnectWidget()->window
;
3953 // Make sure GDK/X11 doesn't refresh the window
3955 gdk_window_set_back_pixmap( window
, None
, False
);
3957 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3960 m_needsStyleChange
= false;
3963 // Do in OnIdle, because the window is not yet available
3964 m_needsStyleChange
= true;
3966 // Don't apply widget style, or we get a grey background
3970 // apply style change (forceStyle=true so that new style is applied
3971 // even if the bg colour changed from valid to wxNullColour):
3972 ApplyWidgetStyle(true);
3977 #if wxUSE_DRAG_AND_DROP
3979 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3981 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3983 GtkWidget
*dnd_widget
= GetConnectWidget();
3985 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3987 if (m_dropTarget
) delete m_dropTarget
;
3988 m_dropTarget
= dropTarget
;
3990 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3993 #endif // wxUSE_DRAG_AND_DROP
3995 GtkWidget
* wxWindowGTK::GetConnectWidget()
3997 GtkWidget
*connect_widget
= m_widget
;
3998 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4000 return connect_widget
;
4003 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4006 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4008 return (window
== m_widget
->window
);
4011 bool wxWindowGTK::SetFont( const wxFont
&font
)
4013 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4015 if (!wxWindowBase::SetFont(font
))
4018 // apply style change (forceStyle=true so that new style is applied
4019 // even if the font changed from valid to wxNullFont):
4020 ApplyWidgetStyle(true);
4025 void wxWindowGTK::DoCaptureMouse()
4027 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4029 GdkWindow
*window
= (GdkWindow
*) NULL
;
4031 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4033 window
= GetConnectWidget()->window
;
4035 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4037 const wxCursor
* cursor
= &m_cursor
;
4039 cursor
= wxSTANDARD_CURSOR
;
4041 gdk_pointer_grab( window
, FALSE
,
4043 (GDK_BUTTON_PRESS_MASK
|
4044 GDK_BUTTON_RELEASE_MASK
|
4045 GDK_POINTER_MOTION_HINT_MASK
|
4046 GDK_POINTER_MOTION_MASK
),
4048 cursor
->GetCursor(),
4049 (guint32
)GDK_CURRENT_TIME
);
4050 g_captureWindow
= this;
4051 g_captureWindowHasMouse
= true;
4054 void wxWindowGTK::DoReleaseMouse()
4056 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4058 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4060 g_captureWindow
= (wxWindowGTK
*) NULL
;
4062 GdkWindow
*window
= (GdkWindow
*) NULL
;
4064 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4066 window
= GetConnectWidget()->window
;
4071 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4075 wxWindow
*wxWindowBase::GetCapture()
4077 return (wxWindow
*)g_captureWindow
;
4080 bool wxWindowGTK::IsRetained() const
4085 void wxWindowGTK::BlockScrollEvent()
4087 wxASSERT(!m_blockScrollEvent
);
4088 m_blockScrollEvent
= true;
4091 void wxWindowGTK::UnblockScrollEvent()
4093 wxASSERT(m_blockScrollEvent
);
4094 m_blockScrollEvent
= false;
4097 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4100 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4101 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4105 m_hasScrolling
= true;
4109 // GtkRange requires upper > lower
4114 if (pos
> range
- thumbVisible
)
4115 pos
= range
- thumbVisible
;
4118 const int i
= orient
== wxVERTICAL
;
4119 GtkAdjustment
* adj
= m_scrollBar
[i
]->adjustment
;
4120 adj
->step_increment
= 1;
4121 adj
->page_increment
=
4122 adj
->page_size
= thumbVisible
;
4124 SetScrollPos(orient
, pos
);
4125 gtk_adjustment_changed(adj
);
4128 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4130 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4131 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4133 // This check is more than an optimization. Without it, the slider
4134 // will not move smoothly while tracking when using wxScrollHelper.
4135 if (GetScrollPos(orient
) != pos
)
4137 const int i
= orient
== wxVERTICAL
;
4138 GtkAdjustment
* adj
= m_scrollBar
[i
]->adjustment
;
4139 const int max
= int(adj
->upper
- adj
->page_size
);
4146 // If a "value_changed" signal emission is not already in progress
4147 if (!m_blockValueChanged
[i
])
4149 gtk_adjustment_value_changed(adj
);
4154 int wxWindowGTK::GetScrollThumb( int orient
) const
4156 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4157 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4159 const int i
= orient
== wxVERTICAL
;
4160 return int(m_scrollBar
[i
]->adjustment
->page_size
);
4163 int wxWindowGTK::GetScrollPos( int orient
) const
4165 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4166 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4168 const int i
= orient
== wxVERTICAL
;
4169 return int(m_scrollBar
[i
]->adjustment
->value
+ 0.5);
4172 int wxWindowGTK::GetScrollRange( int orient
) const
4174 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4175 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4177 const int i
= orient
== wxVERTICAL
;
4178 return int(m_scrollBar
[i
]->adjustment
->upper
);
4181 // Determine if increment is the same as +/-x, allowing for some small
4182 // difference due to possible inexactness in floating point arithmetic
4183 static inline bool IsScrollIncrement(double increment
, double x
)
4185 wxASSERT(increment
> 0);
4186 const double tolerance
= 1.0 / 1024;
4187 return fabs(increment
- fabs(x
)) < tolerance
;
4190 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4195 wxapp_install_idle_handler();
4197 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4199 const int barIndex
= range
== m_scrollBar
[1];
4200 GtkAdjustment
* adj
= range
->adjustment
;
4201 const int value
= int(adj
->value
+ 0.5);
4202 // save previous position
4203 const double oldPos
= m_scrollPos
[barIndex
];
4204 // update current position
4205 m_scrollPos
[barIndex
] = adj
->value
;
4206 // If event should be ignored, or integral position has not changed
4207 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4212 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4215 // Difference from last change event
4216 const double diff
= adj
->value
- oldPos
;
4217 const bool isDown
= diff
> 0;
4219 if (IsScrollIncrement(adj
->step_increment
, diff
))
4221 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4223 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4225 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4227 else if (m_mouseButtonDown
)
4229 // Assume track event
4230 m_isScrolling
= true;
4236 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4238 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4240 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4242 // No scrolling requested.
4243 if ((dx
== 0) && (dy
== 0)) return;
4245 m_clipPaintRegion
= true;
4247 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4249 m_clipPaintRegion
= false;
4252 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4254 //RN: Note that static controls usually have no border on gtk, so maybe
4255 //it makes sense to treat that as simply no border at the wx level
4257 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4259 GtkShadowType gtkstyle
;
4261 if(wxstyle
& wxBORDER_RAISED
)
4262 gtkstyle
= GTK_SHADOW_OUT
;
4263 else if (wxstyle
& wxBORDER_SUNKEN
)
4264 gtkstyle
= GTK_SHADOW_IN
;
4265 else if (wxstyle
& wxBORDER_DOUBLE
)
4266 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4268 gtkstyle
= GTK_SHADOW_IN
;
4270 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4275 void wxWindowGTK::SetWindowStyleFlag( long style
)
4277 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4278 wxWindowBase::SetWindowStyleFlag(style
);
4281 // Find the wxWindow at the current mouse position, also returning the mouse
4283 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4285 pt
= wxGetMousePosition();
4286 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4290 // Get the current mouse position.
4291 wxPoint
wxGetMousePosition()
4293 /* This crashes when used within wxHelpContext,
4294 so we have to use the X-specific implementation below.
4296 GdkModifierType *mask;
4297 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4299 return wxPoint(x, y);
4303 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4305 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4306 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4307 Window rootReturn
, childReturn
;
4308 int rootX
, rootY
, winX
, winY
;
4309 unsigned int maskReturn
;
4311 XQueryPointer (display
,
4315 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4316 return wxPoint(rootX
, rootY
);
4320 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4321 void wxAddGrab(wxWindow
* window
)
4323 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4326 void wxRemoveGrab(wxWindow
* window
)
4328 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4331 // ----------------------------------------------------------------------------
4333 // ----------------------------------------------------------------------------
4335 class wxWinModule
: public wxModule
4342 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4345 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4347 bool wxWinModule::OnInit()
4349 // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() );
4350 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4355 void wxWinModule::OnExit()
4358 g_object_unref (g_eraseGC
);