1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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"
18 #include "wx/dcclient.h"
21 #include "wx/layout.h"
23 #include "wx/dialog.h"
24 #include "wx/msgdlg.h"
25 #include "wx/module.h"
26 #include "wx/combobox.h"
27 #if wxUSE_TOOLBAR_NATIVE
28 #include "wx/toolbar.h"
31 #if wxUSE_DRAG_AND_DROP
36 #include "wx/tooltip.h"
44 #include "wx/textctrl.h"
48 #include "wx/statusbr.h"
50 #include "wx/settings.h"
52 #include "wx/fontutil.h"
53 #include "wx/stattext.h"
56 #include "wx/thread.h"
62 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
63 #include <gtk/gtkversion.h>
64 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
65 #undef GTK_DISABLE_DEPRECATED
68 #include "wx/gtk/private.h"
69 #include <gdk/gdkprivate.h>
70 #include <gdk/gdkkeysyms.h>
74 #include <gtk/gtkprivate.h>
76 #include "wx/gtk/win_gtk.h"
78 #include <pango/pangox.h>
84 extern GtkContainerClass
*pizza_parent_class
;
86 //-----------------------------------------------------------------------------
87 // documentation on internals
88 //-----------------------------------------------------------------------------
91 I have been asked several times about writing some documentation about
92 the GTK port of wxWidgets, especially its internal structures. Obviously,
93 you cannot understand wxGTK without knowing a little about the GTK, but
94 some more information about what the wxWindow, which is the base class
95 for all other window classes, does seems required as well.
99 What does wxWindow do? It contains the common interface for the following
100 jobs of its descendants:
102 1) Define the rudimentary behaviour common to all window classes, such as
103 resizing, intercepting user input (so as to make it possible to use these
104 events for special purposes in a derived class), window names etc.
106 2) Provide the possibility to contain and manage children, if the derived
107 class is allowed to contain children, which holds true for those window
108 classes which do not display a native GTK widget. To name them, these
109 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
110 work classes are a special case and are handled a bit differently from
111 the rest. The same holds true for the wxNotebook class.
113 3) Provide the possibility to draw into a client area of a window. This,
114 too, only holds true for classes that do not display a native GTK widget
117 4) Provide the entire mechanism for scrolling widgets. This actual inter-
118 face for this is usually in wxScrolledWindow, but the GTK implementation
121 5) A multitude of helper or extra methods for special purposes, such as
122 Drag'n'Drop, managing validators etc.
124 6) Display a border (sunken, raised, simple or none).
126 Normally one might expect, that one wxWidgets window would always correspond
127 to one GTK widget. Under GTK, there is no such allround widget that has all
128 the functionality. Moreover, the GTK defines a client area as a different
129 widget from the actual widget you are handling. Last but not least some
130 special classes (e.g. wxFrame) handle different categories of widgets and
131 still have the possibility to draw something in the client area.
132 It was therefore required to write a special purpose GTK widget, that would
133 represent a client area in the sense of wxWidgets capable to do the jobs
134 2), 3) and 4). I have written this class and it resides in win_gtk.c of
137 All windows must have a widget, with which they interact with other under-
138 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
139 the wxWindow class has a member variable called m_widget which holds a
140 pointer to this widget. When the window class represents a GTK native widget,
141 this is (in most cases) the only GTK widget the class manages. E.g. the
142 wxStaticText class handles only a GtkLabel widget a pointer to which you
143 can find in m_widget (defined in wxWindow)
145 When the class has a client area for drawing into and for containing children
146 it has to handle the client area widget (of the type GtkPizza, defined in
147 win_gtk.c), but there could be any number of widgets, handled by a class
148 The common rule for all windows is only, that the widget that interacts with
149 the rest of GTK must be referenced in m_widget and all other widgets must be
150 children of this widget on the GTK level. The top-most widget, which also
151 represents the client area, must be in the m_wxwindow field and must be of
154 As I said, the window classes that display a GTK native widget only have
155 one widget, so in the case of e.g. the wxButton class m_widget holds a
156 pointer to a GtkButton widget. But windows with client areas (for drawing
157 and children) have a m_widget field that is a pointer to a GtkScrolled-
158 Window and a m_wxwindow field that is pointer to a GtkPizza and this
159 one is (in the GTK sense) a child of the GtkScrolledWindow.
161 If the m_wxwindow field is set, then all input to this widget is inter-
162 cepted and sent to the wxWidgets class. If not, all input to the widget
163 that gets pointed to by m_widget gets intercepted and sent to the class.
167 The design of scrolling in wxWidgets is markedly different from that offered
168 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
169 clicking on a scrollbar belonging to scrolled window will inevitably move
170 the window. In wxWidgets, the scrollbar will only emit an event, send this
171 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
172 which actually moves the window and its subchildren. Note that GtkPizza
173 memorizes how much it has been scrolled but that wxWidgets forgets this
174 so that the two coordinates systems have to be kept in synch. This is done
175 in various places using the pizza->xoffset and pizza->yoffset values.
179 Singularily the most broken code in GTK is the code that is supposed to
180 inform subwindows (child windows) about new positions. Very often, duplicate
181 events are sent without changes in size or position, equally often no
182 events are sent at all (All this is due to a bug in the GtkContainer code
183 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
184 GTK's own system and it simply waits for size events for toplevel windows
185 and then iterates down the respective size events to all window. This has
186 the disadvantage that windows might get size events before the GTK widget
187 actually has the reported size. This doesn't normally pose any problem, but
188 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
189 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
190 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
191 window that is used for OpenGL output really has that size (as reported by
196 If someone at some point of time feels the immense desire to have a look at,
197 change or attempt to optimise the Refresh() logic, this person will need an
198 intimate understanding of what "draw" and "expose" events are and what
199 they are used for, in particular when used in connection with GTK's
200 own windowless widgets. Beware.
204 Cursors, too, have been a constant source of pleasure. The main difficulty
205 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
206 for the parent. To prevent this from doing too much harm, I use idle time
207 to set the cursor over and over again, starting from the toplevel windows
208 and ending with the youngest generation (speaking of parent and child windows).
209 Also don't forget that cursors (like much else) are connected to GdkWindows,
210 not GtkWidgets and that the "window" field of a GtkWidget might very well
211 point to the GdkWindow of the parent widget (-> "window-less widget") and
212 that the two obviously have very different meanings.
216 //-----------------------------------------------------------------------------
218 //-----------------------------------------------------------------------------
220 extern wxList wxPendingDelete
;
221 extern bool g_blockEventsOnDrag
;
222 extern bool g_blockEventsOnScroll
;
223 extern wxCursor g_globalCursor
;
225 static GdkGC
*g_eraseGC
= NULL
;
227 // mouse capture state: the window which has it and if the mouse is currently
229 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
230 static bool g_captureWindowHasMouse
= false;
232 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
234 // the last window which had the focus - this is normally never NULL (except
235 // if we never had focus at all) as even when g_focusWindow is NULL it still
236 // keeps its previous value
237 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
239 // If a window get the focus set but has not been realized
240 // yet, defer setting the focus to idle time.
241 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
243 extern bool g_mainThreadLocked
;
245 //-----------------------------------------------------------------------------
247 //-----------------------------------------------------------------------------
252 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
254 # define DEBUG_MAIN_THREAD
257 #define DEBUG_MAIN_THREAD
260 // the trace mask used for the focus debugging messages
261 #define TRACE_FOCUS _T("focus")
263 //-----------------------------------------------------------------------------
264 // missing gdk functions
265 //-----------------------------------------------------------------------------
268 gdk_window_warp_pointer (GdkWindow
*window
,
273 window
= GDK_ROOT_PARENT();
275 if (!GDK_WINDOW_DESTROYED(window
))
277 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
278 None
, /* not source window -> move from anywhere */
279 GDK_WINDOW_XID(window
), /* dest window */
280 0, 0, 0, 0, /* not source window -> move from anywhere */
285 //-----------------------------------------------------------------------------
287 //-----------------------------------------------------------------------------
289 extern void wxapp_install_idle_handler();
290 extern bool g_isIdle
;
292 //-----------------------------------------------------------------------------
293 // local code (see below)
294 //-----------------------------------------------------------------------------
296 // returns the child of win which currently has focus or NULL if not found
298 // Note: can't be static, needed by textctrl.cpp.
299 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
301 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
303 return (wxWindow
*)NULL
;
305 if ( winFocus
== win
)
306 return (wxWindow
*)win
;
308 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
310 node
= node
->GetNext() )
312 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
317 return (wxWindow
*)NULL
;
320 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
322 // wxUniversal widgets draw the borders and scrollbars themselves
323 #ifndef __WXUNIVERSAL__
330 if (win
->m_hasScrolling
)
332 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
334 GtkRequisition vscroll_req
;
335 vscroll_req
.width
= 2;
336 vscroll_req
.height
= 2;
337 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
338 (scroll_window
->vscrollbar
, &vscroll_req
);
340 GtkRequisition hscroll_req
;
341 hscroll_req
.width
= 2;
342 hscroll_req
.height
= 2;
343 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
344 (scroll_window
->hscrollbar
, &hscroll_req
);
346 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
348 if (scroll_window
->vscrollbar_visible
)
350 dw
+= vscroll_req
.width
;
351 dw
+= scroll_class
->scrollbar_spacing
;
354 if (scroll_window
->hscrollbar_visible
)
356 dh
+= hscroll_req
.height
;
357 dh
+= scroll_class
->scrollbar_spacing
;
363 if (GTK_WIDGET_NO_WINDOW (widget
))
365 dx
+= widget
->allocation
.x
;
366 dy
+= widget
->allocation
.y
;
369 if (win
->HasFlag(wxRAISED_BORDER
))
371 gtk_paint_shadow (widget
->style
,
375 NULL
, NULL
, NULL
, // FIXME: No clipping?
377 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
381 if (win
->HasFlag(wxSUNKEN_BORDER
))
383 gtk_paint_shadow (widget
->style
,
387 NULL
, NULL
, NULL
, // FIXME: No clipping?
389 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
393 if (win
->HasFlag(wxSIMPLE_BORDER
))
396 gc
= gdk_gc_new( widget
->window
);
397 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
398 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
400 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
404 #endif // __WXUNIVERSAL__
407 //-----------------------------------------------------------------------------
408 // "expose_event" of m_widget
409 //-----------------------------------------------------------------------------
413 gtk_window_own_expose_callback( GtkWidget
*widget
,
414 GdkEventExpose
*gdk_event
,
417 if (gdk_event
->count
> 0) return FALSE
;
419 draw_frame( widget
, win
);
421 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
427 //-----------------------------------------------------------------------------
428 // "size_request" of m_widget
429 //-----------------------------------------------------------------------------
431 // make it extern because wxStaticText needs to disconnect this one
433 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
434 GtkRequisition
*requisition
,
438 win
->GetSize( &w
, &h
);
444 requisition
->height
= h
;
445 requisition
->width
= w
;
451 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
452 GtkRequisition
*requisition
,
455 // This callback is actually hooked into the text entry
456 // of the combo box, not the GtkHBox.
459 win
->GetSize( &w
, &h
);
465 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
467 GtkRequisition entry_req
;
469 entry_req
.height
= 2;
470 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
471 (gcombo
->button
, &entry_req
);
473 requisition
->width
= w
- entry_req
.width
;
474 requisition
->height
= entry_req
.height
;
478 //-----------------------------------------------------------------------------
479 // "expose_event" of m_wxwindow
480 //-----------------------------------------------------------------------------
484 gtk_window_expose_callback( GtkWidget
*widget
,
485 GdkEventExpose
*gdk_event
,
491 wxapp_install_idle_handler();
493 // This callback gets called in drawing-idle time under
494 // GTK 2.0, so we don't need to defer anything to idle
497 GtkPizza
*pizza
= GTK_PIZZA( widget
);
498 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
503 wxPrintf( wxT("OnExpose from ") );
504 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
505 wxPrintf( win
->GetClassInfo()->GetClassName() );
506 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
507 (int)gdk_event
->area
.y
,
508 (int)gdk_event
->area
.width
,
509 (int)gdk_event
->area
.height
);
514 win
->m_wxwindow
->style
,
518 (GdkRectangle
*) NULL
,
520 (char *)"button", // const_cast
525 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
527 win
->GtkSendPaintEvents();
530 // Let parent window draw window-less widgets
531 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
537 //-----------------------------------------------------------------------------
538 // "key_press_event" from any window
539 //-----------------------------------------------------------------------------
541 // set WXTRACE to this to see the key event codes on the console
542 #define TRACE_KEYS _T("keyevent")
544 // translates an X key symbol to WXK_XXX value
546 // if isChar is true it means that the value returned will be used for EVT_CHAR
547 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
548 // for example, while if it is false it means that the value is going to be
549 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
551 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
557 // Shift, Control and Alt don't generate the CHAR events at all
560 key_code
= isChar
? 0 : WXK_SHIFT
;
564 key_code
= isChar
? 0 : WXK_CONTROL
;
572 key_code
= isChar
? 0 : WXK_ALT
;
575 // neither do the toggle modifies
576 case GDK_Scroll_Lock
:
577 key_code
= isChar
? 0 : WXK_SCROLL
;
581 key_code
= isChar
? 0 : WXK_CAPITAL
;
585 key_code
= isChar
? 0 : WXK_NUMLOCK
;
589 // various other special keys
602 case GDK_ISO_Left_Tab
:
609 key_code
= WXK_RETURN
;
613 key_code
= WXK_CLEAR
;
617 key_code
= WXK_PAUSE
;
621 key_code
= WXK_SELECT
;
625 key_code
= WXK_PRINT
;
629 key_code
= WXK_EXECUTE
;
633 key_code
= WXK_ESCAPE
;
636 // cursor and other extended keyboard keys
638 key_code
= WXK_DELETE
;
654 key_code
= WXK_RIGHT
;
661 case GDK_Prior
: // == GDK_Page_Up
662 key_code
= WXK_PRIOR
;
665 case GDK_Next
: // == GDK_Page_Down
678 key_code
= WXK_INSERT
;
693 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
697 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
701 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
705 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
709 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
713 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
717 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
721 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
725 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
729 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
733 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
737 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
741 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
744 case GDK_KP_Prior
: // == GDK_KP_Page_Up
745 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
748 case GDK_KP_Next
: // == GDK_KP_Page_Down
749 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
753 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
757 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
761 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
765 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
769 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
772 case GDK_KP_Multiply
:
773 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
777 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
780 case GDK_KP_Separator
:
781 // FIXME: what is this?
782 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
785 case GDK_KP_Subtract
:
786 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
790 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
794 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
811 key_code
= WXK_F1
+ keysym
- GDK_F1
;
821 static inline bool wxIsAsciiKeysym(KeySym ks
)
826 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
828 GdkEventKey
*gdk_event
)
832 GdkModifierType state
;
833 if (gdk_event
->window
)
834 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
836 event
.SetTimestamp( gdk_event
->time
);
837 event
.SetId(win
->GetId());
838 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
839 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
840 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
841 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
842 event
.m_scanCode
= gdk_event
->keyval
;
843 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
844 event
.m_rawFlags
= 0;
846 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
847 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
849 event
.m_uniChar
= toupper(event
.m_uniChar
);
852 wxGetMousePosition( &x
, &y
);
853 win
->ScreenToClient( &x
, &y
);
856 event
.SetEventObject( win
);
861 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
863 GdkEventKey
*gdk_event
)
865 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
866 // but only event->keyval which is quite useless to us, so remember
867 // the last character from GDK_KEY_PRESS and reuse it as last resort
869 // NB: should be MT-safe as we're always called from the main thread only
874 } s_lastKeyPress
= { 0, 0 };
876 KeySym keysym
= gdk_event
->keyval
;
878 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
879 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
883 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
887 // do we have the translation or is it a plain ASCII character?
888 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
890 // we should use keysym if it is ASCII as X does some translations
891 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
892 // which we don't want here (but which we do use for OnChar())
893 if ( !wxIsAsciiKeysym(keysym
) )
895 keysym
= (KeySym
)gdk_event
->string
[0];
898 // we want to always get the same key code when the same key is
899 // pressed regardless of the state of the modifiers, i.e. on a
900 // standard US keyboard pressing '5' or '%' ('5' key with
901 // Shift) should result in the same key code in OnKeyDown():
902 // '5' (although OnChar() will get either '5' or '%').
904 // to do it we first translate keysym to keycode (== scan code)
905 // and then back but always using the lower register
906 Display
*dpy
= (Display
*)wxGetDisplay();
907 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
909 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
911 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
913 // use the normalized, i.e. lower register, keysym if we've
915 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
917 // as explained above, we want to have lower register key codes
918 // normally but for the letter keys we want to have the upper ones
920 // NB: don't use XConvertCase() here, we want to do it for letters
922 key_code
= toupper(key_code
);
924 else // non ASCII key, what to do?
926 // by default, ignore it
929 // but if we have cached information from the last KEY_PRESS
930 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
933 if ( keysym
== s_lastKeyPress
.keysym
)
935 key_code
= s_lastKeyPress
.keycode
;
940 if ( gdk_event
->type
== GDK_KEY_PRESS
)
942 // remember it to be reused for KEY_UP event later
943 s_lastKeyPress
.keysym
= keysym
;
944 s_lastKeyPress
.keycode
= key_code
;
948 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
950 // sending unknown key events doesn't really make sense
954 // now fill all the other fields
955 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
957 event
.m_keyCode
= key_code
;
965 GtkIMContext
*context
;
966 GdkEventKey
*lastKeyEvent
;
970 context
= gtk_im_multicontext_new();
975 g_object_unref(context
);
981 gtk_window_key_press_callback( GtkWidget
*widget
,
982 GdkEventKey
*gdk_event
,
988 wxapp_install_idle_handler();
992 if (g_blockEventsOnDrag
)
996 wxKeyEvent
event( wxEVT_KEY_DOWN
);
998 bool return_after_IM
= false;
1000 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1002 // Emit KEY_DOWN event
1003 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1007 // Return after IM processing as we cannot do
1008 // anything with it anyhow.
1009 return_after_IM
= true;
1012 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1013 // When we get a key_press event here, it could be originate
1014 // from the current widget or its child widgets. However, only the widget
1015 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1016 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1017 // originated from its child widgets and shouldn't be passed to IM context.
1018 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1019 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1020 // widgets has both IM context and input focus, the event should be filtered
1021 // by gtk_im_context_filter_keypress().
1022 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1023 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1025 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1026 // docs, if IM filter returns true, no further processing should be done.
1027 // we should send the key_down event anyway.
1028 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1029 win
->m_imData
->lastKeyEvent
= NULL
;
1030 if (intercepted_by_IM
)
1032 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1037 if (return_after_IM
)
1043 wxWindowGTK
*ancestor
= win
;
1046 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1049 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1050 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1053 if (ancestor
->IsTopLevel())
1055 ancestor
= ancestor
->GetParent();
1058 #endif // wxUSE_ACCEL
1060 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1061 // will only be sent if it is not in an accelerator table.
1065 KeySym keysym
= gdk_event
->keyval
;
1066 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1067 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1070 if ( wxIsAsciiKeysym(keysym
) )
1073 key_code
= (unsigned char)keysym
;
1075 // gdk_event->string is actually deprecated
1076 else if ( gdk_event
->length
== 1 )
1078 key_code
= (unsigned char)gdk_event
->string
[0];
1084 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1086 event
.m_keyCode
= key_code
;
1088 // To conform to the docs we need to translate Ctrl-alpha
1089 // characters to values in the range 1-26.
1090 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1092 event
.m_keyCode
= key_code
- 'a' + 1;
1094 event
.m_uniChar
= event
.m_keyCode
;
1098 // Implement OnCharHook by checking ancestor top level windows
1099 wxWindow
*parent
= win
;
1100 while (parent
&& !parent
->IsTopLevel())
1101 parent
= parent
->GetParent();
1104 event
.SetEventType( wxEVT_CHAR_HOOK
);
1105 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1110 event
.SetEventType(wxEVT_CHAR
);
1111 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1120 // win is a control: tab can be propagated up
1122 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1123 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1124 // have this style, yet choose not to process this particular TAB in which
1125 // case TAB must still work as a navigational character
1126 // JS: enabling again to make consistent with other platforms
1127 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1128 // navigation behaviour)
1130 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1132 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1134 wxNavigationKeyEvent new_event
;
1135 new_event
.SetEventObject( win
->GetParent() );
1136 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1137 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1138 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1139 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1140 new_event
.SetCurrentFocus( win
);
1141 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1144 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1146 (gdk_event
->keyval
== GDK_Escape
) )
1148 // however only do it if we have a Cancel button in the dialog,
1149 // otherwise the user code may get confused by the events from a
1150 // non-existing button and, worse, a wxButton might get button event
1151 // from another button which is not really expected
1152 wxWindow
*winForCancel
= win
,
1154 while ( winForCancel
)
1156 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1159 // found a cancel button
1163 if ( winForCancel
->IsTopLevel() )
1165 // no need to look further
1169 // maybe our parent has a cancel button?
1170 winForCancel
= winForCancel
->GetParent();
1175 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1176 eventClick
.SetEventObject(btnCancel
);
1177 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1183 g_signal_stop_emission_by_name (widget
, "key_press_event");
1193 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1197 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1199 // take modifiers, cursor position, timestamp etc. from the last
1200 // key_press_event that was fed into Input Method:
1201 if (window
->m_imData
->lastKeyEvent
)
1203 wxFillOtherKeyEventFields(event
,
1204 window
, window
->m_imData
->lastKeyEvent
);
1208 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1210 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1211 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1212 #endif // wxUSE_UNICODE
1213 if( !(const wxChar
*)data
)
1218 // Implement OnCharHook by checking ancestor top level windows
1219 wxWindow
*parent
= window
;
1220 while (parent
&& !parent
->IsTopLevel())
1221 parent
= parent
->GetParent();
1223 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1226 event
.m_uniChar
= *pstr
;
1227 // Backward compatible for ISO-8859-1
1228 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1229 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1231 event
.m_keyCode
= *pstr
;
1232 #endif // wxUSE_UNICODE
1234 // To conform to the docs we need to translate Ctrl-alpha
1235 // characters to values in the range 1-26.
1236 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1238 event
.m_keyCode
= *pstr
- 'a' + 1;
1240 event
.m_uniChar
= event
.m_keyCode
;
1246 event
.SetEventType( wxEVT_CHAR_HOOK
);
1247 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1252 event
.SetEventType(wxEVT_CHAR
);
1253 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1260 //-----------------------------------------------------------------------------
1261 // "key_release_event" from any window
1262 //-----------------------------------------------------------------------------
1266 gtk_window_key_release_callback( GtkWidget
*widget
,
1267 GdkEventKey
*gdk_event
,
1273 wxapp_install_idle_handler();
1278 if (g_blockEventsOnDrag
)
1281 wxKeyEvent
event( wxEVT_KEY_UP
);
1282 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1284 // unknown key pressed, ignore (the event would be useless anyhow)
1288 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1291 g_signal_stop_emission_by_name (widget
, "key_release_event");
1296 // ============================================================================
1298 // ============================================================================
1300 // ----------------------------------------------------------------------------
1301 // mouse event processing helpers
1302 // ----------------------------------------------------------------------------
1304 // init wxMouseEvent with the info from GdkEventXXX struct
1305 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1306 wxMouseEvent
& event
,
1309 event
.SetTimestamp( gdk_event
->time
);
1310 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1311 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1312 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1313 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1314 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1315 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1316 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1317 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1319 event
.m_linesPerAction
= 3;
1320 event
.m_wheelDelta
= 120;
1321 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1322 event
.m_wheelRotation
= 120;
1323 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1324 event
.m_wheelRotation
= -120;
1327 wxPoint pt
= win
->GetClientAreaOrigin();
1328 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1329 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1331 event
.SetEventObject( win
);
1332 event
.SetId( win
->GetId() );
1333 event
.SetTimestamp( gdk_event
->time
);
1336 static void AdjustEventButtonState(wxMouseEvent
& event
)
1338 // GDK reports the old state of the button for a button press event, but
1339 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1340 // for a LEFT_DOWN event, not FALSE, so we will invert
1341 // left/right/middleDown for the corresponding click events
1343 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1344 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1345 (event
.GetEventType() == wxEVT_LEFT_UP
))
1347 event
.m_leftDown
= !event
.m_leftDown
;
1351 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1352 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1353 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1355 event
.m_middleDown
= !event
.m_middleDown
;
1359 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1360 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1361 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1363 event
.m_rightDown
= !event
.m_rightDown
;
1368 // find the window to send the mouse event too
1370 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1375 if (win
->m_wxwindow
)
1377 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1378 xx
+= pizza
->xoffset
;
1379 yy
+= pizza
->yoffset
;
1382 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1385 wxWindowGTK
*child
= node
->GetData();
1387 node
= node
->GetNext();
1388 if (!child
->IsShown())
1391 if (child
->IsTransparentForMouse())
1393 // wxStaticBox is transparent in the box itself
1394 int xx1
= child
->m_x
;
1395 int yy1
= child
->m_y
;
1396 int xx2
= child
->m_x
+ child
->m_width
;
1397 int yy2
= child
->m_y
+ child
->m_height
;
1400 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1402 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1404 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1406 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1417 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1418 (child
->m_x
<= xx
) &&
1419 (child
->m_y
<= yy
) &&
1420 (child
->m_x
+child
->m_width
>= xx
) &&
1421 (child
->m_y
+child
->m_height
>= yy
))
1434 //-----------------------------------------------------------------------------
1435 // "button_press_event"
1436 //-----------------------------------------------------------------------------
1440 gtk_window_button_press_callback( GtkWidget
*widget
,
1441 GdkEventButton
*gdk_event
,
1447 wxapp_install_idle_handler();
1450 wxPrintf( wxT("1) OnButtonPress from ") );
1451 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1452 wxPrintf( win->GetClassInfo()->GetClassName() );
1453 wxPrintf( wxT(".\n") );
1455 if (!win
->m_hasVMT
) return FALSE
;
1456 if (g_blockEventsOnDrag
) return TRUE
;
1457 if (g_blockEventsOnScroll
) return TRUE
;
1459 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1461 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1463 gtk_widget_grab_focus( win
->m_wxwindow
);
1465 wxPrintf( wxT("GrabFocus from ") );
1466 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1467 wxPrintf( win->GetClassInfo()->GetClassName() );
1468 wxPrintf( wxT(".\n") );
1472 // GDK sends surplus button down events
1473 // before a double click event. We
1474 // need to filter these out.
1475 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1477 GdkEvent
*peek_event
= gdk_event_peek();
1480 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1481 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1483 gdk_event_free( peek_event
);
1488 gdk_event_free( peek_event
);
1493 wxEventType event_type
= wxEVT_NULL
;
1495 // GdkDisplay is a GTK+ 2.2.0 thing
1496 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1497 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1498 !gtk_check_version(2,2,0) &&
1499 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1501 // Reset GDK internal timestamp variables in order to disable GDK
1502 // triple click events. GDK will then next time believe no button has
1503 // been clicked just before, and send a normal button click event.
1504 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1505 display
->button_click_time
[1] = 0;
1506 display
->button_click_time
[0] = 0;
1510 if (gdk_event
->button
== 1)
1512 // note that GDK generates triple click events which are not supported
1513 // by wxWidgets but still have to be passed to the app as otherwise
1514 // clicks would simply go missing
1515 switch (gdk_event
->type
)
1517 // we shouldn't get triple clicks at all for GTK2 because we
1518 // suppress them artificially using the code above but we still
1519 // should map them to something for GTK1 and not just ignore them
1520 // as this would lose clicks
1521 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1522 case GDK_BUTTON_PRESS
:
1523 event_type
= wxEVT_LEFT_DOWN
;
1526 case GDK_2BUTTON_PRESS
:
1527 event_type
= wxEVT_LEFT_DCLICK
;
1531 // just to silence gcc warnings
1535 else if (gdk_event
->button
== 2)
1537 switch (gdk_event
->type
)
1539 case GDK_3BUTTON_PRESS
:
1540 case GDK_BUTTON_PRESS
:
1541 event_type
= wxEVT_MIDDLE_DOWN
;
1544 case GDK_2BUTTON_PRESS
:
1545 event_type
= wxEVT_MIDDLE_DCLICK
;
1552 else if (gdk_event
->button
== 3)
1554 switch (gdk_event
->type
)
1556 case GDK_3BUTTON_PRESS
:
1557 case GDK_BUTTON_PRESS
:
1558 event_type
= wxEVT_RIGHT_DOWN
;
1561 case GDK_2BUTTON_PRESS
:
1562 event_type
= wxEVT_RIGHT_DCLICK
;
1569 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1571 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1573 event_type
= wxEVT_MOUSEWHEEL
;
1577 if ( event_type
== wxEVT_NULL
)
1579 // unknown mouse button or click type
1583 wxMouseEvent
event( event_type
);
1584 InitMouseEvent( win
, event
, gdk_event
);
1586 AdjustEventButtonState(event
);
1588 // wxListBox actually gets mouse events from the item, so we need to give it
1589 // a chance to correct this
1590 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1592 // find the correct window to send the event to: it may be a different one
1593 // from the one which got it at GTK+ level because some controls don't have
1594 // their own X window and thus cannot get any events.
1595 if ( !g_captureWindow
)
1596 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1598 if (win
->GetEventHandler()->ProcessEvent( event
))
1600 g_signal_stop_emission_by_name (widget
, "button_press_event");
1604 if (event_type
== wxEVT_RIGHT_DOWN
)
1606 // generate a "context menu" event: this is similar to right mouse
1607 // click under many GUIs except that it is generated differently
1608 // (right up under MSW, ctrl-click under Mac, right down here) and
1610 // (a) it's a command event and so is propagated to the parent
1611 // (b) under some ports it can be generated from kbd too
1612 // (c) it uses screen coords (because of (a))
1613 wxContextMenuEvent
evtCtx(
1616 win
->ClientToScreen(event
.GetPosition()));
1617 evtCtx
.SetEventObject(win
);
1618 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1625 //-----------------------------------------------------------------------------
1626 // "button_release_event"
1627 //-----------------------------------------------------------------------------
1631 gtk_window_button_release_callback( GtkWidget
*widget
,
1632 GdkEventButton
*gdk_event
,
1638 wxapp_install_idle_handler();
1640 if (!win
->m_hasVMT
) return FALSE
;
1641 if (g_blockEventsOnDrag
) return FALSE
;
1642 if (g_blockEventsOnScroll
) return FALSE
;
1644 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1646 wxEventType event_type
= wxEVT_NULL
;
1648 switch (gdk_event
->button
)
1651 event_type
= wxEVT_LEFT_UP
;
1655 event_type
= wxEVT_MIDDLE_UP
;
1659 event_type
= wxEVT_RIGHT_UP
;
1663 // unknwon button, don't process
1667 wxMouseEvent
event( event_type
);
1668 InitMouseEvent( win
, event
, gdk_event
);
1670 AdjustEventButtonState(event
);
1672 // same wxListBox hack as above
1673 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1675 if ( !g_captureWindow
)
1676 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1678 if (win
->GetEventHandler()->ProcessEvent( event
))
1680 g_signal_stop_emission_by_name (widget
, "button_release_event");
1688 //-----------------------------------------------------------------------------
1689 // "motion_notify_event"
1690 //-----------------------------------------------------------------------------
1694 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1695 GdkEventMotion
*gdk_event
,
1701 wxapp_install_idle_handler();
1703 if (!win
->m_hasVMT
) return FALSE
;
1704 if (g_blockEventsOnDrag
) return FALSE
;
1705 if (g_blockEventsOnScroll
) return FALSE
;
1707 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1709 if (gdk_event
->is_hint
)
1713 GdkModifierType state
;
1714 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1720 printf( "OnMotion from " );
1721 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1722 printf( win->GetClassInfo()->GetClassName() );
1726 wxMouseEvent
event( wxEVT_MOTION
);
1727 InitMouseEvent(win
, event
, gdk_event
);
1729 if ( g_captureWindow
)
1731 // synthetize a mouse enter or leave event if needed
1732 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1733 // This seems to be necessary and actually been added to
1734 // GDK itself in version 2.0.X
1737 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1738 if ( hasMouse
!= g_captureWindowHasMouse
)
1740 // the mouse changed window
1741 g_captureWindowHasMouse
= hasMouse
;
1743 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1744 : wxEVT_LEAVE_WINDOW
);
1745 InitMouseEvent(win
, eventM
, gdk_event
);
1746 eventM
.SetEventObject(win
);
1747 win
->GetEventHandler()->ProcessEvent(eventM
);
1752 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1755 if ( !g_captureWindow
)
1757 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1758 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1760 // Rewrite cursor handling here (away from idle).
1764 if (win
->GetEventHandler()->ProcessEvent( event
))
1766 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1774 //-----------------------------------------------------------------------------
1775 // "mouse_wheel_event"
1776 //-----------------------------------------------------------------------------
1780 gtk_window_wheel_callback (GtkWidget
* widget
,
1781 GdkEventScroll
* gdk_event
,
1787 wxapp_install_idle_handler();
1789 wxEventType event_type
= wxEVT_NULL
;
1790 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1791 event_type
= wxEVT_MOUSEWHEEL
;
1792 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1793 event_type
= wxEVT_MOUSEWHEEL
;
1797 wxMouseEvent
event( event_type
);
1798 // Can't use InitMouse macro because scroll events don't have button
1799 event
.SetTimestamp( gdk_event
->time
);
1800 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1801 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1802 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1803 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1804 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1805 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1806 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1807 event
.m_linesPerAction
= 3;
1808 event
.m_wheelDelta
= 120;
1809 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1810 event
.m_wheelRotation
= 120;
1812 event
.m_wheelRotation
= -120;
1814 wxPoint pt
= win
->GetClientAreaOrigin();
1815 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1816 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1818 event
.SetEventObject( win
);
1819 event
.SetId( win
->GetId() );
1820 event
.SetTimestamp( gdk_event
->time
);
1822 if (win
->GetEventHandler()->ProcessEvent( event
))
1824 g_signal_stop_emission_by_name (widget
, "scroll_event");
1832 //-----------------------------------------------------------------------------
1834 //-----------------------------------------------------------------------------
1836 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1838 wxContextMenuEvent
event(
1842 event
.SetEventObject(win
);
1843 return win
->GetEventHandler()->ProcessEvent(event
);
1847 //-----------------------------------------------------------------------------
1849 //-----------------------------------------------------------------------------
1851 // send the wxChildFocusEvent and wxFocusEvent, common code of
1852 // gtk_window_focus_in_callback() and SetFocus()
1853 static bool DoSendFocusEvents(wxWindow
*win
)
1855 // Notify the parent keeping track of focus for the kbd navigation
1856 // purposes that we got it.
1857 wxChildFocusEvent
eventChildFocus(win
);
1858 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1860 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1861 eventFocus
.SetEventObject(win
);
1863 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1868 gtk_window_focus_in_callback( GtkWidget
*widget
,
1869 GdkEventFocus
*WXUNUSED(event
),
1875 wxapp_install_idle_handler();
1878 gtk_im_context_focus_in(win
->m_imData
->context
);
1881 g_focusWindow
= win
;
1883 wxLogTrace(TRACE_FOCUS
,
1884 _T("%s: focus in"), win
->GetName().c_str());
1888 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1892 // caret needs to be informed about focus change
1893 wxCaret
*caret
= win
->GetCaret();
1896 caret
->OnSetFocus();
1898 #endif // wxUSE_CARET
1900 gboolean ret
= FALSE
;
1902 // does the window itself think that it has the focus?
1903 if ( !win
->m_hasFocus
)
1905 // not yet, notify it
1906 win
->m_hasFocus
= true;
1908 (void)DoSendFocusEvents(win
);
1913 // Disable default focus handling for custom windows
1914 // since the default GTK+ handler issues a repaint
1915 if (win
->m_wxwindow
)
1922 //-----------------------------------------------------------------------------
1923 // "focus_out_event"
1924 //-----------------------------------------------------------------------------
1928 gtk_window_focus_out_callback( GtkWidget
*widget
,
1929 GdkEventFocus
*gdk_event
,
1935 wxapp_install_idle_handler();
1938 gtk_im_context_focus_out(win
->m_imData
->context
);
1940 wxLogTrace( TRACE_FOCUS
,
1941 _T("%s: focus out"), win
->GetName().c_str() );
1944 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1948 g_focusWindow
= (wxWindowGTK
*)NULL
;
1956 // caret needs to be informed about focus change
1957 wxCaret
*caret
= win
->GetCaret();
1960 caret
->OnKillFocus();
1962 #endif // wxUSE_CARET
1964 gboolean ret
= FALSE
;
1966 // don't send the window a kill focus event if it thinks that it doesn't
1967 // have focus already
1968 if ( win
->m_hasFocus
)
1970 win
->m_hasFocus
= false;
1972 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1973 event
.SetEventObject( win
);
1975 (void)win
->GetEventHandler()->ProcessEvent( event
);
1980 // Disable default focus handling for custom windows
1981 // since the default GTK+ handler issues a repaint
1982 if (win
->m_wxwindow
)
1989 //-----------------------------------------------------------------------------
1990 // "enter_notify_event"
1991 //-----------------------------------------------------------------------------
1995 gtk_window_enter_callback( GtkWidget
*widget
,
1996 GdkEventCrossing
*gdk_event
,
2002 wxapp_install_idle_handler();
2004 if (!win
->m_hasVMT
) return FALSE
;
2005 if (g_blockEventsOnDrag
) return FALSE
;
2007 // Event was emitted after a grab
2008 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2010 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2014 GdkModifierType state
= (GdkModifierType
)0;
2016 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2018 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2019 InitMouseEvent(win
, event
, gdk_event
);
2020 wxPoint pt
= win
->GetClientAreaOrigin();
2021 event
.m_x
= x
+ pt
.x
;
2022 event
.m_y
= y
+ pt
.y
;
2024 if ( !g_captureWindow
)
2026 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2027 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2029 // Rewrite cursor handling here (away from idle).
2033 if (win
->GetEventHandler()->ProcessEvent( event
))
2035 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2043 //-----------------------------------------------------------------------------
2044 // "leave_notify_event"
2045 //-----------------------------------------------------------------------------
2049 gtk_window_leave_callback( GtkWidget
*widget
,
2050 GdkEventCrossing
*gdk_event
,
2056 wxapp_install_idle_handler();
2058 if (!win
->m_hasVMT
) return FALSE
;
2059 if (g_blockEventsOnDrag
) return FALSE
;
2061 // Event was emitted after an ungrab
2062 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2064 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2066 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2067 event
.SetTimestamp( gdk_event
->time
);
2068 event
.SetEventObject( win
);
2072 GdkModifierType state
= (GdkModifierType
)0;
2074 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2076 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2077 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2078 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2079 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2080 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2081 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2082 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2084 wxPoint pt
= win
->GetClientAreaOrigin();
2085 event
.m_x
= x
+ pt
.x
;
2086 event
.m_y
= y
+ pt
.y
;
2088 if (win
->GetEventHandler()->ProcessEvent( event
))
2090 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2098 //-----------------------------------------------------------------------------
2099 // "value_changed" from m_vAdjust
2100 //-----------------------------------------------------------------------------
2103 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2109 wxapp_install_idle_handler();
2111 if (g_blockEventsOnDrag
) return;
2113 if (!win
->m_hasVMT
) return;
2115 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2116 if (fabs(diff
) < 0.2) return;
2118 win
->m_oldVerticalPos
= adjust
->value
;
2120 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2122 int value
= (int)(adjust
->value
+0.5);
2124 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2125 event
.SetEventObject( win
);
2126 win
->GetEventHandler()->ProcessEvent( event
);
2130 //-----------------------------------------------------------------------------
2131 // "value_changed" from m_hAdjust
2132 //-----------------------------------------------------------------------------
2135 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2141 wxapp_install_idle_handler();
2143 if (g_blockEventsOnDrag
) return;
2144 if (!win
->m_hasVMT
) return;
2146 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2147 if (fabs(diff
) < 0.2) return;
2149 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2151 win
->m_oldHorizontalPos
= adjust
->value
;
2153 int value
= (int)(adjust
->value
+0.5);
2155 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2156 event
.SetEventObject( win
);
2157 win
->GetEventHandler()->ProcessEvent( event
);
2161 //-----------------------------------------------------------------------------
2162 // "button_press_event" from scrollbar
2163 //-----------------------------------------------------------------------------
2167 gtk_scrollbar_button_press_callback( GtkWidget
*widget
,
2168 GdkEventButton
*gdk_event
,
2174 wxapp_install_idle_handler();
2177 g_blockEventsOnScroll
= true;
2179 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2181 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2188 //-----------------------------------------------------------------------------
2189 // "button_release_event" from scrollbar
2190 //-----------------------------------------------------------------------------
2194 gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2195 GdkEventButton
*WXUNUSED(gdk_event
),
2200 // don't test here as we can release the mouse while being over
2201 // a different window than the slider
2203 // if (gdk_event->window != widget->slider) return FALSE;
2205 g_blockEventsOnScroll
= false;
2207 if (win
->m_isScrolling
)
2209 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2213 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2214 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2216 value
= (int)(win
->m_hAdjust
->value
+0.5);
2219 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2221 value
= (int)(win
->m_vAdjust
->value
+0.5);
2225 wxScrollWinEvent
event( command
, value
, dir
);
2226 event
.SetEventObject( win
);
2227 win
->GetEventHandler()->ProcessEvent( event
);
2230 win
->m_isScrolling
= false;
2236 // ----------------------------------------------------------------------------
2237 // this wxWindowBase function is implemented here (in platform-specific file)
2238 // because it is static and so couldn't be made virtual
2239 // ----------------------------------------------------------------------------
2241 wxWindow
*wxWindowBase::DoFindFocus()
2243 // the cast is necessary when we compile in wxUniversal mode
2244 return (wxWindow
*)g_focusWindow
;
2247 //-----------------------------------------------------------------------------
2248 // "realize" from m_widget
2249 //-----------------------------------------------------------------------------
2251 /* We cannot set colours and fonts before the widget has
2252 been realized, so we do this directly after realization. */
2256 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2261 wxapp_install_idle_handler();
2265 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2266 gtk_im_context_set_client_window( win
->m_imData
->context
,
2267 pizza
->bin_window
);
2270 wxWindowCreateEvent
event( win
);
2271 event
.SetEventObject( win
);
2272 win
->GetEventHandler()->ProcessEvent( event
);
2276 //-----------------------------------------------------------------------------
2278 //-----------------------------------------------------------------------------
2282 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2283 GtkAllocation
*WXUNUSED(alloc
),
2287 wxapp_install_idle_handler();
2289 if (!win
->m_hasScrolling
) return;
2291 int client_width
= 0;
2292 int client_height
= 0;
2293 win
->GetClientSize( &client_width
, &client_height
);
2294 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2297 win
->m_oldClientWidth
= client_width
;
2298 win
->m_oldClientHeight
= client_height
;
2300 if (!win
->m_nativeSizeEvent
)
2302 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2303 event
.SetEventObject( win
);
2304 win
->GetEventHandler()->ProcessEvent( event
);
2311 #define WXUNUSED_UNLESS_XIM(param) param
2313 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2316 /* Resize XIM window */
2320 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2321 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2322 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2325 wxapp_install_idle_handler();
2331 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2335 gdk_window_get_size (widget
->window
, &width
, &height
);
2336 win
->m_icattr
->preedit_area
.width
= width
;
2337 win
->m_icattr
->preedit_area
.height
= height
;
2338 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2344 //-----------------------------------------------------------------------------
2345 // "realize" from m_wxwindow
2346 //-----------------------------------------------------------------------------
2348 /* Initialize XIM support */
2352 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2353 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2356 wxapp_install_idle_handler();
2359 if (win
->m_ic
) return;
2360 if (!widget
) return;
2361 if (!gdk_im_ready()) return;
2363 win
->m_icattr
= gdk_ic_attr_new();
2364 if (!win
->m_icattr
) return;
2368 GdkColormap
*colormap
;
2369 GdkICAttr
*attr
= win
->m_icattr
;
2370 unsigned attrmask
= GDK_IC_ALL_REQ
;
2372 GdkIMStyle supported_style
= (GdkIMStyle
)
2373 (GDK_IM_PREEDIT_NONE
|
2374 GDK_IM_PREEDIT_NOTHING
|
2375 GDK_IM_PREEDIT_POSITION
|
2376 GDK_IM_STATUS_NONE
|
2377 GDK_IM_STATUS_NOTHING
);
2379 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2380 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2382 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2383 attr
->client_window
= widget
->window
;
2385 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2386 gtk_widget_get_default_colormap ())
2388 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2389 attr
->preedit_colormap
= colormap
;
2392 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2393 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2394 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2395 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2397 switch (style
& GDK_IM_PREEDIT_MASK
)
2399 case GDK_IM_PREEDIT_POSITION
:
2400 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2402 g_warning ("over-the-spot style requires fontset");
2406 gdk_window_get_size (widget
->window
, &width
, &height
);
2408 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2409 attr
->spot_location
.x
= 0;
2410 attr
->spot_location
.y
= height
;
2411 attr
->preedit_area
.x
= 0;
2412 attr
->preedit_area
.y
= 0;
2413 attr
->preedit_area
.width
= width
;
2414 attr
->preedit_area
.height
= height
;
2415 attr
->preedit_fontset
= widget
->style
->font
;
2420 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2422 if (win
->m_ic
== NULL
)
2423 g_warning ("Can't create input context.");
2426 mask
= gdk_window_get_events (widget
->window
);
2427 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2428 gdk_window_set_events (widget
->window
, mask
);
2430 if (GTK_WIDGET_HAS_FOCUS(widget
))
2431 gdk_im_begin (win
->m_ic
, widget
->window
);
2437 //-----------------------------------------------------------------------------
2438 // InsertChild for wxWindowGTK.
2439 //-----------------------------------------------------------------------------
2441 /* Callback for wxWindowGTK. This very strange beast has to be used because
2442 * C++ has no virtual methods in a constructor. We have to emulate a
2443 * virtual function here as wxNotebook requires a different way to insert
2444 * a child in it. I had opted for creating a wxNotebookPage window class
2445 * which would have made this superfluous (such in the MDI window system),
2446 * but no-one was listening to me... */
2448 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2450 /* the window might have been scrolled already, do we
2451 have to adapt the position */
2452 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2453 child
->m_x
+= pizza
->xoffset
;
2454 child
->m_y
+= pizza
->yoffset
;
2456 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2457 GTK_WIDGET(child
->m_widget
),
2464 //-----------------------------------------------------------------------------
2466 //-----------------------------------------------------------------------------
2468 wxWindow
*wxGetActiveWindow()
2470 return wxWindow::FindFocus();
2474 wxMouseState
wxGetMouseState()
2480 GdkModifierType mask
;
2482 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2486 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2487 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2488 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2490 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2491 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2492 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2493 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2498 //-----------------------------------------------------------------------------
2500 //-----------------------------------------------------------------------------
2502 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2504 #ifdef __WXUNIVERSAL__
2505 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2507 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2508 #endif // __WXUNIVERSAL__/__WXGTK__
2510 void wxWindowGTK::Init()
2513 m_widget
= (GtkWidget
*) NULL
;
2514 m_wxwindow
= (GtkWidget
*) NULL
;
2515 m_focusWidget
= (GtkWidget
*) NULL
;
2525 m_needParent
= true;
2526 m_isBeingDeleted
= false;
2529 m_nativeSizeEvent
= false;
2531 m_hasScrolling
= false;
2532 m_isScrolling
= false;
2534 m_hAdjust
= (GtkAdjustment
*) NULL
;
2535 m_vAdjust
= (GtkAdjustment
*) NULL
;
2536 m_oldHorizontalPos
=
2537 m_oldVerticalPos
= 0.0;
2539 m_oldClientHeight
= 0;
2543 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2545 m_acceptsFocus
= false;
2548 m_clipPaintRegion
= false;
2550 m_needsStyleChange
= false;
2552 m_cursor
= *wxSTANDARD_CURSOR
;
2555 m_dirtyTabOrder
= false;
2558 wxWindowGTK::wxWindowGTK()
2563 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2568 const wxString
&name
)
2572 Create( parent
, id
, pos
, size
, style
, name
);
2575 bool wxWindowGTK::Create( wxWindow
*parent
,
2580 const wxString
&name
)
2582 if (!PreCreation( parent
, pos
, size
) ||
2583 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2585 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2589 m_insertCallback
= wxInsertChildInWindow
;
2591 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2592 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2594 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2596 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2597 scroll_class
->scrollbar_spacing
= 0;
2599 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2601 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2602 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2604 m_wxwindow
= gtk_pizza_new();
2606 #ifndef __WXUNIVERSAL__
2607 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2609 if (HasFlag(wxRAISED_BORDER
))
2611 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2613 else if (HasFlag(wxSUNKEN_BORDER
))
2615 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2617 else if (HasFlag(wxSIMPLE_BORDER
))
2619 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2623 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2625 #endif // __WXUNIVERSAL__
2627 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2629 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2630 m_acceptsFocus
= true;
2632 // I _really_ don't want scrollbars in the beginning
2633 m_vAdjust
->lower
= 0.0;
2634 m_vAdjust
->upper
= 1.0;
2635 m_vAdjust
->value
= 0.0;
2636 m_vAdjust
->step_increment
= 1.0;
2637 m_vAdjust
->page_increment
= 1.0;
2638 m_vAdjust
->page_size
= 5.0;
2639 g_signal_emit_by_name (m_vAdjust
, "changed");
2640 m_hAdjust
->lower
= 0.0;
2641 m_hAdjust
->upper
= 1.0;
2642 m_hAdjust
->value
= 0.0;
2643 m_hAdjust
->step_increment
= 1.0;
2644 m_hAdjust
->page_increment
= 1.0;
2645 m_hAdjust
->page_size
= 5.0;
2646 g_signal_emit_by_name (m_hAdjust
, "changed");
2648 // these handlers block mouse events to any window during scrolling such as
2649 // motion events and prevent GTK and wxWidgets from fighting over where the
2651 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2652 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2653 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2654 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2655 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2656 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2657 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2658 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2660 // these handlers get notified when screen updates are required either when
2661 // scrolling or when the window size (and therefore scrollbar configuration)
2664 g_signal_connect (m_hAdjust
, "value_changed",
2665 G_CALLBACK (gtk_window_hscroll_callback
), this);
2666 g_signal_connect (m_vAdjust
, "value_changed",
2667 G_CALLBACK (gtk_window_vscroll_callback
), this);
2669 gtk_widget_show( m_wxwindow
);
2672 m_parent
->DoAddChild( this );
2674 m_focusWidget
= m_wxwindow
;
2681 wxWindowGTK::~wxWindowGTK()
2685 if (g_focusWindow
== this)
2686 g_focusWindow
= NULL
;
2688 if ( g_delayedFocus
== this )
2689 g_delayedFocus
= NULL
;
2691 m_isBeingDeleted
= true;
2694 // destroy children before destroying this window itself
2697 // unhook focus handlers to prevent stray events being
2698 // propagated to this (soon to be) dead object
2699 if (m_focusWidget
!= NULL
)
2701 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2702 (gpointer
) gtk_window_focus_in_callback
,
2704 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2705 (gpointer
) gtk_window_focus_out_callback
,
2714 gdk_ic_destroy (m_ic
);
2716 gdk_ic_attr_destroy (m_icattr
);
2719 // delete before the widgets to avoid a crash on solaris
2724 gtk_widget_destroy( m_wxwindow
);
2725 m_wxwindow
= (GtkWidget
*) NULL
;
2730 gtk_widget_destroy( m_widget
);
2731 m_widget
= (GtkWidget
*) NULL
;
2735 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2737 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2739 // Use either the given size, or the default if -1 is given.
2740 // See wxWindowBase for these functions.
2741 m_width
= WidthDefault(size
.x
) ;
2742 m_height
= HeightDefault(size
.y
);
2750 void wxWindowGTK::PostCreation()
2752 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2758 // these get reported to wxWidgets -> wxPaintEvent
2760 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2762 g_signal_connect (m_wxwindow
, "expose_event",
2763 G_CALLBACK (gtk_window_expose_callback
), this);
2765 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2768 // Create input method handler
2769 m_imData
= new wxGtkIMData
;
2771 // Cannot handle drawing preedited text yet
2772 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2774 g_signal_connect (m_imData
->context
, "commit",
2775 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2777 // these are called when the "sunken" or "raised" borders are drawn
2778 g_signal_connect (m_widget
, "expose_event",
2779 G_CALLBACK (gtk_window_own_expose_callback
), this);
2784 if (!GTK_IS_WINDOW(m_widget
))
2786 if (m_focusWidget
== NULL
)
2787 m_focusWidget
= m_widget
;
2791 g_signal_connect (m_focusWidget
, "focus_in_event",
2792 G_CALLBACK (gtk_window_focus_in_callback
), this);
2793 g_signal_connect (m_focusWidget
, "focus_out_event",
2794 G_CALLBACK (gtk_window_focus_out_callback
), this);
2798 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2799 G_CALLBACK (gtk_window_focus_in_callback
), this);
2800 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2801 G_CALLBACK (gtk_window_focus_out_callback
), this);
2805 // connect to the various key and mouse handlers
2807 GtkWidget
*connect_widget
= GetConnectWidget();
2809 ConnectWidget( connect_widget
);
2811 /* We cannot set colours, fonts and cursors before the widget has
2812 been realized, so we do this directly after realization */
2813 g_signal_connect (connect_widget
, "realize",
2814 G_CALLBACK (gtk_window_realized_callback
), this);
2818 // Catch native resize events
2819 g_signal_connect (m_wxwindow
, "size_allocate",
2820 G_CALLBACK (gtk_window_size_callback
), this);
2822 // Initialize XIM support
2823 g_signal_connect (m_wxwindow
, "realize",
2824 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2826 // And resize XIM window
2827 g_signal_connect (m_wxwindow
, "size_allocate",
2828 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2831 if (GTK_IS_COMBO(m_widget
))
2833 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2835 g_signal_connect (gcombo
->entry
, "size_request",
2836 G_CALLBACK (wxgtk_combo_size_request_callback
),
2841 // This is needed if we want to add our windows into native
2842 // GTK controls, such as the toolbar. With this callback, the
2843 // toolbar gets to know the correct size (the one set by the
2844 // programmer). Sadly, it misbehaves for wxComboBox.
2845 g_signal_connect (m_widget
, "size_request",
2846 G_CALLBACK (wxgtk_window_size_request_callback
),
2850 InheritAttributes();
2854 // unless the window was created initially hidden (i.e. Hide() had been
2855 // called before Create()), we should show it at GTK+ level as well
2857 gtk_widget_show( m_widget
);
2860 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2862 g_signal_connect (widget
, "key_press_event",
2863 G_CALLBACK (gtk_window_key_press_callback
), this);
2864 g_signal_connect (widget
, "key_release_event",
2865 G_CALLBACK (gtk_window_key_release_callback
), this);
2866 g_signal_connect (widget
, "button_press_event",
2867 G_CALLBACK (gtk_window_button_press_callback
), this);
2868 g_signal_connect (widget
, "button_release_event",
2869 G_CALLBACK (gtk_window_button_release_callback
), this);
2870 g_signal_connect (widget
, "motion_notify_event",
2871 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2872 g_signal_connect (widget
, "scroll_event",
2873 G_CALLBACK (gtk_window_wheel_callback
), this);
2874 g_signal_connect (widget
, "popup_menu",
2875 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2876 g_signal_connect (widget
, "enter_notify_event",
2877 G_CALLBACK (gtk_window_enter_callback
), this);
2878 g_signal_connect (widget
, "leave_notify_event",
2879 G_CALLBACK (gtk_window_leave_callback
), this);
2882 bool wxWindowGTK::Destroy()
2884 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2888 return wxWindowBase::Destroy();
2891 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2893 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2896 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2898 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2899 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2902 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2905 if (m_resizing
) return; /* I don't like recursions */
2908 int currentX
, currentY
;
2909 GetPosition(¤tX
, ¤tY
);
2910 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2912 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2914 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2916 // calculate the best size if we should auto size the window
2917 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2918 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2920 const wxSize sizeBest
= GetBestSize();
2921 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2923 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2924 height
= sizeBest
.y
;
2932 int minWidth
= GetMinWidth(),
2933 minHeight
= GetMinHeight(),
2934 maxWidth
= GetMaxWidth(),
2935 maxHeight
= GetMaxHeight();
2937 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2938 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2939 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2940 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2942 #if wxUSE_TOOLBAR_NATIVE
2943 if (wxDynamicCast(GetParent(), wxToolBar
))
2945 // don't take the x,y values, they're wrong because toolbar sets them
2946 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2947 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2948 if (GTK_WIDGET_VISIBLE (widget
))
2949 gtk_widget_queue_resize (widget
);
2953 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2955 // don't set the size for children of wxNotebook, just take the values.
2963 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2964 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2966 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2967 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2971 m_x
= x
+ pizza
->xoffset
;
2972 m_y
= y
+ pizza
->yoffset
;
2975 int left_border
= 0;
2976 int right_border
= 0;
2978 int bottom_border
= 0;
2980 /* the default button has a border around it */
2981 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2983 GtkBorder
*default_border
= NULL
;
2984 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2987 left_border
+= default_border
->left
;
2988 right_border
+= default_border
->right
;
2989 top_border
+= default_border
->top
;
2990 bottom_border
+= default_border
->bottom
;
2991 g_free( default_border
);
2995 DoMoveWindow( m_x
-top_border
,
2997 m_width
+left_border
+right_border
,
2998 m_height
+top_border
+bottom_border
);
3003 /* Sometimes the client area changes size without the
3004 whole windows's size changing, but if the whole
3005 windows's size doesn't change, no wxSizeEvent will
3006 normally be sent. Here we add an extra test if
3007 the client test has been changed and this will
3009 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3013 wxPrintf( "OnSize sent from " );
3014 if (GetClassInfo() && GetClassInfo()->GetClassName())
3015 wxPrintf( GetClassInfo()->GetClassName() );
3016 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3019 if (!m_nativeSizeEvent
)
3021 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3022 event
.SetEventObject( this );
3023 GetEventHandler()->ProcessEvent( event
);
3029 void wxWindowGTK::OnInternalIdle()
3031 if ( m_dirtyTabOrder
)
3033 m_dirtyTabOrder
= false;
3037 // Update style if the window was not yet realized
3038 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3039 if (m_needsStyleChange
)
3041 SetBackgroundStyle(GetBackgroundStyle());
3042 m_needsStyleChange
= false;
3045 // Update invalidated regions.
3048 wxCursor cursor
= m_cursor
;
3049 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3053 /* I now set the cursor anew in every OnInternalIdle call
3054 as setting the cursor in a parent window also effects the
3055 windows above so that checking for the current cursor is
3060 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3062 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3064 if (!g_globalCursor
.Ok())
3065 cursor
= *wxSTANDARD_CURSOR
;
3067 window
= m_widget
->window
;
3068 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3069 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3075 GdkWindow
*window
= m_widget
->window
;
3076 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3077 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3082 if (wxUpdateUIEvent::CanUpdate(this))
3083 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3086 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3088 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3090 if (width
) (*width
) = m_width
;
3091 if (height
) (*height
) = m_height
;
3094 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3096 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3100 SetSize( width
, height
);
3107 #ifndef __WXUNIVERSAL__
3108 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3110 /* when using GTK 1.2 we set the shadow border size to 2 */
3114 if (HasFlag(wxSIMPLE_BORDER
))
3116 /* when using GTK 1.2 we set the simple border size to 1 */
3120 #endif // __WXUNIVERSAL__
3124 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3126 GtkRequisition vscroll_req
;
3127 vscroll_req
.width
= 2;
3128 vscroll_req
.height
= 2;
3129 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3130 (scroll_window
->vscrollbar
, &vscroll_req
);
3132 GtkRequisition hscroll_req
;
3133 hscroll_req
.width
= 2;
3134 hscroll_req
.height
= 2;
3135 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3136 (scroll_window
->hscrollbar
, &hscroll_req
);
3138 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3140 if (scroll_window
->vscrollbar_visible
)
3142 dw
+= vscroll_req
.width
;
3143 dw
+= scroll_class
->scrollbar_spacing
;
3146 if (scroll_window
->hscrollbar_visible
)
3148 dh
+= hscroll_req
.height
;
3149 dh
+= scroll_class
->scrollbar_spacing
;
3153 SetSize( width
+dw
, height
+dh
);
3157 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3159 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3163 if (width
) (*width
) = m_width
;
3164 if (height
) (*height
) = m_height
;
3171 #ifndef __WXUNIVERSAL__
3172 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3174 /* when using GTK 1.2 we set the shadow border size to 2 */
3178 if (HasFlag(wxSIMPLE_BORDER
))
3180 /* when using GTK 1.2 we set the simple border size to 1 */
3184 #endif // __WXUNIVERSAL__
3188 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3190 GtkRequisition vscroll_req
;
3191 vscroll_req
.width
= 2;
3192 vscroll_req
.height
= 2;
3193 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3194 (scroll_window
->vscrollbar
, &vscroll_req
);
3196 GtkRequisition hscroll_req
;
3197 hscroll_req
.width
= 2;
3198 hscroll_req
.height
= 2;
3199 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3200 (scroll_window
->hscrollbar
, &hscroll_req
);
3202 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3204 if (scroll_window
->vscrollbar_visible
)
3206 dw
+= vscroll_req
.width
;
3207 dw
+= scroll_class
->scrollbar_spacing
;
3210 if (scroll_window
->hscrollbar_visible
)
3212 dh
+= hscroll_req
.height
;
3213 dh
+= scroll_class
->scrollbar_spacing
;
3217 if (width
) (*width
) = m_width
- dw
;
3218 if (height
) (*height
) = m_height
- dh
;
3222 printf( "GetClientSize, name %s ", GetName().c_str() );
3223 if (width) printf( " width = %d", (*width) );
3224 if (height) printf( " height = %d", (*height) );
3229 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3231 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3235 if (m_parent
&& m_parent
->m_wxwindow
)
3237 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3238 dx
= pizza
->xoffset
;
3239 dy
= pizza
->yoffset
;
3242 if (x
) (*x
) = m_x
- dx
;
3243 if (y
) (*y
) = m_y
- dy
;
3246 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3248 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3250 if (!m_widget
->window
) return;
3252 GdkWindow
*source
= (GdkWindow
*) NULL
;
3254 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3256 source
= m_widget
->window
;
3260 gdk_window_get_origin( source
, &org_x
, &org_y
);
3264 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3266 org_x
+= m_widget
->allocation
.x
;
3267 org_y
+= m_widget
->allocation
.y
;
3275 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3277 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3279 if (!m_widget
->window
) return;
3281 GdkWindow
*source
= (GdkWindow
*) NULL
;
3283 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3285 source
= m_widget
->window
;
3289 gdk_window_get_origin( source
, &org_x
, &org_y
);
3293 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3295 org_x
+= m_widget
->allocation
.x
;
3296 org_y
+= m_widget
->allocation
.y
;
3304 bool wxWindowGTK::Show( bool show
)
3306 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3308 if (!wxWindowBase::Show(show
))
3315 gtk_widget_show( m_widget
);
3317 gtk_widget_hide( m_widget
);
3319 wxShowEvent
eventShow(GetId(), show
);
3320 eventShow
.SetEventObject(this);
3322 GetEventHandler()->ProcessEvent(eventShow
);
3327 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3329 win
->OnParentEnable(enable
);
3331 // Recurse, so that children have the opportunity to Do The Right Thing
3332 // and reset colours that have been messed up by a parent's (really ancestor's)
3334 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3336 node
= node
->GetNext() )
3338 wxWindow
*child
= node
->GetData();
3339 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3340 wxWindowNotifyEnable(child
, enable
);
3344 bool wxWindowGTK::Enable( bool enable
)
3346 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3348 if (!wxWindowBase::Enable(enable
))
3354 gtk_widget_set_sensitive( m_widget
, enable
);
3356 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3358 wxWindowNotifyEnable(this, enable
);
3363 int wxWindowGTK::GetCharHeight() const
3365 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3367 wxFont font
= GetFont();
3368 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3370 PangoContext
*context
= NULL
;
3372 context
= gtk_widget_get_pango_context( m_widget
);
3377 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3378 PangoLayout
*layout
= pango_layout_new(context
);
3379 pango_layout_set_font_description(layout
, desc
);
3380 pango_layout_set_text(layout
, "H", 1);
3381 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3383 PangoRectangle rect
;
3384 pango_layout_line_get_extents(line
, NULL
, &rect
);
3386 g_object_unref( G_OBJECT( layout
) );
3388 return (int) PANGO_PIXELS(rect
.height
);
3391 int wxWindowGTK::GetCharWidth() const
3393 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3395 wxFont font
= GetFont();
3396 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3398 PangoContext
*context
= NULL
;
3400 context
= gtk_widget_get_pango_context( m_widget
);
3405 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3406 PangoLayout
*layout
= pango_layout_new(context
);
3407 pango_layout_set_font_description(layout
, desc
);
3408 pango_layout_set_text(layout
, "g", 1);
3409 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3411 PangoRectangle rect
;
3412 pango_layout_line_get_extents(line
, NULL
, &rect
);
3414 g_object_unref( G_OBJECT( layout
) );
3416 return (int) PANGO_PIXELS(rect
.width
);
3419 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3423 int *externalLeading
,
3424 const wxFont
*theFont
) const
3426 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3428 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3437 PangoContext
*context
= NULL
;
3439 context
= gtk_widget_get_pango_context( m_widget
);
3448 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3449 PangoLayout
*layout
= pango_layout_new(context
);
3450 pango_layout_set_font_description(layout
, desc
);
3453 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3454 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3456 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3457 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3458 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3462 PangoRectangle rect
;
3463 pango_layout_get_extents(layout
, NULL
, &rect
);
3465 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3466 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3469 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3470 int baseline
= pango_layout_iter_get_baseline(iter
);
3471 pango_layout_iter_free(iter
);
3472 *descent
= *y
- PANGO_PIXELS(baseline
);
3474 if (externalLeading
) (*externalLeading
) = 0; // ??
3476 g_object_unref( G_OBJECT( layout
) );
3479 void wxWindowGTK::SetFocus()
3481 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3484 // don't do anything if we already have focus
3490 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3492 gtk_widget_grab_focus (m_wxwindow
);
3497 if (GTK_IS_CONTAINER(m_widget
))
3499 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3502 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3505 if (!GTK_WIDGET_REALIZED(m_widget
))
3507 // we can't set the focus to the widget now so we remember that
3508 // it should be focused and will do it later, during the idle
3509 // time, as soon as we can
3510 wxLogTrace(TRACE_FOCUS
,
3511 _T("Delaying setting focus to %s(%s)"),
3512 GetClassInfo()->GetClassName(), GetLabel().c_str());
3514 g_delayedFocus
= this;
3518 wxLogTrace(TRACE_FOCUS
,
3519 _T("Setting focus to %s(%s)"),
3520 GetClassInfo()->GetClassName(), GetLabel().c_str());
3522 gtk_widget_grab_focus (m_widget
);
3527 wxLogTrace(TRACE_FOCUS
,
3528 _T("Can't set focus to %s(%s)"),
3529 GetClassInfo()->GetClassName(), GetLabel().c_str());
3534 bool wxWindowGTK::AcceptsFocus() const
3536 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3539 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3541 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3543 wxWindowGTK
*oldParent
= m_parent
,
3544 *newParent
= (wxWindowGTK
*)newParentBase
;
3546 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3548 if ( !wxWindowBase::Reparent(newParent
) )
3551 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3553 /* prevent GTK from deleting the widget arbitrarily */
3554 gtk_widget_ref( m_widget
);
3558 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3561 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3565 /* insert GTK representation */
3566 (*(newParent
->m_insertCallback
))(newParent
, this);
3569 /* reverse: prevent GTK from deleting the widget arbitrarily */
3570 gtk_widget_unref( m_widget
);
3575 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3577 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3579 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3581 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3586 /* insert GTK representation */
3587 (*m_insertCallback
)(this, child
);
3590 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3592 wxWindowBase::AddChild(child
);
3593 m_dirtyTabOrder
= true;
3595 wxapp_install_idle_handler();
3598 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3600 wxWindowBase::RemoveChild(child
);
3601 m_dirtyTabOrder
= true;
3603 wxapp_install_idle_handler();
3606 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3608 wxWindowBase::DoMoveInTabOrder(win
, move
);
3609 m_dirtyTabOrder
= true;
3611 wxapp_install_idle_handler();
3614 void wxWindowGTK::RealizeTabOrder()
3618 if ( !m_children
.empty() )
3621 // we don't only construct the correct focus chain but also use
3622 // this opportunity to update the mnemonic widgets for all labels
3624 // it would be nice to extract this code from here and put it in
3625 // stattext.cpp to reduce dependencies but there is no really easy
3626 // way to do it unfortunately
3627 wxStaticText
*lastLabel
= NULL
;
3628 #endif // wxUSE_STATTEXT
3630 GList
*chain
= NULL
;
3632 for ( wxWindowList::const_iterator i
= m_children
.begin();
3633 i
!= m_children
.end();
3636 wxWindowGTK
*win
= *i
;
3640 if ( win
->AcceptsFocusFromKeyboard() )
3642 GtkLabel
*l
= GTK_LABEL(lastLabel
->m_widget
);
3643 gtk_label_set_mnemonic_widget(l
, win
->m_widget
);
3647 else // check if this one is a label
3649 lastLabel
= wxDynamicCast(win
, wxStaticText
);
3651 #endif // wxUSE_STATTEXT
3653 chain
= g_list_prepend(chain
, win
->m_widget
);
3656 chain
= g_list_reverse(chain
);
3658 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3663 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3668 void wxWindowGTK::Raise()
3670 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3672 if (m_wxwindow
&& m_wxwindow
->window
)
3674 gdk_window_raise( m_wxwindow
->window
);
3676 else if (m_widget
->window
)
3678 gdk_window_raise( m_widget
->window
);
3682 void wxWindowGTK::Lower()
3684 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3686 if (m_wxwindow
&& m_wxwindow
->window
)
3688 gdk_window_lower( m_wxwindow
->window
);
3690 else if (m_widget
->window
)
3692 gdk_window_lower( m_widget
->window
);
3696 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3698 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3700 if (cursor
== m_cursor
)
3704 wxapp_install_idle_handler();
3706 if (cursor
== wxNullCursor
)
3707 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3709 return wxWindowBase::SetCursor( cursor
);
3712 void wxWindowGTK::WarpPointer( int x
, int y
)
3714 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3716 // We provide this function ourselves as it is
3717 // missing in GDK (top of this file).
3719 GdkWindow
*window
= (GdkWindow
*) NULL
;
3721 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3723 window
= GetConnectWidget()->window
;
3726 gdk_window_warp_pointer( window
, x
, y
);
3729 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3731 double value_start
= adj
->value
;
3732 double value
= value_start
+ change
;
3733 double upper
= adj
->upper
- adj
->page_size
;
3738 // Lower bound will be checked by gtk_adjustment_set_value
3739 gtk_adjustment_set_value(adj
, value
);
3740 return adj
->value
!= value_start
;
3743 bool wxWindowGTK::ScrollLines(int lines
)
3746 m_vAdjust
!= NULL
&&
3747 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3750 bool wxWindowGTK::ScrollPages(int pages
)
3753 m_vAdjust
!= NULL
&&
3754 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3757 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3759 wxASSERT(m_vAdjust
== NULL
);
3763 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3767 if (!m_widget
->window
)
3772 GdkRectangle gdk_rect
,
3776 gdk_rect
.x
= rect
->x
;
3777 gdk_rect
.y
= rect
->y
;
3778 gdk_rect
.width
= rect
->width
;
3779 gdk_rect
.height
= rect
->height
;
3782 else // invalidate everything
3787 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3791 void wxWindowGTK::Update()
3795 // when we call Update() we really want to update the window immediately on
3796 // screen, even if it means flushing the entire queue and hence slowing down
3797 // everything -- but it should still be done, it's just that Update() should
3798 // be called very rarely
3802 void wxWindowGTK::GtkUpdate()
3804 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3805 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3807 // for consistency with other platforms (and also because it's convenient
3808 // to be able to update an entire TLW by calling Update() only once), we
3809 // should also update all our children here
3810 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3812 node
= node
->GetNext() )
3814 node
->GetData()->GtkUpdate();
3818 void wxWindowGTK::GtkSendPaintEvents()
3822 m_updateRegion
.Clear();
3826 // Clip to paint region in wxClientDC
3827 m_clipPaintRegion
= true;
3829 // widget to draw on
3830 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3832 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3834 // find ancestor from which to steal background
3835 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3837 parent
= (wxWindow
*)this;
3839 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3841 wxRegionIterator
upd( m_updateRegion
);
3845 rect
.x
= upd
.GetX();
3846 rect
.y
= upd
.GetY();
3847 rect
.width
= upd
.GetWidth();
3848 rect
.height
= upd
.GetHeight();
3850 gtk_paint_flat_box( parent
->m_widget
->style
,
3852 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3866 wxWindowDC
dc( (wxWindow
*)this );
3867 dc
.SetClippingRegion( m_updateRegion
);
3869 wxEraseEvent
erase_event( GetId(), &dc
);
3870 erase_event
.SetEventObject( this );
3872 GetEventHandler()->ProcessEvent(erase_event
);
3875 wxNcPaintEvent
nc_paint_event( GetId() );
3876 nc_paint_event
.SetEventObject( this );
3877 GetEventHandler()->ProcessEvent( nc_paint_event
);
3879 wxPaintEvent
paint_event( GetId() );
3880 paint_event
.SetEventObject( this );
3881 GetEventHandler()->ProcessEvent( paint_event
);
3883 m_clipPaintRegion
= false;
3885 m_updateRegion
.Clear();
3888 void wxWindowGTK::ClearBackground()
3890 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3894 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3896 wxWindowBase::DoSetToolTip(tip
);
3899 m_tooltip
->Apply( (wxWindow
*)this );
3902 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3904 wxString
tmp( tip
);
3905 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3907 #endif // wxUSE_TOOLTIPS
3909 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3911 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3913 if (!wxWindowBase::SetBackgroundColour(colour
))
3918 // We need the pixel value e.g. for background clearing.
3919 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3922 // apply style change (forceStyle=true so that new style is applied
3923 // even if the bg colour changed from valid to wxNullColour)
3924 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3925 ApplyWidgetStyle(true);
3930 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3932 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3934 if (!wxWindowBase::SetForegroundColour(colour
))
3941 // We need the pixel value e.g. for background clearing.
3942 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3945 // apply style change (forceStyle=true so that new style is applied
3946 // even if the bg colour changed from valid to wxNullColour):
3947 ApplyWidgetStyle(true);
3952 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3954 return gtk_widget_get_pango_context( m_widget
);
3957 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3959 // do we need to apply any changes at all?
3962 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3967 GtkRcStyle
*style
= gtk_rc_style_new();
3972 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3975 if ( m_foregroundColour
.Ok() )
3977 GdkColor
*fg
= m_foregroundColour
.GetColor();
3979 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3980 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3982 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3983 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3985 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3986 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3989 if ( m_backgroundColour
.Ok() )
3991 GdkColor
*bg
= m_backgroundColour
.GetColor();
3993 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3994 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3995 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3996 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3998 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3999 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4000 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4001 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4003 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4004 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4005 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4006 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4008 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4009 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4010 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4011 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4017 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4019 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4022 DoApplyWidgetStyle(style
);
4023 gtk_rc_style_unref(style
);
4026 // Style change may affect GTK+'s size calculation:
4027 InvalidateBestSize();
4030 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4033 gtk_widget_modify_style(m_wxwindow
, style
);
4035 gtk_widget_modify_style(m_widget
, style
);
4038 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4040 wxWindowBase::SetBackgroundStyle(style
);
4042 if (style
== wxBG_STYLE_CUSTOM
)
4044 GdkWindow
*window
= (GdkWindow
*) NULL
;
4046 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4048 window
= GetConnectWidget()->window
;
4052 // Make sure GDK/X11 doesn't refresh the window
4054 gdk_window_set_back_pixmap( window
, None
, False
);
4056 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4059 m_needsStyleChange
= false;
4062 // Do in OnIdle, because the window is not yet available
4063 m_needsStyleChange
= true;
4065 // Don't apply widget style, or we get a grey background
4069 // apply style change (forceStyle=true so that new style is applied
4070 // even if the bg colour changed from valid to wxNullColour):
4071 ApplyWidgetStyle(true);
4076 #if wxUSE_DRAG_AND_DROP
4078 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4080 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4082 GtkWidget
*dnd_widget
= GetConnectWidget();
4084 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4086 if (m_dropTarget
) delete m_dropTarget
;
4087 m_dropTarget
= dropTarget
;
4089 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4092 #endif // wxUSE_DRAG_AND_DROP
4094 GtkWidget
* wxWindowGTK::GetConnectWidget()
4096 GtkWidget
*connect_widget
= m_widget
;
4097 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4099 return connect_widget
;
4102 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4105 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4107 return (window
== m_widget
->window
);
4110 bool wxWindowGTK::SetFont( const wxFont
&font
)
4112 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4114 if (!wxWindowBase::SetFont(font
))
4117 // apply style change (forceStyle=true so that new style is applied
4118 // even if the font changed from valid to wxNullFont):
4119 ApplyWidgetStyle(true);
4124 void wxWindowGTK::DoCaptureMouse()
4126 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4128 GdkWindow
*window
= (GdkWindow
*) NULL
;
4130 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4132 window
= GetConnectWidget()->window
;
4134 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4136 wxCursor
* cursor
= & m_cursor
;
4138 cursor
= wxSTANDARD_CURSOR
;
4140 gdk_pointer_grab( window
, FALSE
,
4142 (GDK_BUTTON_PRESS_MASK
|
4143 GDK_BUTTON_RELEASE_MASK
|
4144 GDK_POINTER_MOTION_HINT_MASK
|
4145 GDK_POINTER_MOTION_MASK
),
4147 cursor
->GetCursor(),
4148 (guint32
)GDK_CURRENT_TIME
);
4149 g_captureWindow
= this;
4150 g_captureWindowHasMouse
= true;
4153 void wxWindowGTK::DoReleaseMouse()
4155 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4157 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4159 g_captureWindow
= (wxWindowGTK
*) NULL
;
4161 GdkWindow
*window
= (GdkWindow
*) NULL
;
4163 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4165 window
= GetConnectWidget()->window
;
4170 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4174 wxWindow
*wxWindowBase::GetCapture()
4176 return (wxWindow
*)g_captureWindow
;
4179 bool wxWindowGTK::IsRetained() const
4184 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4185 int range
, bool refresh
)
4187 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4189 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4191 m_hasScrolling
= true;
4193 if (orient
== wxHORIZONTAL
)
4195 float fpos
= (float)pos
;
4196 float frange
= (float)range
;
4197 float fthumb
= (float)thumbVisible
;
4198 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4199 if (fpos
< 0.0) fpos
= 0.0;
4201 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4202 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4204 SetScrollPos( orient
, pos
, refresh
);
4208 m_oldHorizontalPos
= fpos
;
4210 m_hAdjust
->lower
= 0.0;
4211 m_hAdjust
->upper
= frange
;
4212 m_hAdjust
->value
= fpos
;
4213 m_hAdjust
->step_increment
= 1.0;
4214 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4215 m_hAdjust
->page_size
= fthumb
;
4219 float fpos
= (float)pos
;
4220 float frange
= (float)range
;
4221 float fthumb
= (float)thumbVisible
;
4222 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4223 if (fpos
< 0.0) fpos
= 0.0;
4225 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4226 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4228 SetScrollPos( orient
, pos
, refresh
);
4232 m_oldVerticalPos
= fpos
;
4234 m_vAdjust
->lower
= 0.0;
4235 m_vAdjust
->upper
= frange
;
4236 m_vAdjust
->value
= fpos
;
4237 m_vAdjust
->step_increment
= 1.0;
4238 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4239 m_vAdjust
->page_size
= fthumb
;
4242 if (orient
== wxHORIZONTAL
)
4243 g_signal_emit_by_name (m_hAdjust
, "changed");
4245 g_signal_emit_by_name (m_vAdjust
, "changed");
4248 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4250 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4251 gpointer fn
= orient
== wxHORIZONTAL
4252 ? (gpointer
) gtk_window_hscroll_callback
4253 : (gpointer
) gtk_window_vscroll_callback
;
4255 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4256 g_signal_emit_by_name (adj
, "value_changed");
4257 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4260 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4262 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4263 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4265 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4267 float fpos
= (float)pos
;
4268 if (fpos
> adj
->upper
- adj
->page_size
)
4269 fpos
= adj
->upper
- adj
->page_size
;
4272 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4274 if (fabs(fpos
-adj
->value
) < 0.2)
4278 if ( m_wxwindow
->window
)
4283 int wxWindowGTK::GetScrollThumb( int orient
) const
4285 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4287 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4289 if (orient
== wxHORIZONTAL
)
4290 return (int)(m_hAdjust
->page_size
+0.5);
4292 return (int)(m_vAdjust
->page_size
+0.5);
4295 int wxWindowGTK::GetScrollPos( int orient
) const
4297 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4299 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4301 if (orient
== wxHORIZONTAL
)
4302 return (int)(m_hAdjust
->value
+0.5);
4304 return (int)(m_vAdjust
->value
+0.5);
4307 int wxWindowGTK::GetScrollRange( int orient
) const
4309 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4311 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4313 if (orient
== wxHORIZONTAL
)
4314 return (int)(m_hAdjust
->upper
+0.5);
4316 return (int)(m_vAdjust
->upper
+0.5);
4319 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4321 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4323 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4325 // No scrolling requested.
4326 if ((dx
== 0) && (dy
== 0)) return;
4328 m_clipPaintRegion
= true;
4330 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4332 m_clipPaintRegion
= false;
4335 void wxWindowGTK::SetWindowStyleFlag( long style
)
4337 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4338 wxWindowBase::SetWindowStyleFlag(style
);
4341 // Find the wxWindow at the current mouse position, also returning the mouse
4343 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4345 pt
= wxGetMousePosition();
4346 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4350 // Get the current mouse position.
4351 wxPoint
wxGetMousePosition()
4353 /* This crashes when used within wxHelpContext,
4354 so we have to use the X-specific implementation below.
4356 GdkModifierType *mask;
4357 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4359 return wxPoint(x, y);
4363 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4365 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4366 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4367 Window rootReturn
, childReturn
;
4368 int rootX
, rootY
, winX
, winY
;
4369 unsigned int maskReturn
;
4371 XQueryPointer (display
,
4375 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4376 return wxPoint(rootX
, rootY
);
4380 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4381 void wxAddGrab(wxWindow
* window
)
4383 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4386 void wxRemoveGrab(wxWindow
* window
)
4388 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4391 // ----------------------------------------------------------------------------
4393 // ----------------------------------------------------------------------------
4395 class wxWinModule
: public wxModule
4402 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4405 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4407 bool wxWinModule::OnInit()
4409 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4410 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4415 void wxWinModule::OnExit()
4418 gdk_gc_unref( g_eraseGC
);