1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
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"
55 #include "wx/thread.h"
61 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
62 #include <gtk/gtkversion.h>
63 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
64 #undef GTK_DISABLE_DEPRECATED
67 #include "wx/gtk/private.h"
68 #include <gdk/gdkprivate.h>
69 #include <gdk/gdkkeysyms.h>
73 #include <gtk/gtkprivate.h>
75 #include "wx/gtk/win_gtk.h"
77 #include <pango/pangox.h>
83 extern GtkContainerClass
*pizza_parent_class
;
85 //-----------------------------------------------------------------------------
86 // documentation on internals
87 //-----------------------------------------------------------------------------
90 I have been asked several times about writing some documentation about
91 the GTK port of wxWidgets, especially its internal structures. Obviously,
92 you cannot understand wxGTK without knowing a little about the GTK, but
93 some more information about what the wxWindow, which is the base class
94 for all other window classes, does seems required as well.
98 What does wxWindow do? It contains the common interface for the following
99 jobs of its descendants:
101 1) Define the rudimentary behaviour common to all window classes, such as
102 resizing, intercepting user input (so as to make it possible to use these
103 events for special purposes in a derived class), window names etc.
105 2) Provide the possibility to contain and manage children, if the derived
106 class is allowed to contain children, which holds true for those window
107 classes which do not display a native GTK widget. To name them, these
108 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
109 work classes are a special case and are handled a bit differently from
110 the rest. The same holds true for the wxNotebook class.
112 3) Provide the possibility to draw into a client area of a window. This,
113 too, only holds true for classes that do not display a native GTK widget
116 4) Provide the entire mechanism for scrolling widgets. This actual inter-
117 face for this is usually in wxScrolledWindow, but the GTK implementation
120 5) A multitude of helper or extra methods for special purposes, such as
121 Drag'n'Drop, managing validators etc.
123 6) Display a border (sunken, raised, simple or none).
125 Normally one might expect, that one wxWidgets window would always correspond
126 to one GTK widget. Under GTK, there is no such allround widget that has all
127 the functionality. Moreover, the GTK defines a client area as a different
128 widget from the actual widget you are handling. Last but not least some
129 special classes (e.g. wxFrame) handle different categories of widgets and
130 still have the possibility to draw something in the client area.
131 It was therefore required to write a special purpose GTK widget, that would
132 represent a client area in the sense of wxWidgets capable to do the jobs
133 2), 3) and 4). I have written this class and it resides in win_gtk.c of
136 All windows must have a widget, with which they interact with other under-
137 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
138 the wxWindow class has a member variable called m_widget which holds a
139 pointer to this widget. When the window class represents a GTK native widget,
140 this is (in most cases) the only GTK widget the class manages. E.g. the
141 wxStaticText class handles only a GtkLabel widget a pointer to which you
142 can find in m_widget (defined in wxWindow)
144 When the class has a client area for drawing into and for containing children
145 it has to handle the client area widget (of the type GtkPizza, defined in
146 win_gtk.c), but there could be any number of widgets, handled by a class
147 The common rule for all windows is only, that the widget that interacts with
148 the rest of GTK must be referenced in m_widget and all other widgets must be
149 children of this widget on the GTK level. The top-most widget, which also
150 represents the client area, must be in the m_wxwindow field and must be of
153 As I said, the window classes that display a GTK native widget only have
154 one widget, so in the case of e.g. the wxButton class m_widget holds a
155 pointer to a GtkButton widget. But windows with client areas (for drawing
156 and children) have a m_widget field that is a pointer to a GtkScrolled-
157 Window and a m_wxwindow field that is pointer to a GtkPizza and this
158 one is (in the GTK sense) a child of the GtkScrolledWindow.
160 If the m_wxwindow field is set, then all input to this widget is inter-
161 cepted and sent to the wxWidgets class. If not, all input to the widget
162 that gets pointed to by m_widget gets intercepted and sent to the class.
166 The design of scrolling in wxWidgets is markedly different from that offered
167 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
168 clicking on a scrollbar belonging to scrolled window will inevitably move
169 the window. In wxWidgets, the scrollbar will only emit an event, send this
170 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
171 which actually moves the window and its subchildren. Note that GtkPizza
172 memorizes how much it has been scrolled but that wxWidgets forgets this
173 so that the two coordinates systems have to be kept in synch. This is done
174 in various places using the pizza->xoffset and pizza->yoffset values.
178 Singularily the most broken code in GTK is the code that is supposed to
179 inform subwindows (child windows) about new positions. Very often, duplicate
180 events are sent without changes in size or position, equally often no
181 events are sent at all (All this is due to a bug in the GtkContainer code
182 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
183 GTK's own system and it simply waits for size events for toplevel windows
184 and then iterates down the respective size events to all window. This has
185 the disadvantage that windows might get size events before the GTK widget
186 actually has the reported size. This doesn't normally pose any problem, but
187 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
188 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
189 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
190 window that is used for OpenGL output really has that size (as reported by
195 If someone at some point of time feels the immense desire to have a look at,
196 change or attempt to optimise the Refresh() logic, this person will need an
197 intimate understanding of what "draw" and "expose" events are and what
198 they are used for, in particular when used in connection with GTK's
199 own windowless widgets. Beware.
203 Cursors, too, have been a constant source of pleasure. The main difficulty
204 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
205 for the parent. To prevent this from doing too much harm, I use idle time
206 to set the cursor over and over again, starting from the toplevel windows
207 and ending with the youngest generation (speaking of parent and child windows).
208 Also don't forget that cursors (like much else) are connected to GdkWindows,
209 not GtkWidgets and that the "window" field of a GtkWidget might very well
210 point to the GdkWindow of the parent widget (-> "window-less widget") and
211 that the two obviously have very different meanings.
215 //-----------------------------------------------------------------------------
217 //-----------------------------------------------------------------------------
219 extern wxList wxPendingDelete
;
220 extern bool g_blockEventsOnDrag
;
221 extern bool g_blockEventsOnScroll
;
222 extern wxCursor g_globalCursor
;
224 static GdkGC
*g_eraseGC
= NULL
;
226 // mouse capture state: the window which has it and if the mouse is currently
228 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
229 static bool g_captureWindowHasMouse
= false;
231 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
233 // the last window which had the focus - this is normally never NULL (except
234 // if we never had focus at all) as even when g_focusWindow is NULL it still
235 // keeps its previous value
236 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
238 // If a window get the focus set but has not been realized
239 // yet, defer setting the focus to idle time.
240 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
242 extern bool g_mainThreadLocked
;
244 //-----------------------------------------------------------------------------
246 //-----------------------------------------------------------------------------
251 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
253 # define DEBUG_MAIN_THREAD
256 #define DEBUG_MAIN_THREAD
259 // the trace mask used for the focus debugging messages
260 #define TRACE_FOCUS _T("focus")
262 //-----------------------------------------------------------------------------
263 // missing gdk functions
264 //-----------------------------------------------------------------------------
267 gdk_window_warp_pointer (GdkWindow
*window
,
272 window
= gdk_get_default_root_window();
274 if (!GDK_WINDOW_DESTROYED(window
))
276 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
277 None
, /* not source window -> move from anywhere */
278 GDK_WINDOW_XID(window
), /* dest window */
279 0, 0, 0, 0, /* not source window -> move from anywhere */
284 //-----------------------------------------------------------------------------
285 // local code (see below)
286 //-----------------------------------------------------------------------------
288 // returns the child of win which currently has focus or NULL if not found
290 // Note: can't be static, needed by textctrl.cpp.
291 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
293 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
295 return (wxWindow
*)NULL
;
297 if ( winFocus
== win
)
298 return (wxWindow
*)win
;
300 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
302 node
= node
->GetNext() )
304 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
309 return (wxWindow
*)NULL
;
312 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
314 // wxUniversal widgets draw the borders and scrollbars themselves
315 #ifndef __WXUNIVERSAL__
322 if (win
->m_hasScrolling
)
324 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
326 GtkRequisition vscroll_req
;
327 vscroll_req
.width
= 2;
328 vscroll_req
.height
= 2;
329 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
330 (scroll_window
->vscrollbar
, &vscroll_req
);
332 GtkRequisition hscroll_req
;
333 hscroll_req
.width
= 2;
334 hscroll_req
.height
= 2;
335 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
336 (scroll_window
->hscrollbar
, &hscroll_req
);
338 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
340 if (scroll_window
->vscrollbar_visible
)
342 dw
+= vscroll_req
.width
;
343 dw
+= scroll_class
->scrollbar_spacing
;
346 if (scroll_window
->hscrollbar_visible
)
348 dh
+= hscroll_req
.height
;
349 dh
+= scroll_class
->scrollbar_spacing
;
355 if (GTK_WIDGET_NO_WINDOW (widget
))
357 dx
+= widget
->allocation
.x
;
358 dy
+= widget
->allocation
.y
;
361 if (win
->HasFlag(wxRAISED_BORDER
))
363 gtk_paint_shadow (widget
->style
,
367 NULL
, NULL
, NULL
, // FIXME: No clipping?
369 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
373 if (win
->HasFlag(wxSUNKEN_BORDER
))
375 gtk_paint_shadow (widget
->style
,
379 NULL
, NULL
, NULL
, // FIXME: No clipping?
381 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
385 if (win
->HasFlag(wxSIMPLE_BORDER
))
388 gc
= gdk_gc_new( widget
->window
);
389 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
390 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
392 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
393 g_object_unref (G_OBJECT (gc
));
396 #endif // __WXUNIVERSAL__
399 //-----------------------------------------------------------------------------
400 // "expose_event" of m_widget
401 //-----------------------------------------------------------------------------
405 gtk_window_own_expose_callback( GtkWidget
*widget
,
406 GdkEventExpose
*gdk_event
,
409 if (gdk_event
->count
> 0) return FALSE
;
411 draw_frame( widget
, win
);
413 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
419 //-----------------------------------------------------------------------------
420 // "size_request" of m_widget
421 //-----------------------------------------------------------------------------
423 // make it extern because wxStaticText needs to disconnect this one
425 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
426 GtkRequisition
*requisition
,
430 win
->GetSize( &w
, &h
);
436 requisition
->height
= h
;
437 requisition
->width
= w
;
443 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
444 GtkRequisition
*requisition
,
447 // This callback is actually hooked into the text entry
448 // of the combo box, not the GtkHBox.
451 win
->GetSize( &w
, &h
);
457 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
459 GtkRequisition entry_req
;
461 entry_req
.height
= 2;
462 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
463 (gcombo
->button
, &entry_req
);
465 requisition
->width
= w
- entry_req
.width
;
466 requisition
->height
= entry_req
.height
;
470 //-----------------------------------------------------------------------------
471 // "expose_event" of m_wxwindow
472 //-----------------------------------------------------------------------------
476 gtk_window_expose_callback( GtkWidget
*widget
,
477 GdkEventExpose
*gdk_event
,
483 wxapp_install_idle_handler();
485 // This callback gets called in drawing-idle time under
486 // GTK 2.0, so we don't need to defer anything to idle
489 GtkPizza
*pizza
= GTK_PIZZA( widget
);
490 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
495 wxPrintf( wxT("OnExpose from ") );
496 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
497 wxPrintf( win
->GetClassInfo()->GetClassName() );
498 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
499 (int)gdk_event
->area
.y
,
500 (int)gdk_event
->area
.width
,
501 (int)gdk_event
->area
.height
);
506 win
->m_wxwindow
->style
,
510 (GdkRectangle
*) NULL
,
512 (char *)"button", // const_cast
517 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
519 win
->GtkSendPaintEvents();
522 // Let parent window draw window-less widgets
523 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
529 //-----------------------------------------------------------------------------
530 // "key_press_event" from any window
531 //-----------------------------------------------------------------------------
533 // set WXTRACE to this to see the key event codes on the console
534 #define TRACE_KEYS _T("keyevent")
536 // translates an X key symbol to WXK_XXX value
538 // if isChar is true it means that the value returned will be used for EVT_CHAR
539 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
540 // for example, while if it is false it means that the value is going to be
541 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
543 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
549 // Shift, Control and Alt don't generate the CHAR events at all
552 key_code
= isChar
? 0 : WXK_SHIFT
;
556 key_code
= isChar
? 0 : WXK_CONTROL
;
564 key_code
= isChar
? 0 : WXK_ALT
;
567 // neither do the toggle modifies
568 case GDK_Scroll_Lock
:
569 key_code
= isChar
? 0 : WXK_SCROLL
;
573 key_code
= isChar
? 0 : WXK_CAPITAL
;
577 key_code
= isChar
? 0 : WXK_NUMLOCK
;
581 // various other special keys
594 case GDK_ISO_Left_Tab
:
601 key_code
= WXK_RETURN
;
605 key_code
= WXK_CLEAR
;
609 key_code
= WXK_PAUSE
;
613 key_code
= WXK_SELECT
;
617 key_code
= WXK_PRINT
;
621 key_code
= WXK_EXECUTE
;
625 key_code
= WXK_ESCAPE
;
628 // cursor and other extended keyboard keys
630 key_code
= WXK_DELETE
;
646 key_code
= WXK_RIGHT
;
653 case GDK_Prior
: // == GDK_Page_Up
654 key_code
= WXK_PAGEUP
;
657 case GDK_Next
: // == GDK_Page_Down
658 key_code
= WXK_PAGEDOWN
;
670 key_code
= WXK_INSERT
;
685 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
689 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
693 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
697 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
701 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
705 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
709 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
713 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
717 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
721 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
725 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
729 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
733 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
736 case GDK_KP_Prior
: // == GDK_KP_Page_Up
737 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
740 case GDK_KP_Next
: // == GDK_KP_Page_Down
741 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
745 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
749 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
753 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
757 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
761 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
764 case GDK_KP_Multiply
:
765 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
769 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
772 case GDK_KP_Separator
:
773 // FIXME: what is this?
774 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
777 case GDK_KP_Subtract
:
778 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
782 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
786 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
803 key_code
= WXK_F1
+ keysym
- GDK_F1
;
813 static inline bool wxIsAsciiKeysym(KeySym ks
)
818 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
820 GdkEventKey
*gdk_event
)
824 GdkModifierType state
;
825 if (gdk_event
->window
)
826 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
828 event
.SetTimestamp( gdk_event
->time
);
829 event
.SetId(win
->GetId());
830 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
831 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
832 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
833 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
834 event
.m_scanCode
= gdk_event
->keyval
;
835 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
836 event
.m_rawFlags
= 0;
838 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
840 wxGetMousePosition( &x
, &y
);
841 win
->ScreenToClient( &x
, &y
);
844 event
.SetEventObject( win
);
849 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
851 GdkEventKey
*gdk_event
)
853 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
854 // but only event->keyval which is quite useless to us, so remember
855 // the last character from GDK_KEY_PRESS and reuse it as last resort
857 // NB: should be MT-safe as we're always called from the main thread only
862 } s_lastKeyPress
= { 0, 0 };
864 KeySym keysym
= gdk_event
->keyval
;
866 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
867 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
871 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
875 // do we have the translation or is it a plain ASCII character?
876 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
878 // we should use keysym if it is ASCII as X does some translations
879 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
880 // which we don't want here (but which we do use for OnChar())
881 if ( !wxIsAsciiKeysym(keysym
) )
883 keysym
= (KeySym
)gdk_event
->string
[0];
886 // we want to always get the same key code when the same key is
887 // pressed regardless of the state of the modifiers, i.e. on a
888 // standard US keyboard pressing '5' or '%' ('5' key with
889 // Shift) should result in the same key code in OnKeyDown():
890 // '5' (although OnChar() will get either '5' or '%').
892 // to do it we first translate keysym to keycode (== scan code)
893 // and then back but always using the lower register
894 Display
*dpy
= (Display
*)wxGetDisplay();
895 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
897 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
899 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
901 // use the normalized, i.e. lower register, keysym if we've
903 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
905 // as explained above, we want to have lower register key codes
906 // normally but for the letter keys we want to have the upper ones
908 // NB: don't use XConvertCase() here, we want to do it for letters
910 key_code
= toupper(key_code
);
912 else // non ASCII key, what to do?
914 // by default, ignore it
917 // but if we have cached information from the last KEY_PRESS
918 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
921 if ( keysym
== s_lastKeyPress
.keysym
)
923 key_code
= s_lastKeyPress
.keycode
;
928 if ( gdk_event
->type
== GDK_KEY_PRESS
)
930 // remember it to be reused for KEY_UP event later
931 s_lastKeyPress
.keysym
= keysym
;
932 s_lastKeyPress
.keycode
= key_code
;
936 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
938 // sending unknown key events doesn't really make sense
942 // now fill all the other fields
943 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
945 event
.m_keyCode
= key_code
;
947 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
949 event
.m_uniChar
= key_code
;
959 GtkIMContext
*context
;
960 GdkEventKey
*lastKeyEvent
;
964 context
= gtk_im_multicontext_new();
969 g_object_unref(context
);
975 gtk_window_key_press_callback( GtkWidget
*widget
,
976 GdkEventKey
*gdk_event
,
982 wxapp_install_idle_handler();
986 if (g_blockEventsOnDrag
)
990 wxKeyEvent
event( wxEVT_KEY_DOWN
);
992 bool return_after_IM
= false;
994 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
996 // Emit KEY_DOWN event
997 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1001 // Return after IM processing as we cannot do
1002 // anything with it anyhow.
1003 return_after_IM
= true;
1006 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1007 // When we get a key_press event here, it could be originate
1008 // from the current widget or its child widgets. However, only the widget
1009 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1010 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1011 // originated from its child widgets and shouldn't be passed to IM context.
1012 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1013 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1014 // widgets has both IM context and input focus, the event should be filtered
1015 // by gtk_im_context_filter_keypress().
1016 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1017 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1019 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1020 // docs, if IM filter returns true, no further processing should be done.
1021 // we should send the key_down event anyway.
1022 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1023 win
->m_imData
->lastKeyEvent
= NULL
;
1024 if (intercepted_by_IM
)
1026 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1031 if (return_after_IM
)
1037 wxWindowGTK
*ancestor
= win
;
1040 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1043 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1044 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1047 if (ancestor
->IsTopLevel())
1049 ancestor
= ancestor
->GetParent();
1052 #endif // wxUSE_ACCEL
1054 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1055 // will only be sent if it is not in an accelerator table.
1059 KeySym keysym
= gdk_event
->keyval
;
1060 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1061 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1064 if ( wxIsAsciiKeysym(keysym
) )
1067 key_code
= (unsigned char)keysym
;
1069 // gdk_event->string is actually deprecated
1070 else if ( gdk_event
->length
== 1 )
1072 key_code
= (unsigned char)gdk_event
->string
[0];
1078 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1080 event
.m_keyCode
= key_code
;
1082 // To conform to the docs we need to translate Ctrl-alpha
1083 // characters to values in the range 1-26.
1084 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1086 event
.m_keyCode
= key_code
- 'a' + 1;
1088 event
.m_uniChar
= event
.m_keyCode
;
1092 // Implement OnCharHook by checking ancestor top level windows
1093 wxWindow
*parent
= win
;
1094 while (parent
&& !parent
->IsTopLevel())
1095 parent
= parent
->GetParent();
1098 event
.SetEventType( wxEVT_CHAR_HOOK
);
1099 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1104 event
.SetEventType(wxEVT_CHAR
);
1105 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1114 // win is a control: tab can be propagated up
1116 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1117 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1118 // have this style, yet choose not to process this particular TAB in which
1119 // case TAB must still work as a navigational character
1120 // JS: enabling again to make consistent with other platforms
1121 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1122 // navigation behaviour)
1124 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1126 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1128 wxNavigationKeyEvent new_event
;
1129 new_event
.SetEventObject( win
->GetParent() );
1130 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1131 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1132 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1133 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1134 new_event
.SetCurrentFocus( win
);
1135 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1138 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1140 (gdk_event
->keyval
== GDK_Escape
) )
1142 // however only do it if we have a Cancel button in the dialog,
1143 // otherwise the user code may get confused by the events from a
1144 // non-existing button and, worse, a wxButton might get button event
1145 // from another button which is not really expected
1146 wxWindow
*winForCancel
= win
,
1148 while ( winForCancel
)
1150 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1153 // found a cancel button
1157 if ( winForCancel
->IsTopLevel() )
1159 // no need to look further
1163 // maybe our parent has a cancel button?
1164 winForCancel
= winForCancel
->GetParent();
1169 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1170 eventClick
.SetEventObject(btnCancel
);
1171 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1177 g_signal_stop_emission_by_name (widget
, "key_press_event");
1187 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1191 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1193 // take modifiers, cursor position, timestamp etc. from the last
1194 // key_press_event that was fed into Input Method:
1195 if (window
->m_imData
->lastKeyEvent
)
1197 wxFillOtherKeyEventFields(event
,
1198 window
, window
->m_imData
->lastKeyEvent
);
1201 const wxWxCharBuffer
data(wxGTK_CONV_BACK(str
));
1207 // Implement OnCharHook by checking ancestor top level windows
1208 wxWindow
*parent
= window
;
1209 while (parent
&& !parent
->IsTopLevel())
1210 parent
= parent
->GetParent();
1212 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1215 event
.m_uniChar
= *pstr
;
1216 // Backward compatible for ISO-8859-1
1217 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1218 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1220 event
.m_keyCode
= *pstr
;
1221 #endif // wxUSE_UNICODE
1223 // To conform to the docs we need to translate Ctrl-alpha
1224 // characters to values in the range 1-26.
1225 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1227 event
.m_keyCode
= *pstr
- 'a' + 1;
1229 event
.m_uniChar
= event
.m_keyCode
;
1235 event
.SetEventType( wxEVT_CHAR_HOOK
);
1236 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1241 event
.SetEventType(wxEVT_CHAR
);
1242 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1249 //-----------------------------------------------------------------------------
1250 // "key_release_event" from any window
1251 //-----------------------------------------------------------------------------
1255 gtk_window_key_release_callback( GtkWidget
*widget
,
1256 GdkEventKey
*gdk_event
,
1262 wxapp_install_idle_handler();
1267 if (g_blockEventsOnDrag
)
1270 wxKeyEvent
event( wxEVT_KEY_UP
);
1271 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1273 // unknown key pressed, ignore (the event would be useless anyhow)
1277 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1280 g_signal_stop_emission_by_name (widget
, "key_release_event");
1285 // ============================================================================
1287 // ============================================================================
1289 // ----------------------------------------------------------------------------
1290 // mouse event processing helpers
1291 // ----------------------------------------------------------------------------
1293 // init wxMouseEvent with the info from GdkEventXXX struct
1294 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1295 wxMouseEvent
& event
,
1298 event
.SetTimestamp( gdk_event
->time
);
1299 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1300 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1301 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1302 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1303 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1304 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1305 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1306 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1308 event
.m_linesPerAction
= 3;
1309 event
.m_wheelDelta
= 120;
1310 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1311 event
.m_wheelRotation
= 120;
1312 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1313 event
.m_wheelRotation
= -120;
1316 wxPoint pt
= win
->GetClientAreaOrigin();
1317 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1318 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1320 event
.SetEventObject( win
);
1321 event
.SetId( win
->GetId() );
1322 event
.SetTimestamp( gdk_event
->time
);
1325 static void AdjustEventButtonState(wxMouseEvent
& event
)
1327 // GDK reports the old state of the button for a button press event, but
1328 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1329 // for a LEFT_DOWN event, not FALSE, so we will invert
1330 // left/right/middleDown for the corresponding click events
1332 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1333 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1334 (event
.GetEventType() == wxEVT_LEFT_UP
))
1336 event
.m_leftDown
= !event
.m_leftDown
;
1340 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1341 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1342 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1344 event
.m_middleDown
= !event
.m_middleDown
;
1348 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1349 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1350 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1352 event
.m_rightDown
= !event
.m_rightDown
;
1357 // find the window to send the mouse event too
1359 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1364 if (win
->m_wxwindow
)
1366 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1367 xx
+= pizza
->xoffset
;
1368 yy
+= pizza
->yoffset
;
1371 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1374 wxWindowGTK
*child
= node
->GetData();
1376 node
= node
->GetNext();
1377 if (!child
->IsShown())
1380 if (child
->IsTransparentForMouse())
1382 // wxStaticBox is transparent in the box itself
1383 int xx1
= child
->m_x
;
1384 int yy1
= child
->m_y
;
1385 int xx2
= child
->m_x
+ child
->m_width
;
1386 int yy2
= child
->m_y
+ child
->m_height
;
1389 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1391 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1393 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1395 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1406 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1407 (child
->m_x
<= xx
) &&
1408 (child
->m_y
<= yy
) &&
1409 (child
->m_x
+child
->m_width
>= xx
) &&
1410 (child
->m_y
+child
->m_height
>= yy
))
1423 //-----------------------------------------------------------------------------
1424 // "button_press_event"
1425 //-----------------------------------------------------------------------------
1429 gtk_window_button_press_callback( GtkWidget
*widget
,
1430 GdkEventButton
*gdk_event
,
1436 wxapp_install_idle_handler();
1439 wxPrintf( wxT("1) OnButtonPress from ") );
1440 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1441 wxPrintf( win->GetClassInfo()->GetClassName() );
1442 wxPrintf( wxT(".\n") );
1444 if (!win
->m_hasVMT
) return FALSE
;
1445 if (g_blockEventsOnDrag
) return TRUE
;
1446 if (g_blockEventsOnScroll
) return TRUE
;
1448 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1450 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1452 gtk_widget_grab_focus( win
->m_wxwindow
);
1454 wxPrintf( wxT("GrabFocus from ") );
1455 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1456 wxPrintf( win->GetClassInfo()->GetClassName() );
1457 wxPrintf( wxT(".\n") );
1461 // GDK sends surplus button down events
1462 // before a double click event. We
1463 // need to filter these out.
1464 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1466 GdkEvent
*peek_event
= gdk_event_peek();
1469 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1470 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1472 gdk_event_free( peek_event
);
1477 gdk_event_free( peek_event
);
1482 wxEventType event_type
= wxEVT_NULL
;
1484 // GdkDisplay is a GTK+ 2.2.0 thing
1485 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1486 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1487 !gtk_check_version(2,2,0) &&
1488 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1490 // Reset GDK internal timestamp variables in order to disable GDK
1491 // triple click events. GDK will then next time believe no button has
1492 // been clicked just before, and send a normal button click event.
1493 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1494 display
->button_click_time
[1] = 0;
1495 display
->button_click_time
[0] = 0;
1499 if (gdk_event
->button
== 1)
1501 // note that GDK generates triple click events which are not supported
1502 // by wxWidgets but still have to be passed to the app as otherwise
1503 // clicks would simply go missing
1504 switch (gdk_event
->type
)
1506 // we shouldn't get triple clicks at all for GTK2 because we
1507 // suppress them artificially using the code above but we still
1508 // should map them to something for GTK1 and not just ignore them
1509 // as this would lose clicks
1510 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1511 case GDK_BUTTON_PRESS
:
1512 event_type
= wxEVT_LEFT_DOWN
;
1515 case GDK_2BUTTON_PRESS
:
1516 event_type
= wxEVT_LEFT_DCLICK
;
1520 // just to silence gcc warnings
1524 else if (gdk_event
->button
== 2)
1526 switch (gdk_event
->type
)
1528 case GDK_3BUTTON_PRESS
:
1529 case GDK_BUTTON_PRESS
:
1530 event_type
= wxEVT_MIDDLE_DOWN
;
1533 case GDK_2BUTTON_PRESS
:
1534 event_type
= wxEVT_MIDDLE_DCLICK
;
1541 else if (gdk_event
->button
== 3)
1543 switch (gdk_event
->type
)
1545 case GDK_3BUTTON_PRESS
:
1546 case GDK_BUTTON_PRESS
:
1547 event_type
= wxEVT_RIGHT_DOWN
;
1550 case GDK_2BUTTON_PRESS
:
1551 event_type
= wxEVT_RIGHT_DCLICK
;
1558 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1560 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1562 event_type
= wxEVT_MOUSEWHEEL
;
1566 if ( event_type
== wxEVT_NULL
)
1568 // unknown mouse button or click type
1572 wxMouseEvent
event( event_type
);
1573 InitMouseEvent( win
, event
, gdk_event
);
1575 AdjustEventButtonState(event
);
1577 // wxListBox actually gets mouse events from the item, so we need to give it
1578 // a chance to correct this
1579 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1581 // find the correct window to send the event to: it may be a different one
1582 // from the one which got it at GTK+ level because some controls don't have
1583 // their own X window and thus cannot get any events.
1584 if ( !g_captureWindow
)
1585 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1587 if (win
->GetEventHandler()->ProcessEvent( event
))
1589 g_signal_stop_emission_by_name (widget
, "button_press_event");
1593 if (event_type
== wxEVT_RIGHT_DOWN
)
1595 // generate a "context menu" event: this is similar to right mouse
1596 // click under many GUIs except that it is generated differently
1597 // (right up under MSW, ctrl-click under Mac, right down here) and
1599 // (a) it's a command event and so is propagated to the parent
1600 // (b) under some ports it can be generated from kbd too
1601 // (c) it uses screen coords (because of (a))
1602 wxContextMenuEvent
evtCtx(
1605 win
->ClientToScreen(event
.GetPosition()));
1606 evtCtx
.SetEventObject(win
);
1607 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1614 //-----------------------------------------------------------------------------
1615 // "button_release_event"
1616 //-----------------------------------------------------------------------------
1620 gtk_window_button_release_callback( GtkWidget
*widget
,
1621 GdkEventButton
*gdk_event
,
1627 wxapp_install_idle_handler();
1629 if (!win
->m_hasVMT
) return FALSE
;
1630 if (g_blockEventsOnDrag
) return FALSE
;
1631 if (g_blockEventsOnScroll
) return FALSE
;
1633 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1635 wxEventType event_type
= wxEVT_NULL
;
1637 switch (gdk_event
->button
)
1640 event_type
= wxEVT_LEFT_UP
;
1644 event_type
= wxEVT_MIDDLE_UP
;
1648 event_type
= wxEVT_RIGHT_UP
;
1652 // unknwon button, don't process
1656 wxMouseEvent
event( event_type
);
1657 InitMouseEvent( win
, event
, gdk_event
);
1659 AdjustEventButtonState(event
);
1661 // same wxListBox hack as above
1662 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1664 if ( !g_captureWindow
)
1665 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1667 if (win
->GetEventHandler()->ProcessEvent( event
))
1669 g_signal_stop_emission_by_name (widget
, "button_release_event");
1677 //-----------------------------------------------------------------------------
1678 // "motion_notify_event"
1679 //-----------------------------------------------------------------------------
1683 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1684 GdkEventMotion
*gdk_event
,
1690 wxapp_install_idle_handler();
1692 if (!win
->m_hasVMT
) return FALSE
;
1693 if (g_blockEventsOnDrag
) return FALSE
;
1694 if (g_blockEventsOnScroll
) return FALSE
;
1696 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1698 if (gdk_event
->is_hint
)
1702 GdkModifierType state
;
1703 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1709 printf( "OnMotion from " );
1710 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1711 printf( win->GetClassInfo()->GetClassName() );
1715 wxMouseEvent
event( wxEVT_MOTION
);
1716 InitMouseEvent(win
, event
, gdk_event
);
1718 if ( g_captureWindow
)
1720 // synthetize a mouse enter or leave event if needed
1721 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1722 // This seems to be necessary and actually been added to
1723 // GDK itself in version 2.0.X
1726 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1727 if ( hasMouse
!= g_captureWindowHasMouse
)
1729 // the mouse changed window
1730 g_captureWindowHasMouse
= hasMouse
;
1732 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1733 : wxEVT_LEAVE_WINDOW
);
1734 InitMouseEvent(win
, eventM
, gdk_event
);
1735 eventM
.SetEventObject(win
);
1736 win
->GetEventHandler()->ProcessEvent(eventM
);
1741 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1744 if ( !g_captureWindow
)
1746 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1747 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1749 // Rewrite cursor handling here (away from idle).
1753 if (win
->GetEventHandler()->ProcessEvent( event
))
1755 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1763 //-----------------------------------------------------------------------------
1764 // "mouse_wheel_event"
1765 //-----------------------------------------------------------------------------
1769 gtk_window_wheel_callback (GtkWidget
* widget
,
1770 GdkEventScroll
* gdk_event
,
1776 wxapp_install_idle_handler();
1778 wxEventType event_type
= wxEVT_NULL
;
1779 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1780 event_type
= wxEVT_MOUSEWHEEL
;
1781 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1782 event_type
= wxEVT_MOUSEWHEEL
;
1786 wxMouseEvent
event( event_type
);
1787 // Can't use InitMouse macro because scroll events don't have button
1788 event
.SetTimestamp( gdk_event
->time
);
1789 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1790 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1791 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1792 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1793 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1794 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1795 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1796 event
.m_linesPerAction
= 3;
1797 event
.m_wheelDelta
= 120;
1798 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1799 event
.m_wheelRotation
= 120;
1801 event
.m_wheelRotation
= -120;
1803 wxPoint pt
= win
->GetClientAreaOrigin();
1804 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1805 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1807 event
.SetEventObject( win
);
1808 event
.SetId( win
->GetId() );
1809 event
.SetTimestamp( gdk_event
->time
);
1811 if (win
->GetEventHandler()->ProcessEvent( event
))
1813 g_signal_stop_emission_by_name (widget
, "scroll_event");
1821 //-----------------------------------------------------------------------------
1823 //-----------------------------------------------------------------------------
1825 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1827 wxContextMenuEvent
event(
1831 event
.SetEventObject(win
);
1832 return win
->GetEventHandler()->ProcessEvent(event
);
1836 //-----------------------------------------------------------------------------
1838 //-----------------------------------------------------------------------------
1840 // send the wxChildFocusEvent and wxFocusEvent, common code of
1841 // gtk_window_focus_in_callback() and SetFocus()
1842 static bool DoSendFocusEvents(wxWindow
*win
)
1844 // Notify the parent keeping track of focus for the kbd navigation
1845 // purposes that we got it.
1846 wxChildFocusEvent
eventChildFocus(win
);
1847 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1849 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1850 eventFocus
.SetEventObject(win
);
1852 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1857 gtk_window_focus_in_callback( GtkWidget
*widget
,
1858 GdkEventFocus
*WXUNUSED(event
),
1864 wxapp_install_idle_handler();
1867 gtk_im_context_focus_in(win
->m_imData
->context
);
1870 g_focusWindow
= win
;
1872 wxLogTrace(TRACE_FOCUS
,
1873 _T("%s: focus in"), win
->GetName().c_str());
1877 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1881 // caret needs to be informed about focus change
1882 wxCaret
*caret
= win
->GetCaret();
1885 caret
->OnSetFocus();
1887 #endif // wxUSE_CARET
1889 gboolean ret
= FALSE
;
1891 // does the window itself think that it has the focus?
1892 if ( !win
->m_hasFocus
)
1894 // not yet, notify it
1895 win
->m_hasFocus
= true;
1897 (void)DoSendFocusEvents(win
);
1902 // Disable default focus handling for custom windows
1903 // since the default GTK+ handler issues a repaint
1904 if (win
->m_wxwindow
)
1911 //-----------------------------------------------------------------------------
1912 // "focus_out_event"
1913 //-----------------------------------------------------------------------------
1917 gtk_window_focus_out_callback( GtkWidget
*widget
,
1918 GdkEventFocus
*gdk_event
,
1924 wxapp_install_idle_handler();
1927 gtk_im_context_focus_out(win
->m_imData
->context
);
1929 wxLogTrace( TRACE_FOCUS
,
1930 _T("%s: focus out"), win
->GetName().c_str() );
1933 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1937 g_focusWindow
= (wxWindowGTK
*)NULL
;
1945 // caret needs to be informed about focus change
1946 wxCaret
*caret
= win
->GetCaret();
1949 caret
->OnKillFocus();
1951 #endif // wxUSE_CARET
1953 gboolean ret
= FALSE
;
1955 // don't send the window a kill focus event if it thinks that it doesn't
1956 // have focus already
1957 if ( win
->m_hasFocus
)
1959 win
->m_hasFocus
= false;
1961 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1962 event
.SetEventObject( win
);
1964 (void)win
->GetEventHandler()->ProcessEvent( event
);
1969 // Disable default focus handling for custom windows
1970 // since the default GTK+ handler issues a repaint
1971 if (win
->m_wxwindow
)
1978 //-----------------------------------------------------------------------------
1979 // "enter_notify_event"
1980 //-----------------------------------------------------------------------------
1984 gtk_window_enter_callback( GtkWidget
*widget
,
1985 GdkEventCrossing
*gdk_event
,
1991 wxapp_install_idle_handler();
1993 if (!win
->m_hasVMT
) return FALSE
;
1994 if (g_blockEventsOnDrag
) return FALSE
;
1996 // Event was emitted after a grab
1997 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1999 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2003 GdkModifierType state
= (GdkModifierType
)0;
2005 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2007 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2008 InitMouseEvent(win
, event
, gdk_event
);
2009 wxPoint pt
= win
->GetClientAreaOrigin();
2010 event
.m_x
= x
+ pt
.x
;
2011 event
.m_y
= y
+ pt
.y
;
2013 if ( !g_captureWindow
)
2015 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2016 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2018 // Rewrite cursor handling here (away from idle).
2022 if (win
->GetEventHandler()->ProcessEvent( event
))
2024 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2032 //-----------------------------------------------------------------------------
2033 // "leave_notify_event"
2034 //-----------------------------------------------------------------------------
2038 gtk_window_leave_callback( GtkWidget
*widget
,
2039 GdkEventCrossing
*gdk_event
,
2045 wxapp_install_idle_handler();
2047 if (!win
->m_hasVMT
) return FALSE
;
2048 if (g_blockEventsOnDrag
) return FALSE
;
2050 // Event was emitted after an ungrab
2051 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2053 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2055 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2056 event
.SetTimestamp( gdk_event
->time
);
2057 event
.SetEventObject( win
);
2061 GdkModifierType state
= (GdkModifierType
)0;
2063 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2065 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2066 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2067 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2068 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2069 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2070 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2071 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2073 wxPoint pt
= win
->GetClientAreaOrigin();
2074 event
.m_x
= x
+ pt
.x
;
2075 event
.m_y
= y
+ pt
.y
;
2077 if (win
->GetEventHandler()->ProcessEvent( event
))
2079 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2087 //-----------------------------------------------------------------------------
2088 // "value_changed" from m_vAdjust
2089 //-----------------------------------------------------------------------------
2092 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2098 wxapp_install_idle_handler();
2100 if (g_blockEventsOnDrag
) return;
2102 if (!win
->m_hasVMT
) return;
2104 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2105 if (fabs(diff
) < 0.2) return;
2107 win
->m_oldVerticalPos
= adjust
->value
;
2109 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2111 int value
= (int)(adjust
->value
+0.5);
2113 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2114 event
.SetEventObject( win
);
2115 win
->GetEventHandler()->ProcessEvent( event
);
2119 //-----------------------------------------------------------------------------
2120 // "value_changed" from m_hAdjust
2121 //-----------------------------------------------------------------------------
2124 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2130 wxapp_install_idle_handler();
2132 if (g_blockEventsOnDrag
) return;
2133 if (!win
->m_hasVMT
) return;
2135 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2136 if (fabs(diff
) < 0.2) return;
2138 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2140 win
->m_oldHorizontalPos
= adjust
->value
;
2142 int value
= (int)(adjust
->value
+0.5);
2144 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2145 event
.SetEventObject( win
);
2146 win
->GetEventHandler()->ProcessEvent( event
);
2150 //-----------------------------------------------------------------------------
2151 // "button_press_event" from scrollbar
2152 //-----------------------------------------------------------------------------
2156 gtk_scrollbar_button_press_callback( GtkWidget
*widget
,
2157 GdkEventButton
*gdk_event
,
2163 wxapp_install_idle_handler();
2166 g_blockEventsOnScroll
= true;
2168 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2170 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2177 //-----------------------------------------------------------------------------
2178 // "button_release_event" from scrollbar
2179 //-----------------------------------------------------------------------------
2183 gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2184 GdkEventButton
*WXUNUSED(gdk_event
),
2189 // don't test here as we can release the mouse while being over
2190 // a different window than the slider
2192 // if (gdk_event->window != widget->slider) return FALSE;
2194 g_blockEventsOnScroll
= false;
2196 if (win
->m_isScrolling
)
2198 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2202 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2203 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2205 value
= (int)(win
->m_hAdjust
->value
+0.5);
2208 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2210 value
= (int)(win
->m_vAdjust
->value
+0.5);
2214 wxScrollWinEvent
event( command
, value
, dir
);
2215 event
.SetEventObject( win
);
2216 win
->GetEventHandler()->ProcessEvent( event
);
2219 win
->m_isScrolling
= false;
2225 // ----------------------------------------------------------------------------
2226 // this wxWindowBase function is implemented here (in platform-specific file)
2227 // because it is static and so couldn't be made virtual
2228 // ----------------------------------------------------------------------------
2230 wxWindow
*wxWindowBase::DoFindFocus()
2232 // the cast is necessary when we compile in wxUniversal mode
2233 return (wxWindow
*)g_focusWindow
;
2236 //-----------------------------------------------------------------------------
2237 // "realize" from m_widget
2238 //-----------------------------------------------------------------------------
2240 /* We cannot set colours and fonts before the widget has
2241 been realized, so we do this directly after realization. */
2245 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2250 wxapp_install_idle_handler();
2254 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2255 gtk_im_context_set_client_window( win
->m_imData
->context
,
2256 pizza
->bin_window
);
2259 wxWindowCreateEvent
event( win
);
2260 event
.SetEventObject( win
);
2261 win
->GetEventHandler()->ProcessEvent( event
);
2265 //-----------------------------------------------------------------------------
2267 //-----------------------------------------------------------------------------
2271 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2272 GtkAllocation
*WXUNUSED(alloc
),
2276 wxapp_install_idle_handler();
2278 if (!win
->m_hasScrolling
) return;
2280 int client_width
= 0;
2281 int client_height
= 0;
2282 win
->GetClientSize( &client_width
, &client_height
);
2283 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2286 win
->m_oldClientWidth
= client_width
;
2287 win
->m_oldClientHeight
= client_height
;
2289 if (!win
->m_nativeSizeEvent
)
2291 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2292 event
.SetEventObject( win
);
2293 win
->GetEventHandler()->ProcessEvent( event
);
2300 #define WXUNUSED_UNLESS_XIM(param) param
2302 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2305 /* Resize XIM window */
2309 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2310 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2311 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2314 wxapp_install_idle_handler();
2320 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2324 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2325 win
->m_icattr
->preedit_area
.width
= width
;
2326 win
->m_icattr
->preedit_area
.height
= height
;
2327 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2333 //-----------------------------------------------------------------------------
2334 // "realize" from m_wxwindow
2335 //-----------------------------------------------------------------------------
2337 /* Initialize XIM support */
2341 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2342 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2345 wxapp_install_idle_handler();
2348 if (win
->m_ic
) return;
2349 if (!widget
) return;
2350 if (!gdk_im_ready()) return;
2352 win
->m_icattr
= gdk_ic_attr_new();
2353 if (!win
->m_icattr
) return;
2357 GdkColormap
*colormap
;
2358 GdkICAttr
*attr
= win
->m_icattr
;
2359 unsigned attrmask
= GDK_IC_ALL_REQ
;
2361 GdkIMStyle supported_style
= (GdkIMStyle
)
2362 (GDK_IM_PREEDIT_NONE
|
2363 GDK_IM_PREEDIT_NOTHING
|
2364 GDK_IM_PREEDIT_POSITION
|
2365 GDK_IM_STATUS_NONE
|
2366 GDK_IM_STATUS_NOTHING
);
2368 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2369 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2371 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2372 attr
->client_window
= widget
->window
;
2374 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2375 gtk_widget_get_default_colormap ())
2377 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2378 attr
->preedit_colormap
= colormap
;
2381 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2382 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2383 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2384 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2386 switch (style
& GDK_IM_PREEDIT_MASK
)
2388 case GDK_IM_PREEDIT_POSITION
:
2389 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2391 g_warning ("over-the-spot style requires fontset");
2395 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2397 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2398 attr
->spot_location
.x
= 0;
2399 attr
->spot_location
.y
= height
;
2400 attr
->preedit_area
.x
= 0;
2401 attr
->preedit_area
.y
= 0;
2402 attr
->preedit_area
.width
= width
;
2403 attr
->preedit_area
.height
= height
;
2404 attr
->preedit_fontset
= widget
->style
->font
;
2409 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2411 if (win
->m_ic
== NULL
)
2412 g_warning ("Can't create input context.");
2415 mask
= gdk_window_get_events (widget
->window
);
2416 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2417 gdk_window_set_events (widget
->window
, mask
);
2419 if (GTK_WIDGET_HAS_FOCUS(widget
))
2420 gdk_im_begin (win
->m_ic
, widget
->window
);
2426 //-----------------------------------------------------------------------------
2427 // InsertChild for wxWindowGTK.
2428 //-----------------------------------------------------------------------------
2430 /* Callback for wxWindowGTK. This very strange beast has to be used because
2431 * C++ has no virtual methods in a constructor. We have to emulate a
2432 * virtual function here as wxNotebook requires a different way to insert
2433 * a child in it. I had opted for creating a wxNotebookPage window class
2434 * which would have made this superfluous (such in the MDI window system),
2435 * but no-one was listening to me... */
2437 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2439 /* the window might have been scrolled already, do we
2440 have to adapt the position */
2441 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2442 child
->m_x
+= pizza
->xoffset
;
2443 child
->m_y
+= pizza
->yoffset
;
2445 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2446 GTK_WIDGET(child
->m_widget
),
2453 //-----------------------------------------------------------------------------
2455 //-----------------------------------------------------------------------------
2457 wxWindow
*wxGetActiveWindow()
2459 return wxWindow::FindFocus();
2463 wxMouseState
wxGetMouseState()
2469 GdkModifierType mask
;
2471 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2475 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2476 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2477 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2479 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2480 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2481 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2482 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2487 //-----------------------------------------------------------------------------
2489 //-----------------------------------------------------------------------------
2491 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2493 #ifdef __WXUNIVERSAL__
2494 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2496 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2497 #endif // __WXUNIVERSAL__/__WXGTK__
2499 void wxWindowGTK::Init()
2502 m_widget
= (GtkWidget
*) NULL
;
2503 m_wxwindow
= (GtkWidget
*) NULL
;
2504 m_focusWidget
= (GtkWidget
*) NULL
;
2514 m_needParent
= true;
2515 m_isBeingDeleted
= false;
2518 m_nativeSizeEvent
= false;
2520 m_hasScrolling
= false;
2521 m_isScrolling
= false;
2523 m_hAdjust
= (GtkAdjustment
*) NULL
;
2524 m_vAdjust
= (GtkAdjustment
*) NULL
;
2525 m_oldHorizontalPos
=
2526 m_oldVerticalPos
= 0.0;
2528 m_oldClientHeight
= 0;
2532 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2534 m_acceptsFocus
= false;
2537 m_clipPaintRegion
= false;
2539 m_needsStyleChange
= false;
2541 m_cursor
= *wxSTANDARD_CURSOR
;
2544 m_dirtyTabOrder
= false;
2547 wxWindowGTK::wxWindowGTK()
2552 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2557 const wxString
&name
)
2561 Create( parent
, id
, pos
, size
, style
, name
);
2564 bool wxWindowGTK::Create( wxWindow
*parent
,
2569 const wxString
&name
)
2571 if (!PreCreation( parent
, pos
, size
) ||
2572 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2574 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2578 m_insertCallback
= wxInsertChildInWindow
;
2580 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2581 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2583 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2585 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2586 scroll_class
->scrollbar_spacing
= 0;
2588 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2590 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2591 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2593 m_wxwindow
= gtk_pizza_new();
2595 #ifndef __WXUNIVERSAL__
2596 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2598 if (HasFlag(wxRAISED_BORDER
))
2600 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2602 else if (HasFlag(wxSUNKEN_BORDER
))
2604 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2606 else if (HasFlag(wxSIMPLE_BORDER
))
2608 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2612 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2614 #endif // __WXUNIVERSAL__
2616 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2618 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2619 m_acceptsFocus
= true;
2621 // I _really_ don't want scrollbars in the beginning
2622 m_vAdjust
->lower
= 0.0;
2623 m_vAdjust
->upper
= 1.0;
2624 m_vAdjust
->value
= 0.0;
2625 m_vAdjust
->step_increment
= 1.0;
2626 m_vAdjust
->page_increment
= 1.0;
2627 m_vAdjust
->page_size
= 5.0;
2628 g_signal_emit_by_name (m_vAdjust
, "changed");
2629 m_hAdjust
->lower
= 0.0;
2630 m_hAdjust
->upper
= 1.0;
2631 m_hAdjust
->value
= 0.0;
2632 m_hAdjust
->step_increment
= 1.0;
2633 m_hAdjust
->page_increment
= 1.0;
2634 m_hAdjust
->page_size
= 5.0;
2635 g_signal_emit_by_name (m_hAdjust
, "changed");
2637 // these handlers block mouse events to any window during scrolling such as
2638 // motion events and prevent GTK and wxWidgets from fighting over where the
2640 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2641 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2642 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2643 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2644 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2645 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2646 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2647 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2649 // these handlers get notified when screen updates are required either when
2650 // scrolling or when the window size (and therefore scrollbar configuration)
2653 g_signal_connect (m_hAdjust
, "value_changed",
2654 G_CALLBACK (gtk_window_hscroll_callback
), this);
2655 g_signal_connect (m_vAdjust
, "value_changed",
2656 G_CALLBACK (gtk_window_vscroll_callback
), this);
2658 gtk_widget_show( m_wxwindow
);
2661 m_parent
->DoAddChild( this );
2663 m_focusWidget
= m_wxwindow
;
2670 wxWindowGTK::~wxWindowGTK()
2674 if (g_focusWindow
== this)
2675 g_focusWindow
= NULL
;
2677 if ( g_delayedFocus
== this )
2678 g_delayedFocus
= NULL
;
2680 m_isBeingDeleted
= true;
2683 // destroy children before destroying this window itself
2686 // unhook focus handlers to prevent stray events being
2687 // propagated to this (soon to be) dead object
2688 if (m_focusWidget
!= NULL
)
2690 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2691 (gpointer
) gtk_window_focus_in_callback
,
2693 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2694 (gpointer
) gtk_window_focus_out_callback
,
2703 gdk_ic_destroy (m_ic
);
2705 gdk_ic_attr_destroy (m_icattr
);
2708 // delete before the widgets to avoid a crash on solaris
2713 gtk_widget_destroy( m_wxwindow
);
2714 m_wxwindow
= (GtkWidget
*) NULL
;
2719 gtk_widget_destroy( m_widget
);
2720 m_widget
= (GtkWidget
*) NULL
;
2724 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2726 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2728 // Use either the given size, or the default if -1 is given.
2729 // See wxWindowBase for these functions.
2730 m_width
= WidthDefault(size
.x
) ;
2731 m_height
= HeightDefault(size
.y
);
2739 void wxWindowGTK::PostCreation()
2741 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2747 // these get reported to wxWidgets -> wxPaintEvent
2749 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2751 g_signal_connect (m_wxwindow
, "expose_event",
2752 G_CALLBACK (gtk_window_expose_callback
), this);
2754 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2757 // Create input method handler
2758 m_imData
= new wxGtkIMData
;
2760 // Cannot handle drawing preedited text yet
2761 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2763 g_signal_connect (m_imData
->context
, "commit",
2764 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2766 // these are called when the "sunken" or "raised" borders are drawn
2767 g_signal_connect (m_widget
, "expose_event",
2768 G_CALLBACK (gtk_window_own_expose_callback
), this);
2773 if (!GTK_IS_WINDOW(m_widget
))
2775 if (m_focusWidget
== NULL
)
2776 m_focusWidget
= m_widget
;
2780 g_signal_connect (m_focusWidget
, "focus_in_event",
2781 G_CALLBACK (gtk_window_focus_in_callback
), this);
2782 g_signal_connect (m_focusWidget
, "focus_out_event",
2783 G_CALLBACK (gtk_window_focus_out_callback
), this);
2787 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2788 G_CALLBACK (gtk_window_focus_in_callback
), this);
2789 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2790 G_CALLBACK (gtk_window_focus_out_callback
), this);
2794 // connect to the various key and mouse handlers
2796 GtkWidget
*connect_widget
= GetConnectWidget();
2798 ConnectWidget( connect_widget
);
2800 /* We cannot set colours, fonts and cursors before the widget has
2801 been realized, so we do this directly after realization */
2802 g_signal_connect (connect_widget
, "realize",
2803 G_CALLBACK (gtk_window_realized_callback
), this);
2807 // Catch native resize events
2808 g_signal_connect (m_wxwindow
, "size_allocate",
2809 G_CALLBACK (gtk_window_size_callback
), this);
2811 // Initialize XIM support
2812 g_signal_connect (m_wxwindow
, "realize",
2813 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2815 // And resize XIM window
2816 g_signal_connect (m_wxwindow
, "size_allocate",
2817 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2820 if (GTK_IS_COMBO(m_widget
))
2822 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2824 g_signal_connect (gcombo
->entry
, "size_request",
2825 G_CALLBACK (wxgtk_combo_size_request_callback
),
2830 // This is needed if we want to add our windows into native
2831 // GTK controls, such as the toolbar. With this callback, the
2832 // toolbar gets to know the correct size (the one set by the
2833 // programmer). Sadly, it misbehaves for wxComboBox.
2834 g_signal_connect (m_widget
, "size_request",
2835 G_CALLBACK (wxgtk_window_size_request_callback
),
2839 InheritAttributes();
2843 // unless the window was created initially hidden (i.e. Hide() had been
2844 // called before Create()), we should show it at GTK+ level as well
2846 gtk_widget_show( m_widget
);
2849 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2851 g_signal_connect (widget
, "key_press_event",
2852 G_CALLBACK (gtk_window_key_press_callback
), this);
2853 g_signal_connect (widget
, "key_release_event",
2854 G_CALLBACK (gtk_window_key_release_callback
), this);
2855 g_signal_connect (widget
, "button_press_event",
2856 G_CALLBACK (gtk_window_button_press_callback
), this);
2857 g_signal_connect (widget
, "button_release_event",
2858 G_CALLBACK (gtk_window_button_release_callback
), this);
2859 g_signal_connect (widget
, "motion_notify_event",
2860 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2861 g_signal_connect (widget
, "scroll_event",
2862 G_CALLBACK (gtk_window_wheel_callback
), this);
2863 g_signal_connect (widget
, "popup_menu",
2864 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2865 g_signal_connect (widget
, "enter_notify_event",
2866 G_CALLBACK (gtk_window_enter_callback
), this);
2867 g_signal_connect (widget
, "leave_notify_event",
2868 G_CALLBACK (gtk_window_leave_callback
), this);
2871 bool wxWindowGTK::Destroy()
2873 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2877 return wxWindowBase::Destroy();
2880 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2882 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2885 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2887 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2888 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2891 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2894 if (m_resizing
) return; /* I don't like recursions */
2897 int currentX
, currentY
;
2898 GetPosition(¤tX
, ¤tY
);
2899 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2901 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2903 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2905 // calculate the best size if we should auto size the window
2906 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2907 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2909 const wxSize sizeBest
= GetBestSize();
2910 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2912 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2913 height
= sizeBest
.y
;
2921 int minWidth
= GetMinWidth(),
2922 minHeight
= GetMinHeight(),
2923 maxWidth
= GetMaxWidth(),
2924 maxHeight
= GetMaxHeight();
2926 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2927 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2928 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2929 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2931 #if wxUSE_TOOLBAR_NATIVE
2932 if (wxDynamicCast(GetParent(), wxToolBar
))
2934 // don't take the x,y values, they're wrong because toolbar sets them
2935 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2936 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2937 if (GTK_WIDGET_VISIBLE (widget
))
2938 gtk_widget_queue_resize (widget
);
2942 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2944 // don't set the size for children of wxNotebook, just take the values.
2952 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2953 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2955 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2956 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2960 m_x
= x
+ pizza
->xoffset
;
2961 m_y
= y
+ pizza
->yoffset
;
2964 int left_border
= 0;
2965 int right_border
= 0;
2967 int bottom_border
= 0;
2969 /* the default button has a border around it */
2970 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2972 GtkBorder
*default_border
= NULL
;
2973 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2976 left_border
+= default_border
->left
;
2977 right_border
+= default_border
->right
;
2978 top_border
+= default_border
->top
;
2979 bottom_border
+= default_border
->bottom
;
2980 g_free( default_border
);
2984 DoMoveWindow( m_x
-top_border
,
2986 m_width
+left_border
+right_border
,
2987 m_height
+top_border
+bottom_border
);
2992 /* Sometimes the client area changes size without the
2993 whole windows's size changing, but if the whole
2994 windows's size doesn't change, no wxSizeEvent will
2995 normally be sent. Here we add an extra test if
2996 the client test has been changed and this will
2998 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3002 wxPrintf( "OnSize sent from " );
3003 if (GetClassInfo() && GetClassInfo()->GetClassName())
3004 wxPrintf( GetClassInfo()->GetClassName() );
3005 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3008 if (!m_nativeSizeEvent
)
3010 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3011 event
.SetEventObject( this );
3012 GetEventHandler()->ProcessEvent( event
);
3018 void wxWindowGTK::OnInternalIdle()
3020 if ( m_dirtyTabOrder
)
3022 m_dirtyTabOrder
= false;
3026 // Update style if the window was not yet realized
3027 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3028 if (m_needsStyleChange
)
3030 SetBackgroundStyle(GetBackgroundStyle());
3031 m_needsStyleChange
= false;
3034 // Update invalidated regions.
3037 wxCursor cursor
= m_cursor
;
3038 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3042 /* I now set the cursor anew in every OnInternalIdle call
3043 as setting the cursor in a parent window also effects the
3044 windows above so that checking for the current cursor is
3049 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3051 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3053 if (!g_globalCursor
.Ok())
3054 cursor
= *wxSTANDARD_CURSOR
;
3056 window
= m_widget
->window
;
3057 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3058 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3064 GdkWindow
*window
= m_widget
->window
;
3065 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3066 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3071 if (wxUpdateUIEvent::CanUpdate(this))
3072 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3075 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3077 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3079 if (width
) (*width
) = m_width
;
3080 if (height
) (*height
) = m_height
;
3083 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3085 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3089 SetSize( width
, height
);
3096 #ifndef __WXUNIVERSAL__
3097 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3099 /* when using GTK 1.2 we set the shadow border size to 2 */
3103 if (HasFlag(wxSIMPLE_BORDER
))
3105 /* when using GTK 1.2 we set the simple border size to 1 */
3109 #endif // __WXUNIVERSAL__
3113 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3115 GtkRequisition vscroll_req
;
3116 vscroll_req
.width
= 2;
3117 vscroll_req
.height
= 2;
3118 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3119 (scroll_window
->vscrollbar
, &vscroll_req
);
3121 GtkRequisition hscroll_req
;
3122 hscroll_req
.width
= 2;
3123 hscroll_req
.height
= 2;
3124 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3125 (scroll_window
->hscrollbar
, &hscroll_req
);
3127 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3129 if (scroll_window
->vscrollbar_visible
)
3131 dw
+= vscroll_req
.width
;
3132 dw
+= scroll_class
->scrollbar_spacing
;
3135 if (scroll_window
->hscrollbar_visible
)
3137 dh
+= hscroll_req
.height
;
3138 dh
+= scroll_class
->scrollbar_spacing
;
3142 SetSize( width
+dw
, height
+dh
);
3146 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3148 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3152 if (width
) (*width
) = m_width
;
3153 if (height
) (*height
) = m_height
;
3160 #ifndef __WXUNIVERSAL__
3161 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3163 /* when using GTK 1.2 we set the shadow border size to 2 */
3167 if (HasFlag(wxSIMPLE_BORDER
))
3169 /* when using GTK 1.2 we set the simple border size to 1 */
3173 #endif // __WXUNIVERSAL__
3177 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3179 GtkRequisition vscroll_req
;
3180 vscroll_req
.width
= 2;
3181 vscroll_req
.height
= 2;
3182 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3183 (scroll_window
->vscrollbar
, &vscroll_req
);
3185 GtkRequisition hscroll_req
;
3186 hscroll_req
.width
= 2;
3187 hscroll_req
.height
= 2;
3188 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3189 (scroll_window
->hscrollbar
, &hscroll_req
);
3191 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3193 if (scroll_window
->vscrollbar_visible
)
3195 dw
+= vscroll_req
.width
;
3196 dw
+= scroll_class
->scrollbar_spacing
;
3199 if (scroll_window
->hscrollbar_visible
)
3201 dh
+= hscroll_req
.height
;
3202 dh
+= scroll_class
->scrollbar_spacing
;
3206 if (width
) (*width
) = m_width
- dw
;
3207 if (height
) (*height
) = m_height
- dh
;
3211 printf( "GetClientSize, name %s ", GetName().c_str() );
3212 if (width) printf( " width = %d", (*width) );
3213 if (height) printf( " height = %d", (*height) );
3218 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3220 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3224 if (m_parent
&& m_parent
->m_wxwindow
)
3226 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3227 dx
= pizza
->xoffset
;
3228 dy
= pizza
->yoffset
;
3231 if (x
) (*x
) = m_x
- dx
;
3232 if (y
) (*y
) = m_y
- dy
;
3235 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3237 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3239 if (!m_widget
->window
) return;
3241 GdkWindow
*source
= (GdkWindow
*) NULL
;
3243 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3245 source
= m_widget
->window
;
3249 gdk_window_get_origin( source
, &org_x
, &org_y
);
3253 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3255 org_x
+= m_widget
->allocation
.x
;
3256 org_y
+= m_widget
->allocation
.y
;
3264 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3266 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3268 if (!m_widget
->window
) return;
3270 GdkWindow
*source
= (GdkWindow
*) NULL
;
3272 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3274 source
= m_widget
->window
;
3278 gdk_window_get_origin( source
, &org_x
, &org_y
);
3282 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3284 org_x
+= m_widget
->allocation
.x
;
3285 org_y
+= m_widget
->allocation
.y
;
3293 bool wxWindowGTK::Show( bool show
)
3295 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3297 if (!wxWindowBase::Show(show
))
3304 gtk_widget_show( m_widget
);
3306 gtk_widget_hide( m_widget
);
3308 wxShowEvent
eventShow(GetId(), show
);
3309 eventShow
.SetEventObject(this);
3311 GetEventHandler()->ProcessEvent(eventShow
);
3316 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3318 win
->OnParentEnable(enable
);
3320 // Recurse, so that children have the opportunity to Do The Right Thing
3321 // and reset colours that have been messed up by a parent's (really ancestor's)
3323 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3325 node
= node
->GetNext() )
3327 wxWindow
*child
= node
->GetData();
3328 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3329 wxWindowNotifyEnable(child
, enable
);
3333 bool wxWindowGTK::Enable( bool enable
)
3335 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3337 if (!wxWindowBase::Enable(enable
))
3343 gtk_widget_set_sensitive( m_widget
, enable
);
3345 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3347 wxWindowNotifyEnable(this, enable
);
3352 int wxWindowGTK::GetCharHeight() const
3354 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3356 wxFont font
= GetFont();
3357 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3359 PangoContext
*context
= NULL
;
3361 context
= gtk_widget_get_pango_context( m_widget
);
3366 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3367 PangoLayout
*layout
= pango_layout_new(context
);
3368 pango_layout_set_font_description(layout
, desc
);
3369 pango_layout_set_text(layout
, "H", 1);
3370 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3372 PangoRectangle rect
;
3373 pango_layout_line_get_extents(line
, NULL
, &rect
);
3375 g_object_unref( G_OBJECT( layout
) );
3377 return (int) PANGO_PIXELS(rect
.height
);
3380 int wxWindowGTK::GetCharWidth() const
3382 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3384 wxFont font
= GetFont();
3385 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3387 PangoContext
*context
= NULL
;
3389 context
= gtk_widget_get_pango_context( m_widget
);
3394 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3395 PangoLayout
*layout
= pango_layout_new(context
);
3396 pango_layout_set_font_description(layout
, desc
);
3397 pango_layout_set_text(layout
, "g", 1);
3398 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3400 PangoRectangle rect
;
3401 pango_layout_line_get_extents(line
, NULL
, &rect
);
3403 g_object_unref( G_OBJECT( layout
) );
3405 return (int) PANGO_PIXELS(rect
.width
);
3408 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3412 int *externalLeading
,
3413 const wxFont
*theFont
) const
3415 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3417 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3426 PangoContext
*context
= NULL
;
3428 context
= gtk_widget_get_pango_context( m_widget
);
3437 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3438 PangoLayout
*layout
= pango_layout_new(context
);
3439 pango_layout_set_font_description(layout
, desc
);
3441 const wxCharBuffer data
= wxGTK_CONV( string
);
3443 pango_layout_set_text(layout
, data
, strlen(data
));
3446 PangoRectangle rect
;
3447 pango_layout_get_extents(layout
, NULL
, &rect
);
3449 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3450 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3453 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3454 int baseline
= pango_layout_iter_get_baseline(iter
);
3455 pango_layout_iter_free(iter
);
3456 *descent
= *y
- PANGO_PIXELS(baseline
);
3458 if (externalLeading
) (*externalLeading
) = 0; // ??
3460 g_object_unref( G_OBJECT( layout
) );
3463 void wxWindowGTK::SetFocus()
3465 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3468 // don't do anything if we already have focus
3474 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3476 gtk_widget_grab_focus (m_wxwindow
);
3481 if (GTK_IS_CONTAINER(m_widget
))
3483 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3486 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3489 if (!GTK_WIDGET_REALIZED(m_widget
))
3491 // we can't set the focus to the widget now so we remember that
3492 // it should be focused and will do it later, during the idle
3493 // time, as soon as we can
3494 wxLogTrace(TRACE_FOCUS
,
3495 _T("Delaying setting focus to %s(%s)"),
3496 GetClassInfo()->GetClassName(), GetLabel().c_str());
3498 g_delayedFocus
= this;
3502 wxLogTrace(TRACE_FOCUS
,
3503 _T("Setting focus to %s(%s)"),
3504 GetClassInfo()->GetClassName(), GetLabel().c_str());
3506 gtk_widget_grab_focus (m_widget
);
3511 wxLogTrace(TRACE_FOCUS
,
3512 _T("Can't set focus to %s(%s)"),
3513 GetClassInfo()->GetClassName(), GetLabel().c_str());
3518 bool wxWindowGTK::AcceptsFocus() const
3520 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3523 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3525 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3527 wxWindowGTK
*oldParent
= m_parent
,
3528 *newParent
= (wxWindowGTK
*)newParentBase
;
3530 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3532 if ( !wxWindowBase::Reparent(newParent
) )
3535 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3537 /* prevent GTK from deleting the widget arbitrarily */
3538 gtk_widget_ref( m_widget
);
3542 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3545 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3549 /* insert GTK representation */
3550 (*(newParent
->m_insertCallback
))(newParent
, this);
3553 /* reverse: prevent GTK from deleting the widget arbitrarily */
3554 gtk_widget_unref( m_widget
);
3559 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3561 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3563 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3565 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3570 /* insert GTK representation */
3571 (*m_insertCallback
)(this, child
);
3574 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3576 wxWindowBase::AddChild(child
);
3577 m_dirtyTabOrder
= true;
3579 wxapp_install_idle_handler();
3582 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3584 wxWindowBase::RemoveChild(child
);
3585 m_dirtyTabOrder
= true;
3587 wxapp_install_idle_handler();
3590 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3592 wxWindowBase::DoMoveInTabOrder(win
, move
);
3593 m_dirtyTabOrder
= true;
3595 wxapp_install_idle_handler();
3598 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3600 // none needed by default
3604 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3606 // nothing to do by default since none is needed
3609 void wxWindowGTK::RealizeTabOrder()
3613 if ( !m_children
.empty() )
3615 // we don't only construct the correct focus chain but also use
3616 // this opportunity to update the mnemonic widgets for the widgets
3619 GList
*chain
= NULL
;
3620 wxWindowGTK
* mnemonicWindow
= NULL
;
3622 for ( wxWindowList::const_iterator i
= m_children
.begin();
3623 i
!= m_children
.end();
3626 wxWindowGTK
*win
= *i
;
3628 if ( mnemonicWindow
)
3630 if ( win
->AcceptsFocusFromKeyboard() )
3632 // wxComboBox et al. needs to focus on on a different
3633 // widget than m_widget, so if the main widget isn't
3634 // focusable try the connect widget
3635 GtkWidget
* w
= win
->m_widget
;
3636 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3638 w
= win
->GetConnectWidget();
3639 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3645 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3646 mnemonicWindow
= NULL
;
3650 else if ( win
->GTKWidgetNeedsMnemonic() )
3652 mnemonicWindow
= win
;
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_get_default_root_window() );
4412 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4417 void wxWinModule::OnExit()
4420 g_object_unref (G_OBJECT (g_eraseGC
));