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
);
848 wxGetMousePosition( &x
, &y
);
849 win
->ScreenToClient( &x
, &y
);
852 event
.SetEventObject( win
);
857 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
859 GdkEventKey
*gdk_event
)
861 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
862 // but only event->keyval which is quite useless to us, so remember
863 // the last character from GDK_KEY_PRESS and reuse it as last resort
865 // NB: should be MT-safe as we're always called from the main thread only
870 } s_lastKeyPress
= { 0, 0 };
872 KeySym keysym
= gdk_event
->keyval
;
874 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
875 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
879 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
883 // do we have the translation or is it a plain ASCII character?
884 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
886 // we should use keysym if it is ASCII as X does some translations
887 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
888 // which we don't want here (but which we do use for OnChar())
889 if ( !wxIsAsciiKeysym(keysym
) )
891 keysym
= (KeySym
)gdk_event
->string
[0];
894 // we want to always get the same key code when the same key is
895 // pressed regardless of the state of the modifiers, i.e. on a
896 // standard US keyboard pressing '5' or '%' ('5' key with
897 // Shift) should result in the same key code in OnKeyDown():
898 // '5' (although OnChar() will get either '5' or '%').
900 // to do it we first translate keysym to keycode (== scan code)
901 // and then back but always using the lower register
902 Display
*dpy
= (Display
*)wxGetDisplay();
903 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
905 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
907 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
909 // use the normalized, i.e. lower register, keysym if we've
911 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
913 // as explained above, we want to have lower register key codes
914 // normally but for the letter keys we want to have the upper ones
916 // NB: don't use XConvertCase() here, we want to do it for letters
918 key_code
= toupper(key_code
);
920 else // non ASCII key, what to do?
922 // by default, ignore it
925 // but if we have cached information from the last KEY_PRESS
926 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
929 if ( keysym
== s_lastKeyPress
.keysym
)
931 key_code
= s_lastKeyPress
.keycode
;
936 if ( gdk_event
->type
== GDK_KEY_PRESS
)
938 // remember it to be reused for KEY_UP event later
939 s_lastKeyPress
.keysym
= keysym
;
940 s_lastKeyPress
.keycode
= key_code
;
944 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
946 // sending unknown key events doesn't really make sense
950 // now fill all the other fields
951 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
953 event
.m_keyCode
= key_code
;
955 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
957 event
.m_uniChar
= key_code
;
967 GtkIMContext
*context
;
968 GdkEventKey
*lastKeyEvent
;
972 context
= gtk_im_multicontext_new();
977 g_object_unref(context
);
983 gtk_window_key_press_callback( GtkWidget
*widget
,
984 GdkEventKey
*gdk_event
,
990 wxapp_install_idle_handler();
994 if (g_blockEventsOnDrag
)
998 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1000 bool return_after_IM
= false;
1002 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1004 // Emit KEY_DOWN event
1005 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1009 // Return after IM processing as we cannot do
1010 // anything with it anyhow.
1011 return_after_IM
= true;
1014 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1015 // When we get a key_press event here, it could be originate
1016 // from the current widget or its child widgets. However, only the widget
1017 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1018 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1019 // originated from its child widgets and shouldn't be passed to IM context.
1020 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1021 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1022 // widgets has both IM context and input focus, the event should be filtered
1023 // by gtk_im_context_filter_keypress().
1024 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1025 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1027 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1028 // docs, if IM filter returns true, no further processing should be done.
1029 // we should send the key_down event anyway.
1030 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1031 win
->m_imData
->lastKeyEvent
= NULL
;
1032 if (intercepted_by_IM
)
1034 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1039 if (return_after_IM
)
1045 wxWindowGTK
*ancestor
= win
;
1048 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1051 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1052 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1055 if (ancestor
->IsTopLevel())
1057 ancestor
= ancestor
->GetParent();
1060 #endif // wxUSE_ACCEL
1062 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1063 // will only be sent if it is not in an accelerator table.
1067 KeySym keysym
= gdk_event
->keyval
;
1068 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1069 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1072 if ( wxIsAsciiKeysym(keysym
) )
1075 key_code
= (unsigned char)keysym
;
1077 // gdk_event->string is actually deprecated
1078 else if ( gdk_event
->length
== 1 )
1080 key_code
= (unsigned char)gdk_event
->string
[0];
1086 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1088 event
.m_keyCode
= key_code
;
1090 // To conform to the docs we need to translate Ctrl-alpha
1091 // characters to values in the range 1-26.
1092 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1094 event
.m_keyCode
= key_code
- 'a' + 1;
1096 event
.m_uniChar
= event
.m_keyCode
;
1100 // Implement OnCharHook by checking ancestor top level windows
1101 wxWindow
*parent
= win
;
1102 while (parent
&& !parent
->IsTopLevel())
1103 parent
= parent
->GetParent();
1106 event
.SetEventType( wxEVT_CHAR_HOOK
);
1107 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1112 event
.SetEventType(wxEVT_CHAR
);
1113 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1122 // win is a control: tab can be propagated up
1124 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1125 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1126 // have this style, yet choose not to process this particular TAB in which
1127 // case TAB must still work as a navigational character
1128 // JS: enabling again to make consistent with other platforms
1129 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1130 // navigation behaviour)
1132 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1134 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1136 wxNavigationKeyEvent new_event
;
1137 new_event
.SetEventObject( win
->GetParent() );
1138 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1139 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1140 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1141 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1142 new_event
.SetCurrentFocus( win
);
1143 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1146 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1148 (gdk_event
->keyval
== GDK_Escape
) )
1150 // however only do it if we have a Cancel button in the dialog,
1151 // otherwise the user code may get confused by the events from a
1152 // non-existing button and, worse, a wxButton might get button event
1153 // from another button which is not really expected
1154 wxWindow
*winForCancel
= win
,
1156 while ( winForCancel
)
1158 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1161 // found a cancel button
1165 if ( winForCancel
->IsTopLevel() )
1167 // no need to look further
1171 // maybe our parent has a cancel button?
1172 winForCancel
= winForCancel
->GetParent();
1177 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1178 eventClick
.SetEventObject(btnCancel
);
1179 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1185 g_signal_stop_emission_by_name (widget
, "key_press_event");
1195 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1199 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1201 // take modifiers, cursor position, timestamp etc. from the last
1202 // key_press_event that was fed into Input Method:
1203 if (window
->m_imData
->lastKeyEvent
)
1205 wxFillOtherKeyEventFields(event
,
1206 window
, window
->m_imData
->lastKeyEvent
);
1210 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1212 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1213 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1214 #endif // wxUSE_UNICODE
1215 if( !(const wxChar
*)data
)
1220 // Implement OnCharHook by checking ancestor top level windows
1221 wxWindow
*parent
= window
;
1222 while (parent
&& !parent
->IsTopLevel())
1223 parent
= parent
->GetParent();
1225 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1228 event
.m_uniChar
= *pstr
;
1229 // Backward compatible for ISO-8859-1
1230 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1231 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1233 event
.m_keyCode
= *pstr
;
1234 #endif // wxUSE_UNICODE
1236 // To conform to the docs we need to translate Ctrl-alpha
1237 // characters to values in the range 1-26.
1238 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1240 event
.m_keyCode
= *pstr
- 'a' + 1;
1242 event
.m_uniChar
= event
.m_keyCode
;
1248 event
.SetEventType( wxEVT_CHAR_HOOK
);
1249 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1254 event
.SetEventType(wxEVT_CHAR
);
1255 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1262 //-----------------------------------------------------------------------------
1263 // "key_release_event" from any window
1264 //-----------------------------------------------------------------------------
1268 gtk_window_key_release_callback( GtkWidget
*widget
,
1269 GdkEventKey
*gdk_event
,
1275 wxapp_install_idle_handler();
1280 if (g_blockEventsOnDrag
)
1283 wxKeyEvent
event( wxEVT_KEY_UP
);
1284 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1286 // unknown key pressed, ignore (the event would be useless anyhow)
1290 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1293 g_signal_stop_emission_by_name (widget
, "key_release_event");
1298 // ============================================================================
1300 // ============================================================================
1302 // ----------------------------------------------------------------------------
1303 // mouse event processing helpers
1304 // ----------------------------------------------------------------------------
1306 // init wxMouseEvent with the info from GdkEventXXX struct
1307 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1308 wxMouseEvent
& event
,
1311 event
.SetTimestamp( gdk_event
->time
);
1312 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1313 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1314 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1315 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1316 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1317 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1318 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1319 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1321 event
.m_linesPerAction
= 3;
1322 event
.m_wheelDelta
= 120;
1323 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1324 event
.m_wheelRotation
= 120;
1325 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1326 event
.m_wheelRotation
= -120;
1329 wxPoint pt
= win
->GetClientAreaOrigin();
1330 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1331 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1333 event
.SetEventObject( win
);
1334 event
.SetId( win
->GetId() );
1335 event
.SetTimestamp( gdk_event
->time
);
1338 static void AdjustEventButtonState(wxMouseEvent
& event
)
1340 // GDK reports the old state of the button for a button press event, but
1341 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1342 // for a LEFT_DOWN event, not FALSE, so we will invert
1343 // left/right/middleDown for the corresponding click events
1345 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1346 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1347 (event
.GetEventType() == wxEVT_LEFT_UP
))
1349 event
.m_leftDown
= !event
.m_leftDown
;
1353 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1354 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1355 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1357 event
.m_middleDown
= !event
.m_middleDown
;
1361 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1362 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1363 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1365 event
.m_rightDown
= !event
.m_rightDown
;
1370 // find the window to send the mouse event too
1372 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1377 if (win
->m_wxwindow
)
1379 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1380 xx
+= pizza
->xoffset
;
1381 yy
+= pizza
->yoffset
;
1384 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1387 wxWindowGTK
*child
= node
->GetData();
1389 node
= node
->GetNext();
1390 if (!child
->IsShown())
1393 if (child
->IsTransparentForMouse())
1395 // wxStaticBox is transparent in the box itself
1396 int xx1
= child
->m_x
;
1397 int yy1
= child
->m_y
;
1398 int xx2
= child
->m_x
+ child
->m_width
;
1399 int yy2
= child
->m_y
+ child
->m_height
;
1402 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1404 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1406 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1408 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1419 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1420 (child
->m_x
<= xx
) &&
1421 (child
->m_y
<= yy
) &&
1422 (child
->m_x
+child
->m_width
>= xx
) &&
1423 (child
->m_y
+child
->m_height
>= yy
))
1436 //-----------------------------------------------------------------------------
1437 // "button_press_event"
1438 //-----------------------------------------------------------------------------
1442 gtk_window_button_press_callback( GtkWidget
*widget
,
1443 GdkEventButton
*gdk_event
,
1449 wxapp_install_idle_handler();
1452 wxPrintf( wxT("1) OnButtonPress from ") );
1453 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1454 wxPrintf( win->GetClassInfo()->GetClassName() );
1455 wxPrintf( wxT(".\n") );
1457 if (!win
->m_hasVMT
) return FALSE
;
1458 if (g_blockEventsOnDrag
) return TRUE
;
1459 if (g_blockEventsOnScroll
) return TRUE
;
1461 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1463 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1465 gtk_widget_grab_focus( win
->m_wxwindow
);
1467 wxPrintf( wxT("GrabFocus from ") );
1468 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1469 wxPrintf( win->GetClassInfo()->GetClassName() );
1470 wxPrintf( wxT(".\n") );
1474 // GDK sends surplus button down events
1475 // before a double click event. We
1476 // need to filter these out.
1477 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1479 GdkEvent
*peek_event
= gdk_event_peek();
1482 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1483 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1485 gdk_event_free( peek_event
);
1490 gdk_event_free( peek_event
);
1495 wxEventType event_type
= wxEVT_NULL
;
1497 // GdkDisplay is a GTK+ 2.2.0 thing
1498 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1499 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1500 !gtk_check_version(2,2,0) &&
1501 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1503 // Reset GDK internal timestamp variables in order to disable GDK
1504 // triple click events. GDK will then next time believe no button has
1505 // been clicked just before, and send a normal button click event.
1506 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1507 display
->button_click_time
[1] = 0;
1508 display
->button_click_time
[0] = 0;
1512 if (gdk_event
->button
== 1)
1514 // note that GDK generates triple click events which are not supported
1515 // by wxWidgets but still have to be passed to the app as otherwise
1516 // clicks would simply go missing
1517 switch (gdk_event
->type
)
1519 // we shouldn't get triple clicks at all for GTK2 because we
1520 // suppress them artificially using the code above but we still
1521 // should map them to something for GTK1 and not just ignore them
1522 // as this would lose clicks
1523 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1524 case GDK_BUTTON_PRESS
:
1525 event_type
= wxEVT_LEFT_DOWN
;
1528 case GDK_2BUTTON_PRESS
:
1529 event_type
= wxEVT_LEFT_DCLICK
;
1533 // just to silence gcc warnings
1537 else if (gdk_event
->button
== 2)
1539 switch (gdk_event
->type
)
1541 case GDK_3BUTTON_PRESS
:
1542 case GDK_BUTTON_PRESS
:
1543 event_type
= wxEVT_MIDDLE_DOWN
;
1546 case GDK_2BUTTON_PRESS
:
1547 event_type
= wxEVT_MIDDLE_DCLICK
;
1554 else if (gdk_event
->button
== 3)
1556 switch (gdk_event
->type
)
1558 case GDK_3BUTTON_PRESS
:
1559 case GDK_BUTTON_PRESS
:
1560 event_type
= wxEVT_RIGHT_DOWN
;
1563 case GDK_2BUTTON_PRESS
:
1564 event_type
= wxEVT_RIGHT_DCLICK
;
1571 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1573 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1575 event_type
= wxEVT_MOUSEWHEEL
;
1579 if ( event_type
== wxEVT_NULL
)
1581 // unknown mouse button or click type
1585 wxMouseEvent
event( event_type
);
1586 InitMouseEvent( win
, event
, gdk_event
);
1588 AdjustEventButtonState(event
);
1590 // wxListBox actually gets mouse events from the item, so we need to give it
1591 // a chance to correct this
1592 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1594 // find the correct window to send the event to: it may be a different one
1595 // from the one which got it at GTK+ level because some controls don't have
1596 // their own X window and thus cannot get any events.
1597 if ( !g_captureWindow
)
1598 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1600 if (win
->GetEventHandler()->ProcessEvent( event
))
1602 g_signal_stop_emission_by_name (widget
, "button_press_event");
1606 if (event_type
== wxEVT_RIGHT_DOWN
)
1608 // generate a "context menu" event: this is similar to right mouse
1609 // click under many GUIs except that it is generated differently
1610 // (right up under MSW, ctrl-click under Mac, right down here) and
1612 // (a) it's a command event and so is propagated to the parent
1613 // (b) under some ports it can be generated from kbd too
1614 // (c) it uses screen coords (because of (a))
1615 wxContextMenuEvent
evtCtx(
1618 win
->ClientToScreen(event
.GetPosition()));
1619 evtCtx
.SetEventObject(win
);
1620 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1627 //-----------------------------------------------------------------------------
1628 // "button_release_event"
1629 //-----------------------------------------------------------------------------
1633 gtk_window_button_release_callback( GtkWidget
*widget
,
1634 GdkEventButton
*gdk_event
,
1640 wxapp_install_idle_handler();
1642 if (!win
->m_hasVMT
) return FALSE
;
1643 if (g_blockEventsOnDrag
) return FALSE
;
1644 if (g_blockEventsOnScroll
) return FALSE
;
1646 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1648 wxEventType event_type
= wxEVT_NULL
;
1650 switch (gdk_event
->button
)
1653 event_type
= wxEVT_LEFT_UP
;
1657 event_type
= wxEVT_MIDDLE_UP
;
1661 event_type
= wxEVT_RIGHT_UP
;
1665 // unknwon button, don't process
1669 wxMouseEvent
event( event_type
);
1670 InitMouseEvent( win
, event
, gdk_event
);
1672 AdjustEventButtonState(event
);
1674 // same wxListBox hack as above
1675 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1677 if ( !g_captureWindow
)
1678 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1680 if (win
->GetEventHandler()->ProcessEvent( event
))
1682 g_signal_stop_emission_by_name (widget
, "button_release_event");
1690 //-----------------------------------------------------------------------------
1691 // "motion_notify_event"
1692 //-----------------------------------------------------------------------------
1696 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1697 GdkEventMotion
*gdk_event
,
1703 wxapp_install_idle_handler();
1705 if (!win
->m_hasVMT
) return FALSE
;
1706 if (g_blockEventsOnDrag
) return FALSE
;
1707 if (g_blockEventsOnScroll
) return FALSE
;
1709 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1711 if (gdk_event
->is_hint
)
1715 GdkModifierType state
;
1716 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1722 printf( "OnMotion from " );
1723 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1724 printf( win->GetClassInfo()->GetClassName() );
1728 wxMouseEvent
event( wxEVT_MOTION
);
1729 InitMouseEvent(win
, event
, gdk_event
);
1731 if ( g_captureWindow
)
1733 // synthetize a mouse enter or leave event if needed
1734 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1735 // This seems to be necessary and actually been added to
1736 // GDK itself in version 2.0.X
1739 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1740 if ( hasMouse
!= g_captureWindowHasMouse
)
1742 // the mouse changed window
1743 g_captureWindowHasMouse
= hasMouse
;
1745 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1746 : wxEVT_LEAVE_WINDOW
);
1747 InitMouseEvent(win
, eventM
, gdk_event
);
1748 eventM
.SetEventObject(win
);
1749 win
->GetEventHandler()->ProcessEvent(eventM
);
1754 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1757 if ( !g_captureWindow
)
1759 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1760 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1762 // Rewrite cursor handling here (away from idle).
1766 if (win
->GetEventHandler()->ProcessEvent( event
))
1768 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1776 //-----------------------------------------------------------------------------
1777 // "mouse_wheel_event"
1778 //-----------------------------------------------------------------------------
1782 gtk_window_wheel_callback (GtkWidget
* widget
,
1783 GdkEventScroll
* gdk_event
,
1789 wxapp_install_idle_handler();
1791 wxEventType event_type
= wxEVT_NULL
;
1792 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1793 event_type
= wxEVT_MOUSEWHEEL
;
1794 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1795 event_type
= wxEVT_MOUSEWHEEL
;
1799 wxMouseEvent
event( event_type
);
1800 // Can't use InitMouse macro because scroll events don't have button
1801 event
.SetTimestamp( gdk_event
->time
);
1802 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1803 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1804 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1805 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1806 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1807 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1808 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1809 event
.m_linesPerAction
= 3;
1810 event
.m_wheelDelta
= 120;
1811 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1812 event
.m_wheelRotation
= 120;
1814 event
.m_wheelRotation
= -120;
1816 wxPoint pt
= win
->GetClientAreaOrigin();
1817 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1818 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1820 event
.SetEventObject( win
);
1821 event
.SetId( win
->GetId() );
1822 event
.SetTimestamp( gdk_event
->time
);
1824 if (win
->GetEventHandler()->ProcessEvent( event
))
1826 g_signal_stop_emission_by_name (widget
, "scroll_event");
1834 //-----------------------------------------------------------------------------
1836 //-----------------------------------------------------------------------------
1838 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1840 wxContextMenuEvent
event(
1844 event
.SetEventObject(win
);
1845 return win
->GetEventHandler()->ProcessEvent(event
);
1849 //-----------------------------------------------------------------------------
1851 //-----------------------------------------------------------------------------
1853 // send the wxChildFocusEvent and wxFocusEvent, common code of
1854 // gtk_window_focus_in_callback() and SetFocus()
1855 static bool DoSendFocusEvents(wxWindow
*win
)
1857 // Notify the parent keeping track of focus for the kbd navigation
1858 // purposes that we got it.
1859 wxChildFocusEvent
eventChildFocus(win
);
1860 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1862 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1863 eventFocus
.SetEventObject(win
);
1865 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1870 gtk_window_focus_in_callback( GtkWidget
*widget
,
1871 GdkEventFocus
*WXUNUSED(event
),
1877 wxapp_install_idle_handler();
1880 gtk_im_context_focus_in(win
->m_imData
->context
);
1883 g_focusWindow
= win
;
1885 wxLogTrace(TRACE_FOCUS
,
1886 _T("%s: focus in"), win
->GetName().c_str());
1890 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1894 // caret needs to be informed about focus change
1895 wxCaret
*caret
= win
->GetCaret();
1898 caret
->OnSetFocus();
1900 #endif // wxUSE_CARET
1902 gboolean ret
= FALSE
;
1904 // does the window itself think that it has the focus?
1905 if ( !win
->m_hasFocus
)
1907 // not yet, notify it
1908 win
->m_hasFocus
= true;
1910 (void)DoSendFocusEvents(win
);
1915 // Disable default focus handling for custom windows
1916 // since the default GTK+ handler issues a repaint
1917 if (win
->m_wxwindow
)
1924 //-----------------------------------------------------------------------------
1925 // "focus_out_event"
1926 //-----------------------------------------------------------------------------
1930 gtk_window_focus_out_callback( GtkWidget
*widget
,
1931 GdkEventFocus
*gdk_event
,
1937 wxapp_install_idle_handler();
1940 gtk_im_context_focus_out(win
->m_imData
->context
);
1942 wxLogTrace( TRACE_FOCUS
,
1943 _T("%s: focus out"), win
->GetName().c_str() );
1946 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1950 g_focusWindow
= (wxWindowGTK
*)NULL
;
1958 // caret needs to be informed about focus change
1959 wxCaret
*caret
= win
->GetCaret();
1962 caret
->OnKillFocus();
1964 #endif // wxUSE_CARET
1966 gboolean ret
= FALSE
;
1968 // don't send the window a kill focus event if it thinks that it doesn't
1969 // have focus already
1970 if ( win
->m_hasFocus
)
1972 win
->m_hasFocus
= false;
1974 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1975 event
.SetEventObject( win
);
1977 (void)win
->GetEventHandler()->ProcessEvent( event
);
1982 // Disable default focus handling for custom windows
1983 // since the default GTK+ handler issues a repaint
1984 if (win
->m_wxwindow
)
1991 //-----------------------------------------------------------------------------
1992 // "enter_notify_event"
1993 //-----------------------------------------------------------------------------
1997 gtk_window_enter_callback( GtkWidget
*widget
,
1998 GdkEventCrossing
*gdk_event
,
2004 wxapp_install_idle_handler();
2006 if (!win
->m_hasVMT
) return FALSE
;
2007 if (g_blockEventsOnDrag
) return FALSE
;
2009 // Event was emitted after a grab
2010 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2012 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2016 GdkModifierType state
= (GdkModifierType
)0;
2018 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2020 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2021 InitMouseEvent(win
, event
, gdk_event
);
2022 wxPoint pt
= win
->GetClientAreaOrigin();
2023 event
.m_x
= x
+ pt
.x
;
2024 event
.m_y
= y
+ pt
.y
;
2026 if ( !g_captureWindow
)
2028 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2029 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2031 // Rewrite cursor handling here (away from idle).
2035 if (win
->GetEventHandler()->ProcessEvent( event
))
2037 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2045 //-----------------------------------------------------------------------------
2046 // "leave_notify_event"
2047 //-----------------------------------------------------------------------------
2051 gtk_window_leave_callback( GtkWidget
*widget
,
2052 GdkEventCrossing
*gdk_event
,
2058 wxapp_install_idle_handler();
2060 if (!win
->m_hasVMT
) return FALSE
;
2061 if (g_blockEventsOnDrag
) return FALSE
;
2063 // Event was emitted after an ungrab
2064 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2066 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2068 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2069 event
.SetTimestamp( gdk_event
->time
);
2070 event
.SetEventObject( win
);
2074 GdkModifierType state
= (GdkModifierType
)0;
2076 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2078 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2079 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2080 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2081 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2082 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2083 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2084 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2086 wxPoint pt
= win
->GetClientAreaOrigin();
2087 event
.m_x
= x
+ pt
.x
;
2088 event
.m_y
= y
+ pt
.y
;
2090 if (win
->GetEventHandler()->ProcessEvent( event
))
2092 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2100 //-----------------------------------------------------------------------------
2101 // "value_changed" from m_vAdjust
2102 //-----------------------------------------------------------------------------
2105 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2111 wxapp_install_idle_handler();
2113 if (g_blockEventsOnDrag
) return;
2115 if (!win
->m_hasVMT
) return;
2117 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2118 if (fabs(diff
) < 0.2) return;
2120 win
->m_oldVerticalPos
= adjust
->value
;
2122 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2124 int value
= (int)(adjust
->value
+0.5);
2126 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2127 event
.SetEventObject( win
);
2128 win
->GetEventHandler()->ProcessEvent( event
);
2132 //-----------------------------------------------------------------------------
2133 // "value_changed" from m_hAdjust
2134 //-----------------------------------------------------------------------------
2137 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2143 wxapp_install_idle_handler();
2145 if (g_blockEventsOnDrag
) return;
2146 if (!win
->m_hasVMT
) return;
2148 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2149 if (fabs(diff
) < 0.2) return;
2151 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2153 win
->m_oldHorizontalPos
= adjust
->value
;
2155 int value
= (int)(adjust
->value
+0.5);
2157 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2158 event
.SetEventObject( win
);
2159 win
->GetEventHandler()->ProcessEvent( event
);
2163 //-----------------------------------------------------------------------------
2164 // "button_press_event" from scrollbar
2165 //-----------------------------------------------------------------------------
2169 gtk_scrollbar_button_press_callback( GtkWidget
*widget
,
2170 GdkEventButton
*gdk_event
,
2176 wxapp_install_idle_handler();
2179 g_blockEventsOnScroll
= true;
2181 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2183 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2190 //-----------------------------------------------------------------------------
2191 // "button_release_event" from scrollbar
2192 //-----------------------------------------------------------------------------
2196 gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2197 GdkEventButton
*WXUNUSED(gdk_event
),
2202 // don't test here as we can release the mouse while being over
2203 // a different window than the slider
2205 // if (gdk_event->window != widget->slider) return FALSE;
2207 g_blockEventsOnScroll
= false;
2209 if (win
->m_isScrolling
)
2211 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2215 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2216 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2218 value
= (int)(win
->m_hAdjust
->value
+0.5);
2221 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2223 value
= (int)(win
->m_vAdjust
->value
+0.5);
2227 wxScrollWinEvent
event( command
, value
, dir
);
2228 event
.SetEventObject( win
);
2229 win
->GetEventHandler()->ProcessEvent( event
);
2232 win
->m_isScrolling
= false;
2238 // ----------------------------------------------------------------------------
2239 // this wxWindowBase function is implemented here (in platform-specific file)
2240 // because it is static and so couldn't be made virtual
2241 // ----------------------------------------------------------------------------
2243 wxWindow
*wxWindowBase::DoFindFocus()
2245 // the cast is necessary when we compile in wxUniversal mode
2246 return (wxWindow
*)g_focusWindow
;
2249 //-----------------------------------------------------------------------------
2250 // "realize" from m_widget
2251 //-----------------------------------------------------------------------------
2253 /* We cannot set colours and fonts before the widget has
2254 been realized, so we do this directly after realization. */
2258 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2263 wxapp_install_idle_handler();
2267 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2268 gtk_im_context_set_client_window( win
->m_imData
->context
,
2269 pizza
->bin_window
);
2272 wxWindowCreateEvent
event( win
);
2273 event
.SetEventObject( win
);
2274 win
->GetEventHandler()->ProcessEvent( event
);
2278 //-----------------------------------------------------------------------------
2280 //-----------------------------------------------------------------------------
2284 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2285 GtkAllocation
*WXUNUSED(alloc
),
2289 wxapp_install_idle_handler();
2291 if (!win
->m_hasScrolling
) return;
2293 int client_width
= 0;
2294 int client_height
= 0;
2295 win
->GetClientSize( &client_width
, &client_height
);
2296 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2299 win
->m_oldClientWidth
= client_width
;
2300 win
->m_oldClientHeight
= client_height
;
2302 if (!win
->m_nativeSizeEvent
)
2304 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2305 event
.SetEventObject( win
);
2306 win
->GetEventHandler()->ProcessEvent( event
);
2313 #define WXUNUSED_UNLESS_XIM(param) param
2315 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2318 /* Resize XIM window */
2322 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2323 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2324 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2327 wxapp_install_idle_handler();
2333 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2337 gdk_window_get_size (widget
->window
, &width
, &height
);
2338 win
->m_icattr
->preedit_area
.width
= width
;
2339 win
->m_icattr
->preedit_area
.height
= height
;
2340 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2346 //-----------------------------------------------------------------------------
2347 // "realize" from m_wxwindow
2348 //-----------------------------------------------------------------------------
2350 /* Initialize XIM support */
2354 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2355 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2358 wxapp_install_idle_handler();
2361 if (win
->m_ic
) return;
2362 if (!widget
) return;
2363 if (!gdk_im_ready()) return;
2365 win
->m_icattr
= gdk_ic_attr_new();
2366 if (!win
->m_icattr
) return;
2370 GdkColormap
*colormap
;
2371 GdkICAttr
*attr
= win
->m_icattr
;
2372 unsigned attrmask
= GDK_IC_ALL_REQ
;
2374 GdkIMStyle supported_style
= (GdkIMStyle
)
2375 (GDK_IM_PREEDIT_NONE
|
2376 GDK_IM_PREEDIT_NOTHING
|
2377 GDK_IM_PREEDIT_POSITION
|
2378 GDK_IM_STATUS_NONE
|
2379 GDK_IM_STATUS_NOTHING
);
2381 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2382 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2384 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2385 attr
->client_window
= widget
->window
;
2387 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2388 gtk_widget_get_default_colormap ())
2390 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2391 attr
->preedit_colormap
= colormap
;
2394 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2395 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2396 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2397 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2399 switch (style
& GDK_IM_PREEDIT_MASK
)
2401 case GDK_IM_PREEDIT_POSITION
:
2402 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2404 g_warning ("over-the-spot style requires fontset");
2408 gdk_window_get_size (widget
->window
, &width
, &height
);
2410 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2411 attr
->spot_location
.x
= 0;
2412 attr
->spot_location
.y
= height
;
2413 attr
->preedit_area
.x
= 0;
2414 attr
->preedit_area
.y
= 0;
2415 attr
->preedit_area
.width
= width
;
2416 attr
->preedit_area
.height
= height
;
2417 attr
->preedit_fontset
= widget
->style
->font
;
2422 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2424 if (win
->m_ic
== NULL
)
2425 g_warning ("Can't create input context.");
2428 mask
= gdk_window_get_events (widget
->window
);
2429 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2430 gdk_window_set_events (widget
->window
, mask
);
2432 if (GTK_WIDGET_HAS_FOCUS(widget
))
2433 gdk_im_begin (win
->m_ic
, widget
->window
);
2439 //-----------------------------------------------------------------------------
2440 // InsertChild for wxWindowGTK.
2441 //-----------------------------------------------------------------------------
2443 /* Callback for wxWindowGTK. This very strange beast has to be used because
2444 * C++ has no virtual methods in a constructor. We have to emulate a
2445 * virtual function here as wxNotebook requires a different way to insert
2446 * a child in it. I had opted for creating a wxNotebookPage window class
2447 * which would have made this superfluous (such in the MDI window system),
2448 * but no-one was listening to me... */
2450 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2452 /* the window might have been scrolled already, do we
2453 have to adapt the position */
2454 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2455 child
->m_x
+= pizza
->xoffset
;
2456 child
->m_y
+= pizza
->yoffset
;
2458 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2459 GTK_WIDGET(child
->m_widget
),
2466 //-----------------------------------------------------------------------------
2468 //-----------------------------------------------------------------------------
2470 wxWindow
*wxGetActiveWindow()
2472 return wxWindow::FindFocus();
2476 wxMouseState
wxGetMouseState()
2482 GdkModifierType mask
;
2484 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2488 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2489 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2490 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2492 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2493 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2494 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2495 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2500 //-----------------------------------------------------------------------------
2502 //-----------------------------------------------------------------------------
2504 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2506 #ifdef __WXUNIVERSAL__
2507 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2509 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2510 #endif // __WXUNIVERSAL__/__WXGTK__
2512 void wxWindowGTK::Init()
2515 m_widget
= (GtkWidget
*) NULL
;
2516 m_wxwindow
= (GtkWidget
*) NULL
;
2517 m_focusWidget
= (GtkWidget
*) NULL
;
2527 m_needParent
= true;
2528 m_isBeingDeleted
= false;
2531 m_nativeSizeEvent
= false;
2533 m_hasScrolling
= false;
2534 m_isScrolling
= false;
2536 m_hAdjust
= (GtkAdjustment
*) NULL
;
2537 m_vAdjust
= (GtkAdjustment
*) NULL
;
2538 m_oldHorizontalPos
=
2539 m_oldVerticalPos
= 0.0;
2541 m_oldClientHeight
= 0;
2545 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2547 m_acceptsFocus
= false;
2550 m_clipPaintRegion
= false;
2552 m_needsStyleChange
= false;
2554 m_cursor
= *wxSTANDARD_CURSOR
;
2557 m_dirtyTabOrder
= false;
2560 wxWindowGTK::wxWindowGTK()
2565 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2570 const wxString
&name
)
2574 Create( parent
, id
, pos
, size
, style
, name
);
2577 bool wxWindowGTK::Create( wxWindow
*parent
,
2582 const wxString
&name
)
2584 if (!PreCreation( parent
, pos
, size
) ||
2585 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2587 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2591 m_insertCallback
= wxInsertChildInWindow
;
2593 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2594 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2596 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2598 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2599 scroll_class
->scrollbar_spacing
= 0;
2601 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2603 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2604 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2606 m_wxwindow
= gtk_pizza_new();
2608 #ifndef __WXUNIVERSAL__
2609 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2611 if (HasFlag(wxRAISED_BORDER
))
2613 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2615 else if (HasFlag(wxSUNKEN_BORDER
))
2617 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2619 else if (HasFlag(wxSIMPLE_BORDER
))
2621 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2625 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2627 #endif // __WXUNIVERSAL__
2629 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2631 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2632 m_acceptsFocus
= true;
2634 // I _really_ don't want scrollbars in the beginning
2635 m_vAdjust
->lower
= 0.0;
2636 m_vAdjust
->upper
= 1.0;
2637 m_vAdjust
->value
= 0.0;
2638 m_vAdjust
->step_increment
= 1.0;
2639 m_vAdjust
->page_increment
= 1.0;
2640 m_vAdjust
->page_size
= 5.0;
2641 g_signal_emit_by_name (m_vAdjust
, "changed");
2642 m_hAdjust
->lower
= 0.0;
2643 m_hAdjust
->upper
= 1.0;
2644 m_hAdjust
->value
= 0.0;
2645 m_hAdjust
->step_increment
= 1.0;
2646 m_hAdjust
->page_increment
= 1.0;
2647 m_hAdjust
->page_size
= 5.0;
2648 g_signal_emit_by_name (m_hAdjust
, "changed");
2650 // these handlers block mouse events to any window during scrolling such as
2651 // motion events and prevent GTK and wxWidgets from fighting over where the
2653 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2654 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2655 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2656 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2657 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2658 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2659 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2660 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2662 // these handlers get notified when screen updates are required either when
2663 // scrolling or when the window size (and therefore scrollbar configuration)
2666 g_signal_connect (m_hAdjust
, "value_changed",
2667 G_CALLBACK (gtk_window_hscroll_callback
), this);
2668 g_signal_connect (m_vAdjust
, "value_changed",
2669 G_CALLBACK (gtk_window_vscroll_callback
), this);
2671 gtk_widget_show( m_wxwindow
);
2674 m_parent
->DoAddChild( this );
2676 m_focusWidget
= m_wxwindow
;
2683 wxWindowGTK::~wxWindowGTK()
2687 if (g_focusWindow
== this)
2688 g_focusWindow
= NULL
;
2690 if ( g_delayedFocus
== this )
2691 g_delayedFocus
= NULL
;
2693 m_isBeingDeleted
= true;
2696 // destroy children before destroying this window itself
2699 // unhook focus handlers to prevent stray events being
2700 // propagated to this (soon to be) dead object
2701 if (m_focusWidget
!= NULL
)
2703 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2704 (gpointer
) gtk_window_focus_in_callback
,
2706 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2707 (gpointer
) gtk_window_focus_out_callback
,
2716 gdk_ic_destroy (m_ic
);
2718 gdk_ic_attr_destroy (m_icattr
);
2721 // delete before the widgets to avoid a crash on solaris
2726 gtk_widget_destroy( m_wxwindow
);
2727 m_wxwindow
= (GtkWidget
*) NULL
;
2732 gtk_widget_destroy( m_widget
);
2733 m_widget
= (GtkWidget
*) NULL
;
2737 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2739 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2741 // Use either the given size, or the default if -1 is given.
2742 // See wxWindowBase for these functions.
2743 m_width
= WidthDefault(size
.x
) ;
2744 m_height
= HeightDefault(size
.y
);
2752 void wxWindowGTK::PostCreation()
2754 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2760 // these get reported to wxWidgets -> wxPaintEvent
2762 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2764 g_signal_connect (m_wxwindow
, "expose_event",
2765 G_CALLBACK (gtk_window_expose_callback
), this);
2767 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2770 // Create input method handler
2771 m_imData
= new wxGtkIMData
;
2773 // Cannot handle drawing preedited text yet
2774 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2776 g_signal_connect (m_imData
->context
, "commit",
2777 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2779 // these are called when the "sunken" or "raised" borders are drawn
2780 g_signal_connect (m_widget
, "expose_event",
2781 G_CALLBACK (gtk_window_own_expose_callback
), this);
2786 if (!GTK_IS_WINDOW(m_widget
))
2788 if (m_focusWidget
== NULL
)
2789 m_focusWidget
= m_widget
;
2793 g_signal_connect (m_focusWidget
, "focus_in_event",
2794 G_CALLBACK (gtk_window_focus_in_callback
), this);
2795 g_signal_connect (m_focusWidget
, "focus_out_event",
2796 G_CALLBACK (gtk_window_focus_out_callback
), this);
2800 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2801 G_CALLBACK (gtk_window_focus_in_callback
), this);
2802 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2803 G_CALLBACK (gtk_window_focus_out_callback
), this);
2807 // connect to the various key and mouse handlers
2809 GtkWidget
*connect_widget
= GetConnectWidget();
2811 ConnectWidget( connect_widget
);
2813 /* We cannot set colours, fonts and cursors before the widget has
2814 been realized, so we do this directly after realization */
2815 g_signal_connect (connect_widget
, "realize",
2816 G_CALLBACK (gtk_window_realized_callback
), this);
2820 // Catch native resize events
2821 g_signal_connect (m_wxwindow
, "size_allocate",
2822 G_CALLBACK (gtk_window_size_callback
), this);
2824 // Initialize XIM support
2825 g_signal_connect (m_wxwindow
, "realize",
2826 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2828 // And resize XIM window
2829 g_signal_connect (m_wxwindow
, "size_allocate",
2830 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2833 if (GTK_IS_COMBO(m_widget
))
2835 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2837 g_signal_connect (gcombo
->entry
, "size_request",
2838 G_CALLBACK (wxgtk_combo_size_request_callback
),
2843 // This is needed if we want to add our windows into native
2844 // GTK controls, such as the toolbar. With this callback, the
2845 // toolbar gets to know the correct size (the one set by the
2846 // programmer). Sadly, it misbehaves for wxComboBox.
2847 g_signal_connect (m_widget
, "size_request",
2848 G_CALLBACK (wxgtk_window_size_request_callback
),
2852 InheritAttributes();
2856 // unless the window was created initially hidden (i.e. Hide() had been
2857 // called before Create()), we should show it at GTK+ level as well
2859 gtk_widget_show( m_widget
);
2862 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2864 g_signal_connect (widget
, "key_press_event",
2865 G_CALLBACK (gtk_window_key_press_callback
), this);
2866 g_signal_connect (widget
, "key_release_event",
2867 G_CALLBACK (gtk_window_key_release_callback
), this);
2868 g_signal_connect (widget
, "button_press_event",
2869 G_CALLBACK (gtk_window_button_press_callback
), this);
2870 g_signal_connect (widget
, "button_release_event",
2871 G_CALLBACK (gtk_window_button_release_callback
), this);
2872 g_signal_connect (widget
, "motion_notify_event",
2873 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2874 g_signal_connect (widget
, "scroll_event",
2875 G_CALLBACK (gtk_window_wheel_callback
), this);
2876 g_signal_connect (widget
, "popup_menu",
2877 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2878 g_signal_connect (widget
, "enter_notify_event",
2879 G_CALLBACK (gtk_window_enter_callback
), this);
2880 g_signal_connect (widget
, "leave_notify_event",
2881 G_CALLBACK (gtk_window_leave_callback
), this);
2884 bool wxWindowGTK::Destroy()
2886 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2890 return wxWindowBase::Destroy();
2893 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2895 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2898 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2900 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2901 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2904 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2907 if (m_resizing
) return; /* I don't like recursions */
2910 int currentX
, currentY
;
2911 GetPosition(¤tX
, ¤tY
);
2912 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2914 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2916 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2918 // calculate the best size if we should auto size the window
2919 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2920 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2922 const wxSize sizeBest
= GetBestSize();
2923 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2925 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2926 height
= sizeBest
.y
;
2934 int minWidth
= GetMinWidth(),
2935 minHeight
= GetMinHeight(),
2936 maxWidth
= GetMaxWidth(),
2937 maxHeight
= GetMaxHeight();
2939 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2940 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2941 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2942 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2944 #if wxUSE_TOOLBAR_NATIVE
2945 if (wxDynamicCast(GetParent(), wxToolBar
))
2947 // don't take the x,y values, they're wrong because toolbar sets them
2948 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2949 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2950 if (GTK_WIDGET_VISIBLE (widget
))
2951 gtk_widget_queue_resize (widget
);
2955 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2957 // don't set the size for children of wxNotebook, just take the values.
2965 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2966 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2968 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2969 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2973 m_x
= x
+ pizza
->xoffset
;
2974 m_y
= y
+ pizza
->yoffset
;
2977 int left_border
= 0;
2978 int right_border
= 0;
2980 int bottom_border
= 0;
2982 /* the default button has a border around it */
2983 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2985 GtkBorder
*default_border
= NULL
;
2986 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2989 left_border
+= default_border
->left
;
2990 right_border
+= default_border
->right
;
2991 top_border
+= default_border
->top
;
2992 bottom_border
+= default_border
->bottom
;
2993 g_free( default_border
);
2997 DoMoveWindow( m_x
-top_border
,
2999 m_width
+left_border
+right_border
,
3000 m_height
+top_border
+bottom_border
);
3005 /* Sometimes the client area changes size without the
3006 whole windows's size changing, but if the whole
3007 windows's size doesn't change, no wxSizeEvent will
3008 normally be sent. Here we add an extra test if
3009 the client test has been changed and this will
3011 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3015 wxPrintf( "OnSize sent from " );
3016 if (GetClassInfo() && GetClassInfo()->GetClassName())
3017 wxPrintf( GetClassInfo()->GetClassName() );
3018 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3021 if (!m_nativeSizeEvent
)
3023 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3024 event
.SetEventObject( this );
3025 GetEventHandler()->ProcessEvent( event
);
3031 void wxWindowGTK::OnInternalIdle()
3033 if ( m_dirtyTabOrder
)
3035 m_dirtyTabOrder
= false;
3039 // Update style if the window was not yet realized
3040 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3041 if (m_needsStyleChange
)
3043 SetBackgroundStyle(GetBackgroundStyle());
3044 m_needsStyleChange
= false;
3047 // Update invalidated regions.
3050 wxCursor cursor
= m_cursor
;
3051 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3055 /* I now set the cursor anew in every OnInternalIdle call
3056 as setting the cursor in a parent window also effects the
3057 windows above so that checking for the current cursor is
3062 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3064 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3066 if (!g_globalCursor
.Ok())
3067 cursor
= *wxSTANDARD_CURSOR
;
3069 window
= m_widget
->window
;
3070 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3071 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3077 GdkWindow
*window
= m_widget
->window
;
3078 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3079 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3084 if (wxUpdateUIEvent::CanUpdate(this))
3085 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3088 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3090 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3092 if (width
) (*width
) = m_width
;
3093 if (height
) (*height
) = m_height
;
3096 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3098 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3102 SetSize( width
, height
);
3109 #ifndef __WXUNIVERSAL__
3110 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3112 /* when using GTK 1.2 we set the shadow border size to 2 */
3116 if (HasFlag(wxSIMPLE_BORDER
))
3118 /* when using GTK 1.2 we set the simple border size to 1 */
3122 #endif // __WXUNIVERSAL__
3126 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3128 GtkRequisition vscroll_req
;
3129 vscroll_req
.width
= 2;
3130 vscroll_req
.height
= 2;
3131 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3132 (scroll_window
->vscrollbar
, &vscroll_req
);
3134 GtkRequisition hscroll_req
;
3135 hscroll_req
.width
= 2;
3136 hscroll_req
.height
= 2;
3137 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3138 (scroll_window
->hscrollbar
, &hscroll_req
);
3140 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3142 if (scroll_window
->vscrollbar_visible
)
3144 dw
+= vscroll_req
.width
;
3145 dw
+= scroll_class
->scrollbar_spacing
;
3148 if (scroll_window
->hscrollbar_visible
)
3150 dh
+= hscroll_req
.height
;
3151 dh
+= scroll_class
->scrollbar_spacing
;
3155 SetSize( width
+dw
, height
+dh
);
3159 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3161 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3165 if (width
) (*width
) = m_width
;
3166 if (height
) (*height
) = m_height
;
3173 #ifndef __WXUNIVERSAL__
3174 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3176 /* when using GTK 1.2 we set the shadow border size to 2 */
3180 if (HasFlag(wxSIMPLE_BORDER
))
3182 /* when using GTK 1.2 we set the simple border size to 1 */
3186 #endif // __WXUNIVERSAL__
3190 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3192 GtkRequisition vscroll_req
;
3193 vscroll_req
.width
= 2;
3194 vscroll_req
.height
= 2;
3195 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3196 (scroll_window
->vscrollbar
, &vscroll_req
);
3198 GtkRequisition hscroll_req
;
3199 hscroll_req
.width
= 2;
3200 hscroll_req
.height
= 2;
3201 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3202 (scroll_window
->hscrollbar
, &hscroll_req
);
3204 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3206 if (scroll_window
->vscrollbar_visible
)
3208 dw
+= vscroll_req
.width
;
3209 dw
+= scroll_class
->scrollbar_spacing
;
3212 if (scroll_window
->hscrollbar_visible
)
3214 dh
+= hscroll_req
.height
;
3215 dh
+= scroll_class
->scrollbar_spacing
;
3219 if (width
) (*width
) = m_width
- dw
;
3220 if (height
) (*height
) = m_height
- dh
;
3224 printf( "GetClientSize, name %s ", GetName().c_str() );
3225 if (width) printf( " width = %d", (*width) );
3226 if (height) printf( " height = %d", (*height) );
3231 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3233 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3237 if (m_parent
&& m_parent
->m_wxwindow
)
3239 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3240 dx
= pizza
->xoffset
;
3241 dy
= pizza
->yoffset
;
3244 if (x
) (*x
) = m_x
- dx
;
3245 if (y
) (*y
) = m_y
- dy
;
3248 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3250 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3252 if (!m_widget
->window
) return;
3254 GdkWindow
*source
= (GdkWindow
*) NULL
;
3256 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3258 source
= m_widget
->window
;
3262 gdk_window_get_origin( source
, &org_x
, &org_y
);
3266 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3268 org_x
+= m_widget
->allocation
.x
;
3269 org_y
+= m_widget
->allocation
.y
;
3277 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3279 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3281 if (!m_widget
->window
) return;
3283 GdkWindow
*source
= (GdkWindow
*) NULL
;
3285 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3287 source
= m_widget
->window
;
3291 gdk_window_get_origin( source
, &org_x
, &org_y
);
3295 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3297 org_x
+= m_widget
->allocation
.x
;
3298 org_y
+= m_widget
->allocation
.y
;
3306 bool wxWindowGTK::Show( bool show
)
3308 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3310 if (!wxWindowBase::Show(show
))
3317 gtk_widget_show( m_widget
);
3319 gtk_widget_hide( m_widget
);
3321 wxShowEvent
eventShow(GetId(), show
);
3322 eventShow
.SetEventObject(this);
3324 GetEventHandler()->ProcessEvent(eventShow
);
3329 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3331 win
->OnParentEnable(enable
);
3333 // Recurse, so that children have the opportunity to Do The Right Thing
3334 // and reset colours that have been messed up by a parent's (really ancestor's)
3336 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3338 node
= node
->GetNext() )
3340 wxWindow
*child
= node
->GetData();
3341 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3342 wxWindowNotifyEnable(child
, enable
);
3346 bool wxWindowGTK::Enable( bool enable
)
3348 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3350 if (!wxWindowBase::Enable(enable
))
3356 gtk_widget_set_sensitive( m_widget
, enable
);
3358 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3360 wxWindowNotifyEnable(this, enable
);
3365 int wxWindowGTK::GetCharHeight() const
3367 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3369 wxFont font
= GetFont();
3370 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3372 PangoContext
*context
= NULL
;
3374 context
= gtk_widget_get_pango_context( m_widget
);
3379 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3380 PangoLayout
*layout
= pango_layout_new(context
);
3381 pango_layout_set_font_description(layout
, desc
);
3382 pango_layout_set_text(layout
, "H", 1);
3383 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3385 PangoRectangle rect
;
3386 pango_layout_line_get_extents(line
, NULL
, &rect
);
3388 g_object_unref( G_OBJECT( layout
) );
3390 return (int) PANGO_PIXELS(rect
.height
);
3393 int wxWindowGTK::GetCharWidth() const
3395 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3397 wxFont font
= GetFont();
3398 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3400 PangoContext
*context
= NULL
;
3402 context
= gtk_widget_get_pango_context( m_widget
);
3407 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3408 PangoLayout
*layout
= pango_layout_new(context
);
3409 pango_layout_set_font_description(layout
, desc
);
3410 pango_layout_set_text(layout
, "g", 1);
3411 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3413 PangoRectangle rect
;
3414 pango_layout_line_get_extents(line
, NULL
, &rect
);
3416 g_object_unref( G_OBJECT( layout
) );
3418 return (int) PANGO_PIXELS(rect
.width
);
3421 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3425 int *externalLeading
,
3426 const wxFont
*theFont
) const
3428 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3430 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3439 PangoContext
*context
= NULL
;
3441 context
= gtk_widget_get_pango_context( m_widget
);
3450 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3451 PangoLayout
*layout
= pango_layout_new(context
);
3452 pango_layout_set_font_description(layout
, desc
);
3455 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3456 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3458 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3459 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3460 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3464 PangoRectangle rect
;
3465 pango_layout_get_extents(layout
, NULL
, &rect
);
3467 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3468 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3471 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3472 int baseline
= pango_layout_iter_get_baseline(iter
);
3473 pango_layout_iter_free(iter
);
3474 *descent
= *y
- PANGO_PIXELS(baseline
);
3476 if (externalLeading
) (*externalLeading
) = 0; // ??
3478 g_object_unref( G_OBJECT( layout
) );
3481 void wxWindowGTK::SetFocus()
3483 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3486 // don't do anything if we already have focus
3492 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3494 gtk_widget_grab_focus (m_wxwindow
);
3499 if (GTK_IS_CONTAINER(m_widget
))
3501 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3504 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3507 if (!GTK_WIDGET_REALIZED(m_widget
))
3509 // we can't set the focus to the widget now so we remember that
3510 // it should be focused and will do it later, during the idle
3511 // time, as soon as we can
3512 wxLogTrace(TRACE_FOCUS
,
3513 _T("Delaying setting focus to %s(%s)"),
3514 GetClassInfo()->GetClassName(), GetLabel().c_str());
3516 g_delayedFocus
= this;
3520 wxLogTrace(TRACE_FOCUS
,
3521 _T("Setting focus to %s(%s)"),
3522 GetClassInfo()->GetClassName(), GetLabel().c_str());
3524 gtk_widget_grab_focus (m_widget
);
3529 wxLogTrace(TRACE_FOCUS
,
3530 _T("Can't set focus to %s(%s)"),
3531 GetClassInfo()->GetClassName(), GetLabel().c_str());
3536 bool wxWindowGTK::AcceptsFocus() const
3538 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3541 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3543 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3545 wxWindowGTK
*oldParent
= m_parent
,
3546 *newParent
= (wxWindowGTK
*)newParentBase
;
3548 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3550 if ( !wxWindowBase::Reparent(newParent
) )
3553 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3555 /* prevent GTK from deleting the widget arbitrarily */
3556 gtk_widget_ref( m_widget
);
3560 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3563 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3567 /* insert GTK representation */
3568 (*(newParent
->m_insertCallback
))(newParent
, this);
3571 /* reverse: prevent GTK from deleting the widget arbitrarily */
3572 gtk_widget_unref( m_widget
);
3577 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3579 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3581 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3583 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3588 /* insert GTK representation */
3589 (*m_insertCallback
)(this, child
);
3592 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3594 wxWindowBase::AddChild(child
);
3595 m_dirtyTabOrder
= true;
3597 wxapp_install_idle_handler();
3600 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3602 wxWindowBase::RemoveChild(child
);
3603 m_dirtyTabOrder
= true;
3605 wxapp_install_idle_handler();
3608 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3610 wxWindowBase::DoMoveInTabOrder(win
, move
);
3611 m_dirtyTabOrder
= true;
3613 wxapp_install_idle_handler();
3616 void wxWindowGTK::RealizeTabOrder()
3620 if ( !m_children
.empty() )
3623 // we don't only construct the correct focus chain but also use
3624 // this opportunity to update the mnemonic widgets for all labels
3626 // it would be nice to extract this code from here and put it in
3627 // stattext.cpp to reduce dependencies but there is no really easy
3628 // way to do it unfortunately
3629 wxStaticText
*lastLabel
= NULL
;
3630 #endif // wxUSE_STATTEXT
3632 GList
*chain
= NULL
;
3634 for ( wxWindowList::const_iterator i
= m_children
.begin();
3635 i
!= m_children
.end();
3638 wxWindowGTK
*win
= *i
;
3642 if ( win
->AcceptsFocusFromKeyboard() )
3644 GtkLabel
*l
= GTK_LABEL(lastLabel
->m_widget
);
3645 gtk_label_set_mnemonic_widget(l
, win
->m_widget
);
3649 else // check if this one is a label
3651 lastLabel
= wxDynamicCast(win
, wxStaticText
);
3653 #endif // wxUSE_STATTEXT
3655 chain
= g_list_prepend(chain
, win
->m_widget
);
3658 chain
= g_list_reverse(chain
);
3660 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3665 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3670 void wxWindowGTK::Raise()
3672 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3674 if (m_wxwindow
&& m_wxwindow
->window
)
3676 gdk_window_raise( m_wxwindow
->window
);
3678 else if (m_widget
->window
)
3680 gdk_window_raise( m_widget
->window
);
3684 void wxWindowGTK::Lower()
3686 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3688 if (m_wxwindow
&& m_wxwindow
->window
)
3690 gdk_window_lower( m_wxwindow
->window
);
3692 else if (m_widget
->window
)
3694 gdk_window_lower( m_widget
->window
);
3698 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3700 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3702 if (cursor
== m_cursor
)
3706 wxapp_install_idle_handler();
3708 if (cursor
== wxNullCursor
)
3709 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3711 return wxWindowBase::SetCursor( cursor
);
3714 void wxWindowGTK::WarpPointer( int x
, int y
)
3716 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3718 // We provide this function ourselves as it is
3719 // missing in GDK (top of this file).
3721 GdkWindow
*window
= (GdkWindow
*) NULL
;
3723 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3725 window
= GetConnectWidget()->window
;
3728 gdk_window_warp_pointer( window
, x
, y
);
3731 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3733 double value_start
= adj
->value
;
3734 double value
= value_start
+ change
;
3735 double upper
= adj
->upper
- adj
->page_size
;
3740 // Lower bound will be checked by gtk_adjustment_set_value
3741 gtk_adjustment_set_value(adj
, value
);
3742 return adj
->value
!= value_start
;
3745 bool wxWindowGTK::ScrollLines(int lines
)
3748 m_vAdjust
!= NULL
&&
3749 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3752 bool wxWindowGTK::ScrollPages(int pages
)
3755 m_vAdjust
!= NULL
&&
3756 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3759 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3761 wxASSERT(m_vAdjust
== NULL
);
3765 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3769 if (!m_widget
->window
)
3774 GdkRectangle gdk_rect
,
3778 gdk_rect
.x
= rect
->x
;
3779 gdk_rect
.y
= rect
->y
;
3780 gdk_rect
.width
= rect
->width
;
3781 gdk_rect
.height
= rect
->height
;
3784 else // invalidate everything
3789 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3793 void wxWindowGTK::Update()
3797 // when we call Update() we really want to update the window immediately on
3798 // screen, even if it means flushing the entire queue and hence slowing down
3799 // everything -- but it should still be done, it's just that Update() should
3800 // be called very rarely
3804 void wxWindowGTK::GtkUpdate()
3806 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3807 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3809 // for consistency with other platforms (and also because it's convenient
3810 // to be able to update an entire TLW by calling Update() only once), we
3811 // should also update all our children here
3812 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3814 node
= node
->GetNext() )
3816 node
->GetData()->GtkUpdate();
3820 void wxWindowGTK::GtkSendPaintEvents()
3824 m_updateRegion
.Clear();
3828 // Clip to paint region in wxClientDC
3829 m_clipPaintRegion
= true;
3831 // widget to draw on
3832 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3834 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3836 // find ancestor from which to steal background
3837 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3839 parent
= (wxWindow
*)this;
3841 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3843 wxRegionIterator
upd( m_updateRegion
);
3847 rect
.x
= upd
.GetX();
3848 rect
.y
= upd
.GetY();
3849 rect
.width
= upd
.GetWidth();
3850 rect
.height
= upd
.GetHeight();
3852 gtk_paint_flat_box( parent
->m_widget
->style
,
3854 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3868 wxWindowDC
dc( (wxWindow
*)this );
3869 dc
.SetClippingRegion( m_updateRegion
);
3871 wxEraseEvent
erase_event( GetId(), &dc
);
3872 erase_event
.SetEventObject( this );
3874 GetEventHandler()->ProcessEvent(erase_event
);
3877 wxNcPaintEvent
nc_paint_event( GetId() );
3878 nc_paint_event
.SetEventObject( this );
3879 GetEventHandler()->ProcessEvent( nc_paint_event
);
3881 wxPaintEvent
paint_event( GetId() );
3882 paint_event
.SetEventObject( this );
3883 GetEventHandler()->ProcessEvent( paint_event
);
3885 m_clipPaintRegion
= false;
3887 m_updateRegion
.Clear();
3890 void wxWindowGTK::ClearBackground()
3892 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3896 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3898 wxWindowBase::DoSetToolTip(tip
);
3901 m_tooltip
->Apply( (wxWindow
*)this );
3904 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3906 wxString
tmp( tip
);
3907 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3909 #endif // wxUSE_TOOLTIPS
3911 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3913 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3915 if (!wxWindowBase::SetBackgroundColour(colour
))
3920 // We need the pixel value e.g. for background clearing.
3921 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3924 // apply style change (forceStyle=true so that new style is applied
3925 // even if the bg colour changed from valid to wxNullColour)
3926 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3927 ApplyWidgetStyle(true);
3932 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3934 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3936 if (!wxWindowBase::SetForegroundColour(colour
))
3943 // We need the pixel value e.g. for background clearing.
3944 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3947 // apply style change (forceStyle=true so that new style is applied
3948 // even if the bg colour changed from valid to wxNullColour):
3949 ApplyWidgetStyle(true);
3954 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3956 return gtk_widget_get_pango_context( m_widget
);
3959 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3961 // do we need to apply any changes at all?
3964 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3969 GtkRcStyle
*style
= gtk_rc_style_new();
3974 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3977 if ( m_foregroundColour
.Ok() )
3979 GdkColor
*fg
= m_foregroundColour
.GetColor();
3981 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3982 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3984 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3985 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3987 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3988 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3991 if ( m_backgroundColour
.Ok() )
3993 GdkColor
*bg
= m_backgroundColour
.GetColor();
3995 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3996 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3997 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3998 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4000 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4001 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4002 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4003 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4005 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4006 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4007 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4008 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4010 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4011 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4012 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4013 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4019 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4021 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4024 DoApplyWidgetStyle(style
);
4025 gtk_rc_style_unref(style
);
4028 // Style change may affect GTK+'s size calculation:
4029 InvalidateBestSize();
4032 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4035 gtk_widget_modify_style(m_wxwindow
, style
);
4037 gtk_widget_modify_style(m_widget
, style
);
4040 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4042 wxWindowBase::SetBackgroundStyle(style
);
4044 if (style
== wxBG_STYLE_CUSTOM
)
4046 GdkWindow
*window
= (GdkWindow
*) NULL
;
4048 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4050 window
= GetConnectWidget()->window
;
4054 // Make sure GDK/X11 doesn't refresh the window
4056 gdk_window_set_back_pixmap( window
, None
, False
);
4058 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4061 m_needsStyleChange
= false;
4064 // Do in OnIdle, because the window is not yet available
4065 m_needsStyleChange
= true;
4067 // Don't apply widget style, or we get a grey background
4071 // apply style change (forceStyle=true so that new style is applied
4072 // even if the bg colour changed from valid to wxNullColour):
4073 ApplyWidgetStyle(true);
4078 #if wxUSE_DRAG_AND_DROP
4080 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4082 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4084 GtkWidget
*dnd_widget
= GetConnectWidget();
4086 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4088 if (m_dropTarget
) delete m_dropTarget
;
4089 m_dropTarget
= dropTarget
;
4091 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4094 #endif // wxUSE_DRAG_AND_DROP
4096 GtkWidget
* wxWindowGTK::GetConnectWidget()
4098 GtkWidget
*connect_widget
= m_widget
;
4099 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4101 return connect_widget
;
4104 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4107 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4109 return (window
== m_widget
->window
);
4112 bool wxWindowGTK::SetFont( const wxFont
&font
)
4114 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4116 if (!wxWindowBase::SetFont(font
))
4119 // apply style change (forceStyle=true so that new style is applied
4120 // even if the font changed from valid to wxNullFont):
4121 ApplyWidgetStyle(true);
4126 void wxWindowGTK::DoCaptureMouse()
4128 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4130 GdkWindow
*window
= (GdkWindow
*) NULL
;
4132 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4134 window
= GetConnectWidget()->window
;
4136 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4138 wxCursor
* cursor
= & m_cursor
;
4140 cursor
= wxSTANDARD_CURSOR
;
4142 gdk_pointer_grab( window
, FALSE
,
4144 (GDK_BUTTON_PRESS_MASK
|
4145 GDK_BUTTON_RELEASE_MASK
|
4146 GDK_POINTER_MOTION_HINT_MASK
|
4147 GDK_POINTER_MOTION_MASK
),
4149 cursor
->GetCursor(),
4150 (guint32
)GDK_CURRENT_TIME
);
4151 g_captureWindow
= this;
4152 g_captureWindowHasMouse
= true;
4155 void wxWindowGTK::DoReleaseMouse()
4157 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4159 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4161 g_captureWindow
= (wxWindowGTK
*) NULL
;
4163 GdkWindow
*window
= (GdkWindow
*) NULL
;
4165 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4167 window
= GetConnectWidget()->window
;
4172 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4176 wxWindow
*wxWindowBase::GetCapture()
4178 return (wxWindow
*)g_captureWindow
;
4181 bool wxWindowGTK::IsRetained() const
4186 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4187 int range
, bool refresh
)
4189 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4191 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4193 m_hasScrolling
= true;
4195 if (orient
== wxHORIZONTAL
)
4197 float fpos
= (float)pos
;
4198 float frange
= (float)range
;
4199 float fthumb
= (float)thumbVisible
;
4200 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4201 if (fpos
< 0.0) fpos
= 0.0;
4203 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4204 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4206 SetScrollPos( orient
, pos
, refresh
);
4210 m_oldHorizontalPos
= fpos
;
4212 m_hAdjust
->lower
= 0.0;
4213 m_hAdjust
->upper
= frange
;
4214 m_hAdjust
->value
= fpos
;
4215 m_hAdjust
->step_increment
= 1.0;
4216 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4217 m_hAdjust
->page_size
= fthumb
;
4221 float fpos
= (float)pos
;
4222 float frange
= (float)range
;
4223 float fthumb
= (float)thumbVisible
;
4224 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4225 if (fpos
< 0.0) fpos
= 0.0;
4227 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4228 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4230 SetScrollPos( orient
, pos
, refresh
);
4234 m_oldVerticalPos
= fpos
;
4236 m_vAdjust
->lower
= 0.0;
4237 m_vAdjust
->upper
= frange
;
4238 m_vAdjust
->value
= fpos
;
4239 m_vAdjust
->step_increment
= 1.0;
4240 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4241 m_vAdjust
->page_size
= fthumb
;
4244 if (orient
== wxHORIZONTAL
)
4245 g_signal_emit_by_name (m_hAdjust
, "changed");
4247 g_signal_emit_by_name (m_vAdjust
, "changed");
4250 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4252 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4253 gpointer fn
= orient
== wxHORIZONTAL
4254 ? (gpointer
) gtk_window_hscroll_callback
4255 : (gpointer
) gtk_window_vscroll_callback
;
4257 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4258 g_signal_emit_by_name (adj
, "value_changed");
4259 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4262 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4264 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4265 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4267 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4269 float fpos
= (float)pos
;
4270 if (fpos
> adj
->upper
- adj
->page_size
)
4271 fpos
= adj
->upper
- adj
->page_size
;
4274 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4276 if (fabs(fpos
-adj
->value
) < 0.2)
4280 if ( m_wxwindow
->window
)
4285 int wxWindowGTK::GetScrollThumb( int orient
) const
4287 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4289 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4291 if (orient
== wxHORIZONTAL
)
4292 return (int)(m_hAdjust
->page_size
+0.5);
4294 return (int)(m_vAdjust
->page_size
+0.5);
4297 int wxWindowGTK::GetScrollPos( int orient
) const
4299 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4301 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4303 if (orient
== wxHORIZONTAL
)
4304 return (int)(m_hAdjust
->value
+0.5);
4306 return (int)(m_vAdjust
->value
+0.5);
4309 int wxWindowGTK::GetScrollRange( int orient
) const
4311 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4313 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4315 if (orient
== wxHORIZONTAL
)
4316 return (int)(m_hAdjust
->upper
+0.5);
4318 return (int)(m_vAdjust
->upper
+0.5);
4321 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4323 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4325 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4327 // No scrolling requested.
4328 if ((dx
== 0) && (dy
== 0)) return;
4330 m_clipPaintRegion
= true;
4332 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4334 m_clipPaintRegion
= false;
4337 void wxWindowGTK::SetWindowStyleFlag( long style
)
4339 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4340 wxWindowBase::SetWindowStyleFlag(style
);
4343 // Find the wxWindow at the current mouse position, also returning the mouse
4345 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4347 pt
= wxGetMousePosition();
4348 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4352 // Get the current mouse position.
4353 wxPoint
wxGetMousePosition()
4355 /* This crashes when used within wxHelpContext,
4356 so we have to use the X-specific implementation below.
4358 GdkModifierType *mask;
4359 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4361 return wxPoint(x, y);
4365 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4367 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4368 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4369 Window rootReturn
, childReturn
;
4370 int rootX
, rootY
, winX
, winY
;
4371 unsigned int maskReturn
;
4373 XQueryPointer (display
,
4377 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4378 return wxPoint(rootX
, rootY
);
4382 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4383 void wxAddGrab(wxWindow
* window
)
4385 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4388 void wxRemoveGrab(wxWindow
* window
)
4390 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4393 // ----------------------------------------------------------------------------
4395 // ----------------------------------------------------------------------------
4397 class wxWinModule
: public wxModule
4404 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4407 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4409 bool wxWinModule::OnInit()
4411 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4412 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4417 void wxWinModule::OnExit()
4420 gdk_gc_unref( g_eraseGC
);