1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
18 #include "wx/dcclient.h"
21 #include "wx/layout.h"
23 #include "wx/dialog.h"
24 #include "wx/msgdlg.h"
25 #include "wx/module.h"
26 #include "wx/combobox.h"
28 #if wxUSE_DRAG_AND_DROP
33 #include "wx/tooltip.h"
41 #include "wx/textctrl.h"
45 #include "wx/statusbr.h"
47 #include "wx/settings.h"
49 #include "wx/fontutil.h"
52 #include "wx/thread.h"
58 #include "wx/gtk/private.h"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
68 #include <pango/pangox.h>
74 extern GtkContainerClass
*pizza_parent_class
;
76 //-----------------------------------------------------------------------------
77 // documentation on internals
78 //-----------------------------------------------------------------------------
81 I have been asked several times about writing some documentation about
82 the GTK port of wxWidgets, especially its internal structures. Obviously,
83 you cannot understand wxGTK without knowing a little about the GTK, but
84 some more information about what the wxWindow, which is the base class
85 for all other window classes, does seems required as well.
89 What does wxWindow do? It contains the common interface for the following
90 jobs of its descendants:
92 1) Define the rudimentary behaviour common to all window classes, such as
93 resizing, intercepting user input (so as to make it possible to use these
94 events for special purposes in a derived class), window names etc.
96 2) Provide the possibility to contain and manage children, if the derived
97 class is allowed to contain children, which holds true for those window
98 classes which do not display a native GTK widget. To name them, these
99 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
100 work classes are a special case and are handled a bit differently from
101 the rest. The same holds true for the wxNotebook class.
103 3) Provide the possibility to draw into a client area of a window. This,
104 too, only holds true for classes that do not display a native GTK widget
107 4) Provide the entire mechanism for scrolling widgets. This actual inter-
108 face for this is usually in wxScrolledWindow, but the GTK implementation
111 5) A multitude of helper or extra methods for special purposes, such as
112 Drag'n'Drop, managing validators etc.
114 6) Display a border (sunken, raised, simple or none).
116 Normally one might expect, that one wxWidgets window would always correspond
117 to one GTK widget. Under GTK, there is no such allround widget that has all
118 the functionality. Moreover, the GTK defines a client area as a different
119 widget from the actual widget you are handling. Last but not least some
120 special classes (e.g. wxFrame) handle different categories of widgets and
121 still have the possibility to draw something in the client area.
122 It was therefore required to write a special purpose GTK widget, that would
123 represent a client area in the sense of wxWidgets capable to do the jobs
124 2), 3) and 4). I have written this class and it resides in win_gtk.c of
127 All windows must have a widget, with which they interact with other under-
128 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
129 the wxWindow class has a member variable called m_widget which holds a
130 pointer to this widget. When the window class represents a GTK native widget,
131 this is (in most cases) the only GTK widget the class manages. E.g. the
132 wxStaticText class handles only a GtkLabel widget a pointer to which you
133 can find in m_widget (defined in wxWindow)
135 When the class has a client area for drawing into and for containing children
136 it has to handle the client area widget (of the type GtkPizza, defined in
137 win_gtk.c), but there could be any number of widgets, handled by a class
138 The common rule for all windows is only, that the widget that interacts with
139 the rest of GTK must be referenced in m_widget and all other widgets must be
140 children of this widget on the GTK level. The top-most widget, which also
141 represents the client area, must be in the m_wxwindow field and must be of
144 As I said, the window classes that display a GTK native widget only have
145 one widget, so in the case of e.g. the wxButton class m_widget holds a
146 pointer to a GtkButton widget. But windows with client areas (for drawing
147 and children) have a m_widget field that is a pointer to a GtkScrolled-
148 Window and a m_wxwindow field that is pointer to a GtkPizza and this
149 one is (in the GTK sense) a child of the GtkScrolledWindow.
151 If the m_wxwindow field is set, then all input to this widget is inter-
152 cepted and sent to the wxWidgets class. If not, all input to the widget
153 that gets pointed to by m_widget gets intercepted and sent to the class.
157 The design of scrolling in wxWidgets is markedly different from that offered
158 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
159 clicking on a scrollbar belonging to scrolled window will inevitably move
160 the window. In wxWidgets, the scrollbar will only emit an event, send this
161 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
162 which actually moves the window and its subchildren. Note that GtkPizza
163 memorizes how much it has been scrolled but that wxWidgets forgets this
164 so that the two coordinates systems have to be kept in synch. This is done
165 in various places using the pizza->xoffset and pizza->yoffset values.
169 Singularily the most broken code in GTK is the code that is supposed to
170 inform subwindows (child windows) about new positions. Very often, duplicate
171 events are sent without changes in size or position, equally often no
172 events are sent at all (All this is due to a bug in the GtkContainer code
173 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
174 GTK's own system and it simply waits for size events for toplevel windows
175 and then iterates down the respective size events to all window. This has
176 the disadvantage that windows might get size events before the GTK widget
177 actually has the reported size. This doesn't normally pose any problem, but
178 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
179 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
180 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
181 window that is used for OpenGL output really has that size (as reported by
186 If someone at some point of time feels the immense desire to have a look at,
187 change or attempt to optimise the Refresh() logic, this person will need an
188 intimate understanding of what "draw" and "expose" events are and what
189 they are used for, in particular when used in connection with GTK's
190 own windowless widgets. Beware.
194 Cursors, too, have been a constant source of pleasure. The main difficulty
195 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
196 for the parent. To prevent this from doing too much harm, I use idle time
197 to set the cursor over and over again, starting from the toplevel windows
198 and ending with the youngest generation (speaking of parent and child windows).
199 Also don't forget that cursors (like much else) are connected to GdkWindows,
200 not GtkWidgets and that the "window" field of a GtkWidget might very well
201 point to the GdkWindow of the parent widget (-> "window-less widget") and
202 that the two obviously have very different meanings.
206 //-----------------------------------------------------------------------------
208 //-----------------------------------------------------------------------------
210 extern wxList wxPendingDelete
;
211 extern bool g_blockEventsOnDrag
;
212 extern bool g_blockEventsOnScroll
;
213 extern wxCursor g_globalCursor
;
215 static GdkGC
*g_eraseGC
= NULL
;
217 // mouse capture state: the window which has it and if the mouse is currently
219 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
220 static bool g_captureWindowHasMouse
= false;
222 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
224 // the last window which had the focus - this is normally never NULL (except
225 // if we never had focus at all) as even when g_focusWindow is NULL it still
226 // keeps its previous value
227 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
229 // If a window get the focus set but has not been realized
230 // yet, defer setting the focus to idle time.
231 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
233 extern bool g_mainThreadLocked
;
235 //-----------------------------------------------------------------------------
237 //-----------------------------------------------------------------------------
242 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
244 # define DEBUG_MAIN_THREAD
247 #define DEBUG_MAIN_THREAD
250 // the trace mask used for the focus debugging messages
251 #define TRACE_FOCUS _T("focus")
253 //-----------------------------------------------------------------------------
254 // missing gdk functions
255 //-----------------------------------------------------------------------------
258 gdk_window_warp_pointer (GdkWindow
*window
,
263 window
= GDK_ROOT_PARENT();
265 if (!GDK_WINDOW_DESTROYED(window
))
267 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
268 None
, /* not source window -> move from anywhere */
269 GDK_WINDOW_XID(window
), /* dest window */
270 0, 0, 0, 0, /* not source window -> move from anywhere */
275 //-----------------------------------------------------------------------------
277 //-----------------------------------------------------------------------------
279 extern void wxapp_install_idle_handler();
280 extern bool g_isIdle
;
282 //-----------------------------------------------------------------------------
283 // local code (see below)
284 //-----------------------------------------------------------------------------
286 // returns the child of win which currently has focus or NULL if not found
288 // Note: can't be static, needed by textctrl.cpp.
289 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
291 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
293 return (wxWindow
*)NULL
;
295 if ( winFocus
== win
)
296 return (wxWindow
*)win
;
298 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
300 node
= node
->GetNext() )
302 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
307 return (wxWindow
*)NULL
;
310 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
312 // wxUniversal widgets draw the borders and scrollbars themselves
313 #ifndef __WXUNIVERSAL__
320 if (win
->m_hasScrolling
)
322 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
324 GtkRequisition vscroll_req
;
325 vscroll_req
.width
= 2;
326 vscroll_req
.height
= 2;
327 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
328 (scroll_window
->vscrollbar
, &vscroll_req
);
330 GtkRequisition hscroll_req
;
331 hscroll_req
.width
= 2;
332 hscroll_req
.height
= 2;
333 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
334 (scroll_window
->hscrollbar
, &hscroll_req
);
336 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
338 if (scroll_window
->vscrollbar_visible
)
340 dw
+= vscroll_req
.width
;
341 dw
+= scroll_class
->scrollbar_spacing
;
344 if (scroll_window
->hscrollbar_visible
)
346 dh
+= hscroll_req
.height
;
347 dh
+= scroll_class
->scrollbar_spacing
;
353 if (GTK_WIDGET_NO_WINDOW (widget
))
355 dx
+= widget
->allocation
.x
;
356 dy
+= widget
->allocation
.y
;
359 if (win
->HasFlag(wxRAISED_BORDER
))
361 gtk_paint_shadow (widget
->style
,
365 NULL
, NULL
, NULL
, // FIXME: No clipping?
367 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
371 if (win
->HasFlag(wxSUNKEN_BORDER
))
373 gtk_paint_shadow (widget
->style
,
377 NULL
, NULL
, NULL
, // FIXME: No clipping?
379 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
383 if (win
->HasFlag(wxSIMPLE_BORDER
))
386 gc
= gdk_gc_new( widget
->window
);
387 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
388 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
390 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
394 #endif // __WXUNIVERSAL__
397 //-----------------------------------------------------------------------------
398 // "expose_event" of m_widget
399 //-----------------------------------------------------------------------------
402 static gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
404 if (gdk_event
->count
> 0) return FALSE
;
406 draw_frame( widget
, win
);
408 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
414 //-----------------------------------------------------------------------------
415 // "size_request" of m_widget
416 //-----------------------------------------------------------------------------
418 // make it extern because wxStaticText needs to disconnect this one
420 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
421 GtkRequisition
*requisition
,
425 win
->GetSize( &w
, &h
);
431 requisition
->height
= h
;
432 requisition
->width
= w
;
438 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
439 GtkRequisition
*requisition
,
442 // This callback is actually hooked into the text entry
443 // of the combo box, not the GtkHBox.
446 win
->GetSize( &w
, &h
);
452 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
454 GtkRequisition entry_req
;
456 entry_req
.height
= 2;
457 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
458 (gcombo
->button
, &entry_req
);
460 requisition
->width
= w
- entry_req
.width
;
461 requisition
->height
= entry_req
.height
;
465 //-----------------------------------------------------------------------------
466 // "expose_event" of m_wxwindow
467 //-----------------------------------------------------------------------------
470 static int gtk_window_expose_callback( GtkWidget
*widget
,
471 GdkEventExpose
*gdk_event
,
477 wxapp_install_idle_handler();
479 // This callback gets called in drawing-idle time under
480 // GTK 2.0, so we don't need to defer anything to idle
483 GtkPizza
*pizza
= GTK_PIZZA( widget
);
484 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
489 wxPrintf( wxT("OnExpose from ") );
490 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
491 wxPrintf( win
->GetClassInfo()->GetClassName() );
492 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
493 (int)gdk_event
->area
.y
,
494 (int)gdk_event
->area
.width
,
495 (int)gdk_event
->area
.height
);
500 win
->m_wxwindow
->style
,
504 (GdkRectangle
*) NULL
,
506 (char *)"button", // const_cast
511 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
513 win
->GtkSendPaintEvents();
516 // Let parent window draw window-less widgets
517 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
523 //-----------------------------------------------------------------------------
524 // "key_press_event" from any window
525 //-----------------------------------------------------------------------------
527 // set WXTRACE to this to see the key event codes on the console
528 #define TRACE_KEYS _T("keyevent")
530 // translates an X key symbol to WXK_XXX value
532 // if isChar is true it means that the value returned will be used for EVT_CHAR
533 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
534 // for example, while if it is false it means that the value is going to be
535 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
537 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
543 // Shift, Control and Alt don't generate the CHAR events at all
546 key_code
= isChar
? 0 : WXK_SHIFT
;
550 key_code
= isChar
? 0 : WXK_CONTROL
;
558 key_code
= isChar
? 0 : WXK_ALT
;
561 // neither do the toggle modifies
562 case GDK_Scroll_Lock
:
563 key_code
= isChar
? 0 : WXK_SCROLL
;
567 key_code
= isChar
? 0 : WXK_CAPITAL
;
571 key_code
= isChar
? 0 : WXK_NUMLOCK
;
575 // various other special keys
588 case GDK_ISO_Left_Tab
:
595 key_code
= WXK_RETURN
;
599 key_code
= WXK_CLEAR
;
603 key_code
= WXK_PAUSE
;
607 key_code
= WXK_SELECT
;
611 key_code
= WXK_PRINT
;
615 key_code
= WXK_EXECUTE
;
619 key_code
= WXK_ESCAPE
;
622 // cursor and other extended keyboard keys
624 key_code
= WXK_DELETE
;
640 key_code
= WXK_RIGHT
;
647 case GDK_Prior
: // == GDK_Page_Up
648 key_code
= WXK_PRIOR
;
651 case GDK_Next
: // == GDK_Page_Down
664 key_code
= WXK_INSERT
;
679 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
683 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
687 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
691 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
695 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
699 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
703 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
707 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
711 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
715 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
719 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
723 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
727 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
730 case GDK_KP_Prior
: // == GDK_KP_Page_Up
731 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
734 case GDK_KP_Next
: // == GDK_KP_Page_Down
735 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
739 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
743 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
747 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
751 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
755 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
758 case GDK_KP_Multiply
:
759 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
763 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
766 case GDK_KP_Separator
:
767 // FIXME: what is this?
768 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
771 case GDK_KP_Subtract
:
772 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
776 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
780 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
797 key_code
= WXK_F1
+ keysym
- GDK_F1
;
807 static inline bool wxIsAsciiKeysym(KeySym ks
)
812 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
814 GdkEventKey
*gdk_event
)
818 GdkModifierType state
;
819 if (gdk_event
->window
)
820 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
822 event
.SetTimestamp( gdk_event
->time
);
823 event
.SetId(win
->GetId());
824 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
825 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
826 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
827 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
828 event
.m_scanCode
= gdk_event
->keyval
;
829 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
830 event
.m_rawFlags
= 0;
832 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
833 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
835 event
.m_uniChar
= toupper(event
.m_uniChar
);
838 wxGetMousePosition( &x
, &y
);
839 win
->ScreenToClient( &x
, &y
);
842 event
.SetEventObject( win
);
847 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
849 GdkEventKey
*gdk_event
)
851 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
852 // but only event->keyval which is quite useless to us, so remember
853 // the last character from GDK_KEY_PRESS and reuse it as last resort
855 // NB: should be MT-safe as we're always called from the main thread only
860 } s_lastKeyPress
= { 0, 0 };
862 KeySym keysym
= gdk_event
->keyval
;
864 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
865 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
869 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
873 // do we have the translation or is it a plain ASCII character?
874 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
876 // we should use keysym if it is ASCII as X does some translations
877 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
878 // which we don't want here (but which we do use for OnChar())
879 if ( !wxIsAsciiKeysym(keysym
) )
881 keysym
= (KeySym
)gdk_event
->string
[0];
884 // we want to always get the same key code when the same key is
885 // pressed regardless of the state of the modifiers, i.e. on a
886 // standard US keyboard pressing '5' or '%' ('5' key with
887 // Shift) should result in the same key code in OnKeyDown():
888 // '5' (although OnChar() will get either '5' or '%').
890 // to do it we first translate keysym to keycode (== scan code)
891 // and then back but always using the lower register
892 Display
*dpy
= (Display
*)wxGetDisplay();
893 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
895 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
897 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
899 // use the normalized, i.e. lower register, keysym if we've
901 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
903 // as explained above, we want to have lower register key codes
904 // normally but for the letter keys we want to have the upper ones
906 // NB: don't use XConvertCase() here, we want to do it for letters
908 key_code
= toupper(key_code
);
910 else // non ASCII key, what to do?
912 // by default, ignore it
915 // but if we have cached information from the last KEY_PRESS
916 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
919 if ( keysym
== s_lastKeyPress
.keysym
)
921 key_code
= s_lastKeyPress
.keycode
;
926 if ( gdk_event
->type
== GDK_KEY_PRESS
)
928 // remember it to be reused for KEY_UP event later
929 s_lastKeyPress
.keysym
= keysym
;
930 s_lastKeyPress
.keycode
= key_code
;
934 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
936 // sending unknown key events doesn't really make sense
940 // now fill all the other fields
941 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
943 event
.m_keyCode
= key_code
;
951 GtkIMContext
*context
;
952 GdkEventKey
*lastKeyEvent
;
956 context
= gtk_im_multicontext_new();
961 g_object_unref(context
);
966 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
967 GdkEventKey
*gdk_event
,
973 wxapp_install_idle_handler();
977 if (g_blockEventsOnDrag
)
981 wxKeyEvent
event( wxEVT_KEY_DOWN
);
983 bool return_after_IM
= false;
985 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
987 // Emit KEY_DOWN event
988 ret
= win
->GetEventHandler()->ProcessEvent( event
);
992 // Return after IM processing as we cannot do
993 // anything with it anyhow.
994 return_after_IM
= true;
997 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
998 // When we get a key_press event here, it could be originate
999 // from the current widget or its child widgets. However, only the widget
1000 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1001 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1002 // originated from its child widgets and shouldn't be passed to IM context.
1003 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1004 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1005 // widgets has both IM context and input focus, the event should be filtered
1006 // by gtk_im_context_filter_keypress().
1007 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1008 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1010 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1011 // docs, if IM filter returns true, no further processing should be done.
1012 // we should send the key_down event anyway.
1013 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1014 win
->m_imData
->lastKeyEvent
= NULL
;
1015 if (intercepted_by_IM
)
1017 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1022 if (return_after_IM
)
1028 wxWindowGTK
*ancestor
= win
;
1031 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1034 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1035 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1038 if (ancestor
->IsTopLevel())
1040 ancestor
= ancestor
->GetParent();
1043 #endif // wxUSE_ACCEL
1045 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1046 // will only be sent if it is not in an accelerator table.
1050 KeySym keysym
= gdk_event
->keyval
;
1051 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1052 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1055 if ( wxIsAsciiKeysym(keysym
) )
1058 key_code
= (unsigned char)keysym
;
1060 // gdk_event->string is actually deprecated
1061 else if ( gdk_event
->length
== 1 )
1063 key_code
= (unsigned char)gdk_event
->string
[0];
1069 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1071 event
.m_keyCode
= key_code
;
1073 // To conform to the docs we need to translate Ctrl-alpha
1074 // characters to values in the range 1-26.
1075 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1077 event
.m_keyCode
= key_code
- 'a' + 1;
1079 event
.m_uniChar
= event
.m_keyCode
;
1083 // Implement OnCharHook by checking ancestor top level windows
1084 wxWindow
*parent
= win
;
1085 while (parent
&& !parent
->IsTopLevel())
1086 parent
= parent
->GetParent();
1089 event
.SetEventType( wxEVT_CHAR_HOOK
);
1090 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1095 event
.SetEventType(wxEVT_CHAR
);
1096 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1105 // win is a control: tab can be propagated up
1107 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1108 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1109 // have this style, yet choose not to process this particular TAB in which
1110 // case TAB must still work as a navigational character
1111 // JS: enabling again to make consistent with other platforms
1112 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1113 // navigation behaviour)
1115 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1117 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1119 wxNavigationKeyEvent new_event
;
1120 new_event
.SetEventObject( win
->GetParent() );
1121 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1122 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1123 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1124 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1125 new_event
.SetCurrentFocus( win
);
1126 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1129 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1131 (gdk_event
->keyval
== GDK_Escape
) )
1133 // however only do it if we have a Cancel button in the dialog,
1134 // otherwise the user code may get confused by the events from a
1135 // non-existing button and, worse, a wxButton might get button event
1136 // from another button which is not really expected
1137 wxWindow
*winForCancel
= win
,
1139 while ( winForCancel
)
1141 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1144 // found a cancel button
1148 if ( winForCancel
->IsTopLevel() )
1150 // no need to look further
1154 // maybe our parent has a cancel button?
1155 winForCancel
= winForCancel
->GetParent();
1160 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1161 eventClick
.SetEventObject(btnCancel
);
1162 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1168 g_signal_stop_emission_by_name (widget
, "key_press_event");
1177 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1181 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1183 // take modifiers, cursor position, timestamp etc. from the last
1184 // key_press_event that was fed into Input Method:
1185 if (window
->m_imData
->lastKeyEvent
)
1187 wxFillOtherKeyEventFields(event
,
1188 window
, window
->m_imData
->lastKeyEvent
);
1192 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1194 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1195 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1196 #endif // wxUSE_UNICODE
1197 if( !(const wxChar
*)data
)
1202 // Implement OnCharHook by checking ancestor top level windows
1203 wxWindow
*parent
= window
;
1204 while (parent
&& !parent
->IsTopLevel())
1205 parent
= parent
->GetParent();
1207 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1210 event
.m_uniChar
= *pstr
;
1211 // Backward compatible for ISO-8859-1
1212 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1213 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1215 event
.m_keyCode
= *pstr
;
1216 #endif // wxUSE_UNICODE
1218 // To conform to the docs we need to translate Ctrl-alpha
1219 // characters to values in the range 1-26.
1220 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1222 event
.m_keyCode
= *pstr
- 'a' + 1;
1224 event
.m_uniChar
= event
.m_keyCode
;
1230 event
.SetEventType( wxEVT_CHAR_HOOK
);
1231 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1236 event
.SetEventType(wxEVT_CHAR
);
1237 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1244 //-----------------------------------------------------------------------------
1245 // "key_release_event" from any window
1246 //-----------------------------------------------------------------------------
1249 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1250 GdkEventKey
*gdk_event
,
1256 wxapp_install_idle_handler();
1261 if (g_blockEventsOnDrag
)
1264 wxKeyEvent
event( wxEVT_KEY_UP
);
1265 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1267 // unknown key pressed, ignore (the event would be useless anyhow)
1271 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1274 g_signal_stop_emission_by_name (widget
, "key_release_event");
1279 // ============================================================================
1281 // ============================================================================
1283 // ----------------------------------------------------------------------------
1284 // mouse event processing helpers
1285 // ----------------------------------------------------------------------------
1287 // init wxMouseEvent with the info from GdkEventXXX struct
1288 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1289 wxMouseEvent
& event
,
1292 event
.SetTimestamp( gdk_event
->time
);
1293 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1294 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1295 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1296 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1297 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1298 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1299 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1300 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1302 event
.m_linesPerAction
= 3;
1303 event
.m_wheelDelta
= 120;
1304 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1305 event
.m_wheelRotation
= 120;
1306 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1307 event
.m_wheelRotation
= -120;
1310 wxPoint pt
= win
->GetClientAreaOrigin();
1311 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1312 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1314 event
.SetEventObject( win
);
1315 event
.SetId( win
->GetId() );
1316 event
.SetTimestamp( gdk_event
->time
);
1319 static void AdjustEventButtonState(wxMouseEvent
& event
)
1321 // GDK reports the old state of the button for a button press event, but
1322 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1323 // for a LEFT_DOWN event, not FALSE, so we will invert
1324 // left/right/middleDown for the corresponding click events
1326 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1327 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1328 (event
.GetEventType() == wxEVT_LEFT_UP
))
1330 event
.m_leftDown
= !event
.m_leftDown
;
1334 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1335 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1336 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1338 event
.m_middleDown
= !event
.m_middleDown
;
1342 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1343 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1344 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1346 event
.m_rightDown
= !event
.m_rightDown
;
1351 // find the window to send the mouse event too
1353 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1358 if (win
->m_wxwindow
)
1360 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1361 xx
+= pizza
->xoffset
;
1362 yy
+= pizza
->yoffset
;
1365 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1368 wxWindowGTK
*child
= node
->GetData();
1370 node
= node
->GetNext();
1371 if (!child
->IsShown())
1374 if (child
->IsTransparentForMouse())
1376 // wxStaticBox is transparent in the box itself
1377 int xx1
= child
->m_x
;
1378 int yy1
= child
->m_y
;
1379 int xx2
= child
->m_x
+ child
->m_width
;
1380 int yy2
= child
->m_y
+ child
->m_height
;
1383 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1385 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1387 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1389 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1400 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1401 (child
->m_x
<= xx
) &&
1402 (child
->m_y
<= yy
) &&
1403 (child
->m_x
+child
->m_width
>= xx
) &&
1404 (child
->m_y
+child
->m_height
>= yy
))
1417 //-----------------------------------------------------------------------------
1418 // "button_press_event"
1419 //-----------------------------------------------------------------------------
1422 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1423 GdkEventButton
*gdk_event
,
1429 wxapp_install_idle_handler();
1432 wxPrintf( wxT("1) OnButtonPress from ") );
1433 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1434 wxPrintf( win->GetClassInfo()->GetClassName() );
1435 wxPrintf( wxT(".\n") );
1437 if (!win
->m_hasVMT
) return FALSE
;
1438 if (g_blockEventsOnDrag
) return TRUE
;
1439 if (g_blockEventsOnScroll
) return TRUE
;
1441 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1443 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1445 gtk_widget_grab_focus( win
->m_wxwindow
);
1447 wxPrintf( wxT("GrabFocus from ") );
1448 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1449 wxPrintf( win->GetClassInfo()->GetClassName() );
1450 wxPrintf( wxT(".\n") );
1454 // GDK sends surplus button down events
1455 // before a double click event. We
1456 // need to filter these out.
1457 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1459 GdkEvent
*peek_event
= gdk_event_peek();
1462 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1463 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1465 gdk_event_free( peek_event
);
1470 gdk_event_free( peek_event
);
1475 wxEventType event_type
= wxEVT_NULL
;
1477 // GdkDisplay is a GTK+ 2.2.0 thing
1478 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1479 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1480 !gtk_check_version(2,2,0) &&
1481 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1483 // Reset GDK internal timestamp variables in order to disable GDK
1484 // triple click events. GDK will then next time believe no button has
1485 // been clicked just before, and send a normal button click event.
1486 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1487 display
->button_click_time
[1] = 0;
1488 display
->button_click_time
[0] = 0;
1492 if (gdk_event
->button
== 1)
1494 // note that GDK generates triple click events which are not supported
1495 // by wxWidgets but still have to be passed to the app as otherwise
1496 // clicks would simply go missing
1497 switch (gdk_event
->type
)
1499 // we shouldn't get triple clicks at all for GTK2 because we
1500 // suppress them artificially using the code above but we still
1501 // should map them to something for GTK1 and not just ignore them
1502 // as this would lose clicks
1503 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1504 case GDK_BUTTON_PRESS
:
1505 event_type
= wxEVT_LEFT_DOWN
;
1508 case GDK_2BUTTON_PRESS
:
1509 event_type
= wxEVT_LEFT_DCLICK
;
1513 // just to silence gcc warnings
1517 else if (gdk_event
->button
== 2)
1519 switch (gdk_event
->type
)
1521 case GDK_3BUTTON_PRESS
:
1522 case GDK_BUTTON_PRESS
:
1523 event_type
= wxEVT_MIDDLE_DOWN
;
1526 case GDK_2BUTTON_PRESS
:
1527 event_type
= wxEVT_MIDDLE_DCLICK
;
1534 else if (gdk_event
->button
== 3)
1536 switch (gdk_event
->type
)
1538 case GDK_3BUTTON_PRESS
:
1539 case GDK_BUTTON_PRESS
:
1540 event_type
= wxEVT_RIGHT_DOWN
;
1543 case GDK_2BUTTON_PRESS
:
1544 event_type
= wxEVT_RIGHT_DCLICK
;
1551 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1553 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1555 event_type
= wxEVT_MOUSEWHEEL
;
1559 if ( event_type
== wxEVT_NULL
)
1561 // unknown mouse button or click type
1565 wxMouseEvent
event( event_type
);
1566 InitMouseEvent( win
, event
, gdk_event
);
1568 AdjustEventButtonState(event
);
1570 // wxListBox actually gets mouse events from the item, so we need to give it
1571 // a chance to correct this
1572 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1574 // find the correct window to send the event to: it may be a different one
1575 // from the one which got it at GTK+ level because some controls don't have
1576 // their own X window and thus cannot get any events.
1577 if ( !g_captureWindow
)
1578 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1580 if (win
->GetEventHandler()->ProcessEvent( event
))
1582 g_signal_stop_emission_by_name (widget
, "button_press_event");
1586 if (event_type
== wxEVT_RIGHT_DOWN
)
1588 // generate a "context menu" event: this is similar to right mouse
1589 // click under many GUIs except that it is generated differently
1590 // (right up under MSW, ctrl-click under Mac, right down here) and
1592 // (a) it's a command event and so is propagated to the parent
1593 // (b) under some ports it can be generated from kbd too
1594 // (c) it uses screen coords (because of (a))
1595 wxContextMenuEvent
evtCtx(
1598 win
->ClientToScreen(event
.GetPosition()));
1599 evtCtx
.SetEventObject(win
);
1600 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1607 //-----------------------------------------------------------------------------
1608 // "button_release_event"
1609 //-----------------------------------------------------------------------------
1612 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1613 GdkEventButton
*gdk_event
,
1619 wxapp_install_idle_handler();
1621 if (!win
->m_hasVMT
) return FALSE
;
1622 if (g_blockEventsOnDrag
) return FALSE
;
1623 if (g_blockEventsOnScroll
) return FALSE
;
1625 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1627 wxEventType event_type
= wxEVT_NULL
;
1629 switch (gdk_event
->button
)
1632 event_type
= wxEVT_LEFT_UP
;
1636 event_type
= wxEVT_MIDDLE_UP
;
1640 event_type
= wxEVT_RIGHT_UP
;
1644 // unknwon button, don't process
1648 wxMouseEvent
event( event_type
);
1649 InitMouseEvent( win
, event
, gdk_event
);
1651 AdjustEventButtonState(event
);
1653 // same wxListBox hack as above
1654 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1656 if ( !g_captureWindow
)
1657 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1659 if (win
->GetEventHandler()->ProcessEvent( event
))
1661 g_signal_stop_emission_by_name (widget
, "button_release_event");
1669 //-----------------------------------------------------------------------------
1670 // "motion_notify_event"
1671 //-----------------------------------------------------------------------------
1674 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1675 GdkEventMotion
*gdk_event
,
1681 wxapp_install_idle_handler();
1683 if (!win
->m_hasVMT
) return FALSE
;
1684 if (g_blockEventsOnDrag
) return FALSE
;
1685 if (g_blockEventsOnScroll
) return FALSE
;
1687 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1689 if (gdk_event
->is_hint
)
1693 GdkModifierType state
;
1694 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1700 printf( "OnMotion from " );
1701 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1702 printf( win->GetClassInfo()->GetClassName() );
1706 wxMouseEvent
event( wxEVT_MOTION
);
1707 InitMouseEvent(win
, event
, gdk_event
);
1709 if ( g_captureWindow
)
1711 // synthetize a mouse enter or leave event if needed
1712 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1713 // This seems to be necessary and actually been added to
1714 // GDK itself in version 2.0.X
1717 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1718 if ( hasMouse
!= g_captureWindowHasMouse
)
1720 // the mouse changed window
1721 g_captureWindowHasMouse
= hasMouse
;
1723 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1724 : wxEVT_LEAVE_WINDOW
);
1725 InitMouseEvent(win
, eventM
, gdk_event
);
1726 eventM
.SetEventObject(win
);
1727 win
->GetEventHandler()->ProcessEvent(eventM
);
1732 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1735 if (win
->GetEventHandler()->ProcessEvent( event
))
1737 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1745 //-----------------------------------------------------------------------------
1746 // "mouse_wheel_event"
1747 //-----------------------------------------------------------------------------
1750 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1751 GdkEventScroll
* gdk_event
,
1757 wxapp_install_idle_handler();
1759 wxEventType event_type
= wxEVT_NULL
;
1760 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1761 event_type
= wxEVT_MOUSEWHEEL
;
1762 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1763 event_type
= wxEVT_MOUSEWHEEL
;
1767 wxMouseEvent
event( event_type
);
1768 // Can't use InitMouse macro because scroll events don't have button
1769 event
.SetTimestamp( gdk_event
->time
);
1770 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1771 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1772 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1773 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1774 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1775 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1776 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1777 event
.m_linesPerAction
= 3;
1778 event
.m_wheelDelta
= 120;
1779 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1780 event
.m_wheelRotation
= 120;
1782 event
.m_wheelRotation
= -120;
1784 wxPoint pt
= win
->GetClientAreaOrigin();
1785 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1786 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1788 event
.SetEventObject( win
);
1789 event
.SetId( win
->GetId() );
1790 event
.SetTimestamp( gdk_event
->time
);
1792 if (win
->GetEventHandler()->ProcessEvent( event
))
1794 g_signal_stop_emission_by_name (widget
, "scroll_event");
1802 //-----------------------------------------------------------------------------
1804 //-----------------------------------------------------------------------------
1806 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1808 wxContextMenuEvent
event(
1812 event
.SetEventObject(win
);
1813 return win
->GetEventHandler()->ProcessEvent(event
);
1817 //-----------------------------------------------------------------------------
1819 //-----------------------------------------------------------------------------
1821 // send the wxChildFocusEvent and wxFocusEvent, common code of
1822 // gtk_window_focus_in_callback() and SetFocus()
1823 static bool DoSendFocusEvents(wxWindow
*win
)
1825 // Notify the parent keeping track of focus for the kbd navigation
1826 // purposes that we got it.
1827 wxChildFocusEvent
eventChildFocus(win
);
1828 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1830 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1831 eventFocus
.SetEventObject(win
);
1833 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1837 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1838 GdkEvent
*WXUNUSED(event
),
1844 wxapp_install_idle_handler();
1847 gtk_im_context_focus_in(win
->m_imData
->context
);
1850 g_focusWindow
= win
;
1852 wxLogTrace(TRACE_FOCUS
,
1853 _T("%s: focus in"), win
->GetName().c_str());
1857 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1861 // caret needs to be informed about focus change
1862 wxCaret
*caret
= win
->GetCaret();
1865 caret
->OnSetFocus();
1867 #endif // wxUSE_CARET
1869 // does the window itself think that it has the focus?
1870 if ( !win
->m_hasFocus
)
1872 // not yet, notify it
1873 win
->m_hasFocus
= true;
1875 if ( DoSendFocusEvents(win
) )
1877 g_signal_stop_emission_by_name (widget
, "focus_in_event");
1886 //-----------------------------------------------------------------------------
1887 // "focus_out_event"
1888 //-----------------------------------------------------------------------------
1891 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1896 wxapp_install_idle_handler();
1899 gtk_im_context_focus_out(win
->m_imData
->context
);
1901 wxLogTrace( TRACE_FOCUS
,
1902 _T("%s: focus out"), win
->GetName().c_str() );
1905 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1909 g_focusWindow
= (wxWindowGTK
*)NULL
;
1917 // caret needs to be informed about focus change
1918 wxCaret
*caret
= win
->GetCaret();
1921 caret
->OnKillFocus();
1923 #endif // wxUSE_CARET
1925 // don't send the window a kill focus event if it thinks that it doesn't
1926 // have focus already
1927 if ( win
->m_hasFocus
)
1929 win
->m_hasFocus
= false;
1931 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1932 event
.SetEventObject( win
);
1934 // even if we did process the event in wx code, still let GTK itself
1935 // process it too as otherwise bad things happen, especially in GTK2
1936 // where the text control simply aborts the program if it doesn't get
1937 // the matching focus out event
1938 (void)win
->GetEventHandler()->ProcessEvent( event
);
1945 //-----------------------------------------------------------------------------
1946 // "enter_notify_event"
1947 //-----------------------------------------------------------------------------
1951 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1952 GdkEventCrossing
*gdk_event
,
1958 wxapp_install_idle_handler();
1960 if (!win
->m_hasVMT
) return FALSE
;
1961 if (g_blockEventsOnDrag
) return FALSE
;
1963 // Event was emitted after a grab
1964 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1966 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1970 GdkModifierType state
= (GdkModifierType
)0;
1972 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1974 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1975 InitMouseEvent(win
, event
, gdk_event
);
1976 wxPoint pt
= win
->GetClientAreaOrigin();
1977 event
.m_x
= x
+ pt
.x
;
1978 event
.m_y
= y
+ pt
.y
;
1980 if (win
->GetEventHandler()->ProcessEvent( event
))
1982 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
1990 //-----------------------------------------------------------------------------
1991 // "leave_notify_event"
1992 //-----------------------------------------------------------------------------
1995 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2000 wxapp_install_idle_handler();
2002 if (!win
->m_hasVMT
) return FALSE
;
2003 if (g_blockEventsOnDrag
) return FALSE
;
2005 // Event was emitted after an ungrab
2006 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2008 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2010 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2011 event
.SetTimestamp( gdk_event
->time
);
2012 event
.SetEventObject( win
);
2016 GdkModifierType state
= (GdkModifierType
)0;
2018 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2020 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2021 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2022 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2023 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2024 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2025 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2026 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2028 wxPoint pt
= win
->GetClientAreaOrigin();
2029 event
.m_x
= x
+ pt
.x
;
2030 event
.m_y
= y
+ pt
.y
;
2032 if (win
->GetEventHandler()->ProcessEvent( event
))
2034 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2042 //-----------------------------------------------------------------------------
2043 // "value_changed" from m_vAdjust
2044 //-----------------------------------------------------------------------------
2047 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2053 wxapp_install_idle_handler();
2055 if (g_blockEventsOnDrag
) return;
2057 if (!win
->m_hasVMT
) return;
2059 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2060 if (fabs(diff
) < 0.2) return;
2062 win
->m_oldVerticalPos
= adjust
->value
;
2064 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2066 int value
= (int)(adjust
->value
+0.5);
2068 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2069 event
.SetEventObject( win
);
2070 win
->GetEventHandler()->ProcessEvent( event
);
2074 //-----------------------------------------------------------------------------
2075 // "value_changed" from m_hAdjust
2076 //-----------------------------------------------------------------------------
2079 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2085 wxapp_install_idle_handler();
2087 if (g_blockEventsOnDrag
) return;
2088 if (!win
->m_hasVMT
) return;
2090 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2091 if (fabs(diff
) < 0.2) return;
2093 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2095 win
->m_oldHorizontalPos
= adjust
->value
;
2097 int value
= (int)(adjust
->value
+0.5);
2099 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2100 event
.SetEventObject( win
);
2101 win
->GetEventHandler()->ProcessEvent( event
);
2105 //-----------------------------------------------------------------------------
2106 // "button_press_event" from scrollbar
2107 //-----------------------------------------------------------------------------
2110 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2111 GdkEventButton
*gdk_event
,
2117 wxapp_install_idle_handler();
2120 g_blockEventsOnScroll
= true;
2122 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2124 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2131 //-----------------------------------------------------------------------------
2132 // "button_release_event" from scrollbar
2133 //-----------------------------------------------------------------------------
2136 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2137 GdkEventButton
*WXUNUSED(gdk_event
),
2142 // don't test here as we can release the mouse while being over
2143 // a different window than the slider
2145 // if (gdk_event->window != widget->slider) return FALSE;
2147 g_blockEventsOnScroll
= false;
2149 if (win
->m_isScrolling
)
2151 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2155 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2156 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2158 value
= (int)(win
->m_hAdjust
->value
+0.5);
2161 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2163 value
= (int)(win
->m_vAdjust
->value
+0.5);
2167 wxScrollWinEvent
event( command
, value
, dir
);
2168 event
.SetEventObject( win
);
2169 win
->GetEventHandler()->ProcessEvent( event
);
2172 win
->m_isScrolling
= false;
2178 // ----------------------------------------------------------------------------
2179 // this wxWindowBase function is implemented here (in platform-specific file)
2180 // because it is static and so couldn't be made virtual
2181 // ----------------------------------------------------------------------------
2183 wxWindow
*wxWindowBase::DoFindFocus()
2185 // the cast is necessary when we compile in wxUniversal mode
2186 return (wxWindow
*)g_focusWindow
;
2189 //-----------------------------------------------------------------------------
2190 // "realize" from m_widget
2191 //-----------------------------------------------------------------------------
2193 /* We cannot set colours and fonts before the widget has
2194 been realized, so we do this directly after realization. */
2198 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2203 wxapp_install_idle_handler();
2207 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2208 gtk_im_context_set_client_window( win
->m_imData
->context
,
2209 pizza
->bin_window
);
2212 wxWindowCreateEvent
event( win
);
2213 event
.SetEventObject( win
);
2214 win
->GetEventHandler()->ProcessEvent( event
);
2220 //-----------------------------------------------------------------------------
2222 //-----------------------------------------------------------------------------
2226 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2227 GtkAllocation
*WXUNUSED(alloc
),
2231 wxapp_install_idle_handler();
2233 if (!win
->m_hasScrolling
) return;
2235 int client_width
= 0;
2236 int client_height
= 0;
2237 win
->GetClientSize( &client_width
, &client_height
);
2238 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2241 win
->m_oldClientWidth
= client_width
;
2242 win
->m_oldClientHeight
= client_height
;
2244 if (!win
->m_nativeSizeEvent
)
2246 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2247 event
.SetEventObject( win
);
2248 win
->GetEventHandler()->ProcessEvent( event
);
2255 #define WXUNUSED_UNLESS_XIM(param) param
2257 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2260 /* Resize XIM window */
2264 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2265 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2266 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2269 wxapp_install_idle_handler();
2275 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2279 gdk_window_get_size (widget
->window
, &width
, &height
);
2280 win
->m_icattr
->preedit_area
.width
= width
;
2281 win
->m_icattr
->preedit_area
.height
= height
;
2282 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2288 //-----------------------------------------------------------------------------
2289 // "realize" from m_wxwindow
2290 //-----------------------------------------------------------------------------
2292 /* Initialize XIM support */
2296 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2297 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2300 wxapp_install_idle_handler();
2303 if (win
->m_ic
) return FALSE
;
2304 if (!widget
) return FALSE
;
2305 if (!gdk_im_ready()) return FALSE
;
2307 win
->m_icattr
= gdk_ic_attr_new();
2308 if (!win
->m_icattr
) return FALSE
;
2312 GdkColormap
*colormap
;
2313 GdkICAttr
*attr
= win
->m_icattr
;
2314 unsigned attrmask
= GDK_IC_ALL_REQ
;
2316 GdkIMStyle supported_style
= (GdkIMStyle
)
2317 (GDK_IM_PREEDIT_NONE
|
2318 GDK_IM_PREEDIT_NOTHING
|
2319 GDK_IM_PREEDIT_POSITION
|
2320 GDK_IM_STATUS_NONE
|
2321 GDK_IM_STATUS_NOTHING
);
2323 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2324 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2326 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2327 attr
->client_window
= widget
->window
;
2329 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2330 gtk_widget_get_default_colormap ())
2332 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2333 attr
->preedit_colormap
= colormap
;
2336 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2337 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2338 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2339 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2341 switch (style
& GDK_IM_PREEDIT_MASK
)
2343 case GDK_IM_PREEDIT_POSITION
:
2344 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2346 g_warning ("over-the-spot style requires fontset");
2350 gdk_window_get_size (widget
->window
, &width
, &height
);
2352 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2353 attr
->spot_location
.x
= 0;
2354 attr
->spot_location
.y
= height
;
2355 attr
->preedit_area
.x
= 0;
2356 attr
->preedit_area
.y
= 0;
2357 attr
->preedit_area
.width
= width
;
2358 attr
->preedit_area
.height
= height
;
2359 attr
->preedit_fontset
= widget
->style
->font
;
2364 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2366 if (win
->m_ic
== NULL
)
2367 g_warning ("Can't create input context.");
2370 mask
= gdk_window_get_events (widget
->window
);
2371 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2372 gdk_window_set_events (widget
->window
, mask
);
2374 if (GTK_WIDGET_HAS_FOCUS(widget
))
2375 gdk_im_begin (win
->m_ic
, widget
->window
);
2383 //-----------------------------------------------------------------------------
2384 // InsertChild for wxWindowGTK.
2385 //-----------------------------------------------------------------------------
2387 /* Callback for wxWindowGTK. This very strange beast has to be used because
2388 * C++ has no virtual methods in a constructor. We have to emulate a
2389 * virtual function here as wxNotebook requires a different way to insert
2390 * a child in it. I had opted for creating a wxNotebookPage window class
2391 * which would have made this superfluous (such in the MDI window system),
2392 * but no-one was listening to me... */
2394 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2396 /* the window might have been scrolled already, do we
2397 have to adapt the position */
2398 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2399 child
->m_x
+= pizza
->xoffset
;
2400 child
->m_y
+= pizza
->yoffset
;
2402 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2403 GTK_WIDGET(child
->m_widget
),
2410 //-----------------------------------------------------------------------------
2412 //-----------------------------------------------------------------------------
2414 wxWindow
*wxGetActiveWindow()
2416 return wxWindow::FindFocus();
2420 wxMouseState
wxGetMouseState()
2426 GdkModifierType mask
;
2428 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2432 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2433 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2434 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2436 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2437 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2438 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2439 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2444 //-----------------------------------------------------------------------------
2446 //-----------------------------------------------------------------------------
2448 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2450 #ifdef __WXUNIVERSAL__
2451 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2453 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2454 #endif // __WXUNIVERSAL__/__WXGTK__
2456 void wxWindowGTK::Init()
2459 m_widget
= (GtkWidget
*) NULL
;
2460 m_wxwindow
= (GtkWidget
*) NULL
;
2461 m_focusWidget
= (GtkWidget
*) NULL
;
2471 m_needParent
= true;
2472 m_isBeingDeleted
= false;
2475 m_nativeSizeEvent
= false;
2477 m_hasScrolling
= false;
2478 m_isScrolling
= false;
2480 m_hAdjust
= (GtkAdjustment
*) NULL
;
2481 m_vAdjust
= (GtkAdjustment
*) NULL
;
2482 m_oldHorizontalPos
=
2483 m_oldVerticalPos
= 0.0;
2485 m_oldClientHeight
= 0;
2489 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2491 m_acceptsFocus
= false;
2494 m_clipPaintRegion
= false;
2496 m_needsStyleChange
= false;
2498 m_cursor
= *wxSTANDARD_CURSOR
;
2501 m_dirtyTabOrder
= false;
2504 wxWindowGTK::wxWindowGTK()
2509 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2514 const wxString
&name
)
2518 Create( parent
, id
, pos
, size
, style
, name
);
2521 bool wxWindowGTK::Create( wxWindow
*parent
,
2526 const wxString
&name
)
2528 if (!PreCreation( parent
, pos
, size
) ||
2529 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2531 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2535 m_insertCallback
= wxInsertChildInWindow
;
2537 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2538 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2540 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2542 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2543 scroll_class
->scrollbar_spacing
= 0;
2545 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2547 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2548 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2550 m_wxwindow
= gtk_pizza_new();
2552 #ifndef __WXUNIVERSAL__
2553 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2555 if (HasFlag(wxRAISED_BORDER
))
2557 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2559 else if (HasFlag(wxSUNKEN_BORDER
))
2561 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2563 else if (HasFlag(wxSIMPLE_BORDER
))
2565 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2569 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2571 #endif // __WXUNIVERSAL__
2573 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2575 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2576 m_acceptsFocus
= true;
2578 // I _really_ don't want scrollbars in the beginning
2579 m_vAdjust
->lower
= 0.0;
2580 m_vAdjust
->upper
= 1.0;
2581 m_vAdjust
->value
= 0.0;
2582 m_vAdjust
->step_increment
= 1.0;
2583 m_vAdjust
->page_increment
= 1.0;
2584 m_vAdjust
->page_size
= 5.0;
2585 g_signal_emit_by_name (m_vAdjust
, "changed");
2586 m_hAdjust
->lower
= 0.0;
2587 m_hAdjust
->upper
= 1.0;
2588 m_hAdjust
->value
= 0.0;
2589 m_hAdjust
->step_increment
= 1.0;
2590 m_hAdjust
->page_increment
= 1.0;
2591 m_hAdjust
->page_size
= 5.0;
2592 g_signal_emit_by_name (m_hAdjust
, "changed");
2594 // these handlers block mouse events to any window during scrolling such as
2595 // motion events and prevent GTK and wxWidgets from fighting over where the
2597 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2598 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2599 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2600 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2601 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2602 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2603 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2604 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2606 // these handlers get notified when screen updates are required either when
2607 // scrolling or when the window size (and therefore scrollbar configuration)
2610 g_signal_connect (m_hAdjust
, "value_changed",
2611 G_CALLBACK (gtk_window_hscroll_callback
), this);
2612 g_signal_connect (m_vAdjust
, "value_changed",
2613 G_CALLBACK (gtk_window_vscroll_callback
), this);
2615 gtk_widget_show( m_wxwindow
);
2618 m_parent
->DoAddChild( this );
2620 m_focusWidget
= m_wxwindow
;
2627 wxWindowGTK::~wxWindowGTK()
2631 if (g_focusWindow
== this)
2632 g_focusWindow
= NULL
;
2634 if ( g_delayedFocus
== this )
2635 g_delayedFocus
= NULL
;
2637 m_isBeingDeleted
= true;
2640 // destroy children before destroying this window itself
2643 // unhook focus handlers to prevent stray events being
2644 // propagated to this (soon to be) dead object
2645 if (m_focusWidget
!= NULL
)
2647 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2648 (gpointer
) gtk_window_focus_in_callback
,
2650 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2651 (gpointer
) gtk_window_focus_out_callback
,
2660 gdk_ic_destroy (m_ic
);
2662 gdk_ic_attr_destroy (m_icattr
);
2665 // delete before the widgets to avoid a crash on solaris
2670 gtk_widget_destroy( m_wxwindow
);
2671 m_wxwindow
= (GtkWidget
*) NULL
;
2676 gtk_widget_destroy( m_widget
);
2677 m_widget
= (GtkWidget
*) NULL
;
2681 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2683 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2685 // Use either the given size, or the default if -1 is given.
2686 // See wxWindowBase for these functions.
2687 m_width
= WidthDefault(size
.x
) ;
2688 m_height
= HeightDefault(size
.y
);
2696 void wxWindowGTK::PostCreation()
2698 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2704 // these get reported to wxWidgets -> wxPaintEvent
2706 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2708 g_signal_connect (m_wxwindow
, "expose_event",
2709 G_CALLBACK (gtk_window_expose_callback
), this);
2711 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2714 // Create input method handler
2715 m_imData
= new wxGtkIMData
;
2717 // Cannot handle drawing preedited text yet
2718 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2720 g_signal_connect (m_imData
->context
, "commit",
2721 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2723 // these are called when the "sunken" or "raised" borders are drawn
2724 g_signal_connect (m_widget
, "expose_event",
2725 G_CALLBACK (gtk_window_own_expose_callback
), this);
2730 if (!GTK_IS_WINDOW(m_widget
))
2732 if (m_focusWidget
== NULL
)
2733 m_focusWidget
= m_widget
;
2735 g_signal_connect (m_focusWidget
, "focus_in_event",
2736 G_CALLBACK (gtk_window_focus_in_callback
), this);
2737 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2738 G_CALLBACK (gtk_window_focus_out_callback
), this);
2741 // connect to the various key and mouse handlers
2743 GtkWidget
*connect_widget
= GetConnectWidget();
2745 ConnectWidget( connect_widget
);
2747 /* We cannot set colours, fonts and cursors before the widget has
2748 been realized, so we do this directly after realization */
2749 g_signal_connect (connect_widget
, "realize",
2750 G_CALLBACK (gtk_window_realized_callback
), this);
2754 // Catch native resize events
2755 g_signal_connect (m_wxwindow
, "size_allocate",
2756 G_CALLBACK (gtk_window_size_callback
), this);
2758 // Initialize XIM support
2759 g_signal_connect (m_wxwindow
, "realize",
2760 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2762 // And resize XIM window
2763 g_signal_connect (m_wxwindow
, "size_allocate",
2764 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2767 if (GTK_IS_COMBO(m_widget
))
2769 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2771 g_signal_connect (gcombo
->entry
, "size_request",
2772 G_CALLBACK (wxgtk_combo_size_request_callback
),
2777 // This is needed if we want to add our windows into native
2778 // GTK controls, such as the toolbar. With this callback, the
2779 // toolbar gets to know the correct size (the one set by the
2780 // programmer). Sadly, it misbehaves for wxComboBox.
2781 g_signal_connect (m_widget
, "size_request",
2782 G_CALLBACK (wxgtk_window_size_request_callback
),
2786 InheritAttributes();
2790 // unless the window was created initially hidden (i.e. Hide() had been
2791 // called before Create()), we should show it at GTK+ level as well
2793 gtk_widget_show( m_widget
);
2796 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2798 g_signal_connect (widget
, "key_press_event",
2799 G_CALLBACK (gtk_window_key_press_callback
), this);
2800 g_signal_connect (widget
, "key_release_event",
2801 G_CALLBACK (gtk_window_key_release_callback
), this);
2802 g_signal_connect (widget
, "button_press_event",
2803 G_CALLBACK (gtk_window_button_press_callback
), this);
2804 g_signal_connect (widget
, "button_release_event",
2805 G_CALLBACK (gtk_window_button_release_callback
), this);
2806 g_signal_connect (widget
, "motion_notify_event",
2807 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2808 g_signal_connect (widget
, "scroll_event",
2809 G_CALLBACK (gtk_window_wheel_callback
), this);
2810 g_signal_connect (widget
, "popup_menu",
2811 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2812 g_signal_connect (widget
, "enter_notify_event",
2813 G_CALLBACK (gtk_window_enter_callback
), this);
2814 g_signal_connect (widget
, "leave_notify_event",
2815 G_CALLBACK (gtk_window_leave_callback
), this);
2818 bool wxWindowGTK::Destroy()
2820 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2824 return wxWindowBase::Destroy();
2827 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2829 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2832 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2834 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2835 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2838 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2841 if (m_resizing
) return; /* I don't like recursions */
2844 int currentX
, currentY
;
2845 GetPosition(¤tX
, ¤tY
);
2846 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2848 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2850 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2852 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2854 /* don't set the size for children of wxNotebook, just take the values. */
2862 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2863 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2865 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2866 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2870 m_x
= x
+ pizza
->xoffset
;
2871 m_y
= y
+ pizza
->yoffset
;
2874 // calculate the best size if we should auto size the window
2875 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2876 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2878 const wxSize sizeBest
= GetBestSize();
2879 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2881 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2882 height
= sizeBest
.y
;
2890 int minWidth
= GetMinWidth(),
2891 minHeight
= GetMinHeight(),
2892 maxWidth
= GetMaxWidth(),
2893 maxHeight
= GetMaxHeight();
2895 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2896 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2897 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2898 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2900 int left_border
= 0;
2901 int right_border
= 0;
2903 int bottom_border
= 0;
2905 /* the default button has a border around it */
2906 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2908 GtkBorder
*default_border
= NULL
;
2909 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2912 left_border
+= default_border
->left
;
2913 right_border
+= default_border
->right
;
2914 top_border
+= default_border
->top
;
2915 bottom_border
+= default_border
->bottom
;
2916 g_free( default_border
);
2920 DoMoveWindow( m_x
-top_border
,
2922 m_width
+left_border
+right_border
,
2923 m_height
+top_border
+bottom_border
);
2928 /* Sometimes the client area changes size without the
2929 whole windows's size changing, but if the whole
2930 windows's size doesn't change, no wxSizeEvent will
2931 normally be sent. Here we add an extra test if
2932 the client test has been changed and this will
2934 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2938 wxPrintf( "OnSize sent from " );
2939 if (GetClassInfo() && GetClassInfo()->GetClassName())
2940 wxPrintf( GetClassInfo()->GetClassName() );
2941 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2944 if (!m_nativeSizeEvent
)
2946 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2947 event
.SetEventObject( this );
2948 GetEventHandler()->ProcessEvent( event
);
2954 void wxWindowGTK::OnInternalIdle()
2956 if ( m_dirtyTabOrder
)
2958 m_dirtyTabOrder
= false;
2962 // Update style if the window was not yet realized
2963 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2964 if (m_needsStyleChange
)
2966 SetBackgroundStyle(GetBackgroundStyle());
2967 m_needsStyleChange
= false;
2970 // Update invalidated regions.
2973 wxCursor cursor
= m_cursor
;
2974 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2978 /* I now set the cursor anew in every OnInternalIdle call
2979 as setting the cursor in a parent window also effects the
2980 windows above so that checking for the current cursor is
2985 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2987 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2989 if (!g_globalCursor
.Ok())
2990 cursor
= *wxSTANDARD_CURSOR
;
2992 window
= m_widget
->window
;
2993 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2994 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3000 GdkWindow
*window
= m_widget
->window
;
3001 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3002 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3007 if (wxUpdateUIEvent::CanUpdate(this))
3008 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3011 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3013 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3015 if (width
) (*width
) = m_width
;
3016 if (height
) (*height
) = m_height
;
3019 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3021 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3025 SetSize( width
, height
);
3032 #ifndef __WXUNIVERSAL__
3033 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3035 /* when using GTK 1.2 we set the shadow border size to 2 */
3039 if (HasFlag(wxSIMPLE_BORDER
))
3041 /* when using GTK 1.2 we set the simple border size to 1 */
3045 #endif // __WXUNIVERSAL__
3049 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3051 GtkRequisition vscroll_req
;
3052 vscroll_req
.width
= 2;
3053 vscroll_req
.height
= 2;
3054 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3055 (scroll_window
->vscrollbar
, &vscroll_req
);
3057 GtkRequisition hscroll_req
;
3058 hscroll_req
.width
= 2;
3059 hscroll_req
.height
= 2;
3060 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3061 (scroll_window
->hscrollbar
, &hscroll_req
);
3063 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3065 if (scroll_window
->vscrollbar_visible
)
3067 dw
+= vscroll_req
.width
;
3068 dw
+= scroll_class
->scrollbar_spacing
;
3071 if (scroll_window
->hscrollbar_visible
)
3073 dh
+= hscroll_req
.height
;
3074 dh
+= scroll_class
->scrollbar_spacing
;
3078 SetSize( width
+dw
, height
+dh
);
3082 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3084 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3088 if (width
) (*width
) = m_width
;
3089 if (height
) (*height
) = m_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 if (width
) (*width
) = m_width
- dw
;
3143 if (height
) (*height
) = m_height
- dh
;
3147 printf( "GetClientSize, name %s ", GetName().c_str() );
3148 if (width) printf( " width = %d", (*width) );
3149 if (height) printf( " height = %d", (*height) );
3154 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3156 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3160 if (m_parent
&& m_parent
->m_wxwindow
)
3162 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3163 dx
= pizza
->xoffset
;
3164 dy
= pizza
->yoffset
;
3167 if (x
) (*x
) = m_x
- dx
;
3168 if (y
) (*y
) = m_y
- dy
;
3171 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3173 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3175 if (!m_widget
->window
) return;
3177 GdkWindow
*source
= (GdkWindow
*) NULL
;
3179 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3181 source
= m_widget
->window
;
3185 gdk_window_get_origin( source
, &org_x
, &org_y
);
3189 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3191 org_x
+= m_widget
->allocation
.x
;
3192 org_y
+= m_widget
->allocation
.y
;
3200 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3202 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3204 if (!m_widget
->window
) return;
3206 GdkWindow
*source
= (GdkWindow
*) NULL
;
3208 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3210 source
= m_widget
->window
;
3214 gdk_window_get_origin( source
, &org_x
, &org_y
);
3218 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3220 org_x
+= m_widget
->allocation
.x
;
3221 org_y
+= m_widget
->allocation
.y
;
3229 bool wxWindowGTK::Show( bool show
)
3231 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3233 if (!wxWindowBase::Show(show
))
3240 gtk_widget_show( m_widget
);
3242 gtk_widget_hide( m_widget
);
3244 wxShowEvent
eventShow(GetId(), show
);
3245 eventShow
.SetEventObject(this);
3247 GetEventHandler()->ProcessEvent(eventShow
);
3252 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3254 win
->OnParentEnable(enable
);
3256 // Recurse, so that children have the opportunity to Do The Right Thing
3257 // and reset colours that have been messed up by a parent's (really ancestor's)
3259 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3261 node
= node
->GetNext() )
3263 wxWindow
*child
= node
->GetData();
3264 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3265 wxWindowNotifyEnable(child
, enable
);
3269 bool wxWindowGTK::Enable( bool enable
)
3271 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3273 if (!wxWindowBase::Enable(enable
))
3279 gtk_widget_set_sensitive( m_widget
, enable
);
3281 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3283 wxWindowNotifyEnable(this, enable
);
3288 int wxWindowGTK::GetCharHeight() const
3290 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3292 wxFont font
= GetFont();
3293 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3295 PangoContext
*context
= NULL
;
3297 context
= gtk_widget_get_pango_context( m_widget
);
3302 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3303 PangoLayout
*layout
= pango_layout_new(context
);
3304 pango_layout_set_font_description(layout
, desc
);
3305 pango_layout_set_text(layout
, "H", 1);
3306 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3308 PangoRectangle rect
;
3309 pango_layout_line_get_extents(line
, NULL
, &rect
);
3311 g_object_unref( G_OBJECT( layout
) );
3313 return (int) PANGO_PIXELS(rect
.height
);
3316 int wxWindowGTK::GetCharWidth() const
3318 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3320 wxFont font
= GetFont();
3321 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3323 PangoContext
*context
= NULL
;
3325 context
= gtk_widget_get_pango_context( m_widget
);
3330 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3331 PangoLayout
*layout
= pango_layout_new(context
);
3332 pango_layout_set_font_description(layout
, desc
);
3333 pango_layout_set_text(layout
, "g", 1);
3334 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3336 PangoRectangle rect
;
3337 pango_layout_line_get_extents(line
, NULL
, &rect
);
3339 g_object_unref( G_OBJECT( layout
) );
3341 return (int) PANGO_PIXELS(rect
.width
);
3344 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3348 int *externalLeading
,
3349 const wxFont
*theFont
) const
3351 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3353 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3362 PangoContext
*context
= NULL
;
3364 context
= gtk_widget_get_pango_context( m_widget
);
3373 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3374 PangoLayout
*layout
= pango_layout_new(context
);
3375 pango_layout_set_font_description(layout
, desc
);
3378 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3379 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3381 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3382 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3383 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3387 PangoRectangle rect
;
3388 pango_layout_get_extents(layout
, NULL
, &rect
);
3390 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3391 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3394 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3395 int baseline
= pango_layout_iter_get_baseline(iter
);
3396 pango_layout_iter_free(iter
);
3397 *descent
= *y
- PANGO_PIXELS(baseline
);
3399 if (externalLeading
) (*externalLeading
) = 0; // ??
3401 g_object_unref( G_OBJECT( layout
) );
3404 void wxWindowGTK::SetFocus()
3406 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3409 // don't do anything if we already have focus
3415 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3417 gtk_widget_grab_focus (m_wxwindow
);
3422 if (GTK_IS_CONTAINER(m_widget
))
3424 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3427 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3430 if (!GTK_WIDGET_REALIZED(m_widget
))
3432 // we can't set the focus to the widget now so we remember that
3433 // it should be focused and will do it later, during the idle
3434 // time, as soon as we can
3435 wxLogTrace(TRACE_FOCUS
,
3436 _T("Delaying setting focus to %s(%s)"),
3437 GetClassInfo()->GetClassName(), GetLabel().c_str());
3439 g_delayedFocus
= this;
3443 wxLogTrace(TRACE_FOCUS
,
3444 _T("Setting focus to %s(%s)"),
3445 GetClassInfo()->GetClassName(), GetLabel().c_str());
3447 gtk_widget_grab_focus (m_widget
);
3452 wxLogTrace(TRACE_FOCUS
,
3453 _T("Can't set focus to %s(%s)"),
3454 GetClassInfo()->GetClassName(), GetLabel().c_str());
3459 bool wxWindowGTK::AcceptsFocus() const
3461 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3464 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3466 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3468 wxWindowGTK
*oldParent
= m_parent
,
3469 *newParent
= (wxWindowGTK
*)newParentBase
;
3471 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3473 if ( !wxWindowBase::Reparent(newParent
) )
3476 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3478 /* prevent GTK from deleting the widget arbitrarily */
3479 gtk_widget_ref( m_widget
);
3483 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3486 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3490 /* insert GTK representation */
3491 (*(newParent
->m_insertCallback
))(newParent
, this);
3494 /* reverse: prevent GTK from deleting the widget arbitrarily */
3495 gtk_widget_unref( m_widget
);
3500 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3502 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3504 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3506 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3511 /* insert GTK representation */
3512 (*m_insertCallback
)(this, child
);
3515 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3517 wxWindowBase::AddChild(child
);
3518 m_dirtyTabOrder
= true;
3520 wxapp_install_idle_handler();
3523 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3525 wxWindowBase::RemoveChild(child
);
3526 m_dirtyTabOrder
= true;
3528 wxapp_install_idle_handler();
3531 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3533 wxWindowBase::DoMoveInTabOrder(win
, move
);
3534 m_dirtyTabOrder
= true;
3536 wxapp_install_idle_handler();
3539 void wxWindowGTK::RealizeTabOrder()
3543 if ( !m_children
.empty() )
3545 GList
*chain
= NULL
;
3547 for ( wxWindowList::const_iterator i
= m_children
.begin();
3548 i
!= m_children
.end();
3551 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3554 chain
= g_list_reverse(chain
);
3556 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3561 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3566 void wxWindowGTK::Raise()
3568 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3570 if (m_wxwindow
&& m_wxwindow
->window
)
3572 gdk_window_raise( m_wxwindow
->window
);
3574 else if (m_widget
->window
)
3576 gdk_window_raise( m_widget
->window
);
3580 void wxWindowGTK::Lower()
3582 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3584 if (m_wxwindow
&& m_wxwindow
->window
)
3586 gdk_window_lower( m_wxwindow
->window
);
3588 else if (m_widget
->window
)
3590 gdk_window_lower( m_widget
->window
);
3594 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3596 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3598 if (cursor
== m_cursor
)
3602 wxapp_install_idle_handler();
3604 if (cursor
== wxNullCursor
)
3605 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3607 return wxWindowBase::SetCursor( cursor
);
3610 void wxWindowGTK::WarpPointer( int x
, int y
)
3612 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3614 // We provide this function ourselves as it is
3615 // missing in GDK (top of this file).
3617 GdkWindow
*window
= (GdkWindow
*) NULL
;
3619 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3621 window
= GetConnectWidget()->window
;
3624 gdk_window_warp_pointer( window
, x
, y
);
3628 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3632 if (!m_widget
->window
)
3637 GdkRectangle gdk_rect
,
3641 gdk_rect
.x
= rect
->x
;
3642 gdk_rect
.y
= rect
->y
;
3643 gdk_rect
.width
= rect
->width
;
3644 gdk_rect
.height
= rect
->height
;
3647 else // invalidate everything
3652 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3656 void wxWindowGTK::Update()
3660 // when we call Update() we really want to update the window immediately on
3661 // screen, even if it means flushing the entire queue and hence slowing down
3662 // everything -- but it should still be done, it's just that Update() should
3663 // be called very rarely
3667 void wxWindowGTK::GtkUpdate()
3669 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3670 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3672 // for consistency with other platforms (and also because it's convenient
3673 // to be able to update an entire TLW by calling Update() only once), we
3674 // should also update all our children here
3675 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3677 node
= node
->GetNext() )
3679 node
->GetData()->GtkUpdate();
3683 void wxWindowGTK::GtkSendPaintEvents()
3687 m_updateRegion
.Clear();
3691 // Clip to paint region in wxClientDC
3692 m_clipPaintRegion
= true;
3694 // widget to draw on
3695 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3697 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3699 // find ancestor from which to steal background
3700 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3702 parent
= (wxWindow
*)this;
3704 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3706 wxRegionIterator
upd( m_updateRegion
);
3710 rect
.x
= upd
.GetX();
3711 rect
.y
= upd
.GetY();
3712 rect
.width
= upd
.GetWidth();
3713 rect
.height
= upd
.GetHeight();
3715 gtk_paint_flat_box( parent
->m_widget
->style
,
3717 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3731 wxWindowDC
dc( (wxWindow
*)this );
3732 dc
.SetClippingRegion( m_updateRegion
);
3734 wxEraseEvent
erase_event( GetId(), &dc
);
3735 erase_event
.SetEventObject( this );
3737 GetEventHandler()->ProcessEvent(erase_event
);
3740 wxNcPaintEvent
nc_paint_event( GetId() );
3741 nc_paint_event
.SetEventObject( this );
3742 GetEventHandler()->ProcessEvent( nc_paint_event
);
3744 wxPaintEvent
paint_event( GetId() );
3745 paint_event
.SetEventObject( this );
3746 GetEventHandler()->ProcessEvent( paint_event
);
3748 m_clipPaintRegion
= false;
3750 m_updateRegion
.Clear();
3753 void wxWindowGTK::ClearBackground()
3755 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3759 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3761 wxWindowBase::DoSetToolTip(tip
);
3764 m_tooltip
->Apply( (wxWindow
*)this );
3767 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3769 wxString
tmp( tip
);
3770 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3772 #endif // wxUSE_TOOLTIPS
3774 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3776 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3778 if (!wxWindowBase::SetBackgroundColour(colour
))
3783 // We need the pixel value e.g. for background clearing.
3784 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3787 // apply style change (forceStyle=true so that new style is applied
3788 // even if the bg colour changed from valid to wxNullColour)
3789 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3790 ApplyWidgetStyle(true);
3795 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3797 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3799 if (!wxWindowBase::SetForegroundColour(colour
))
3806 // We need the pixel value e.g. for background clearing.
3807 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3810 // apply style change (forceStyle=true so that new style is applied
3811 // even if the bg colour changed from valid to wxNullColour):
3812 ApplyWidgetStyle(true);
3817 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3819 return gtk_widget_get_pango_context( m_widget
);
3822 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3824 // do we need to apply any changes at all?
3827 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3832 GtkRcStyle
*style
= gtk_rc_style_new();
3837 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3840 if ( m_foregroundColour
.Ok() )
3842 GdkColor
*fg
= m_foregroundColour
.GetColor();
3844 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3845 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3847 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3848 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3850 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3851 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3854 if ( m_backgroundColour
.Ok() )
3856 GdkColor
*bg
= m_backgroundColour
.GetColor();
3858 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3859 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3860 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3861 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3863 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3864 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3865 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3866 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3868 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3869 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3870 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3871 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3873 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3874 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3875 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3876 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3882 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3884 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3887 DoApplyWidgetStyle(style
);
3888 gtk_rc_style_unref(style
);
3891 // Style change may affect GTK+'s size calculation:
3892 InvalidateBestSize();
3895 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3898 gtk_widget_modify_style(m_wxwindow
, style
);
3900 gtk_widget_modify_style(m_widget
, style
);
3903 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3905 wxWindowBase::SetBackgroundStyle(style
);
3907 if (style
== wxBG_STYLE_CUSTOM
)
3909 GdkWindow
*window
= (GdkWindow
*) NULL
;
3911 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3913 window
= GetConnectWidget()->window
;
3917 // Make sure GDK/X11 doesn't refresh the window
3919 gdk_window_set_back_pixmap( window
, None
, False
);
3921 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3924 m_needsStyleChange
= false;
3927 // Do in OnIdle, because the window is not yet available
3928 m_needsStyleChange
= true;
3930 // Don't apply widget style, or we get a grey background
3934 // apply style change (forceStyle=true so that new style is applied
3935 // even if the bg colour changed from valid to wxNullColour):
3936 ApplyWidgetStyle(true);
3941 #if wxUSE_DRAG_AND_DROP
3943 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3945 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3947 GtkWidget
*dnd_widget
= GetConnectWidget();
3949 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3951 if (m_dropTarget
) delete m_dropTarget
;
3952 m_dropTarget
= dropTarget
;
3954 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3957 #endif // wxUSE_DRAG_AND_DROP
3959 GtkWidget
* wxWindowGTK::GetConnectWidget()
3961 GtkWidget
*connect_widget
= m_widget
;
3962 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3964 return connect_widget
;
3967 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3970 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3972 return (window
== m_widget
->window
);
3975 bool wxWindowGTK::SetFont( const wxFont
&font
)
3977 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3979 if (!wxWindowBase::SetFont(font
))
3982 // apply style change (forceStyle=true so that new style is applied
3983 // even if the font changed from valid to wxNullFont):
3984 ApplyWidgetStyle(true);
3989 void wxWindowGTK::DoCaptureMouse()
3991 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3993 GdkWindow
*window
= (GdkWindow
*) NULL
;
3995 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3997 window
= GetConnectWidget()->window
;
3999 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4001 wxCursor
* cursor
= & m_cursor
;
4003 cursor
= wxSTANDARD_CURSOR
;
4005 gdk_pointer_grab( window
, FALSE
,
4007 (GDK_BUTTON_PRESS_MASK
|
4008 GDK_BUTTON_RELEASE_MASK
|
4009 GDK_POINTER_MOTION_HINT_MASK
|
4010 GDK_POINTER_MOTION_MASK
),
4012 cursor
->GetCursor(),
4013 (guint32
)GDK_CURRENT_TIME
);
4014 g_captureWindow
= this;
4015 g_captureWindowHasMouse
= true;
4018 void wxWindowGTK::DoReleaseMouse()
4020 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4022 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4024 g_captureWindow
= (wxWindowGTK
*) NULL
;
4026 GdkWindow
*window
= (GdkWindow
*) NULL
;
4028 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4030 window
= GetConnectWidget()->window
;
4035 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4039 wxWindow
*wxWindowBase::GetCapture()
4041 return (wxWindow
*)g_captureWindow
;
4044 bool wxWindowGTK::IsRetained() const
4049 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4050 int range
, bool refresh
)
4052 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4054 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4056 m_hasScrolling
= true;
4058 if (orient
== wxHORIZONTAL
)
4060 float fpos
= (float)pos
;
4061 float frange
= (float)range
;
4062 float fthumb
= (float)thumbVisible
;
4063 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4064 if (fpos
< 0.0) fpos
= 0.0;
4066 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4067 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4069 SetScrollPos( orient
, pos
, refresh
);
4073 m_oldHorizontalPos
= fpos
;
4075 m_hAdjust
->lower
= 0.0;
4076 m_hAdjust
->upper
= frange
;
4077 m_hAdjust
->value
= fpos
;
4078 m_hAdjust
->step_increment
= 1.0;
4079 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4080 m_hAdjust
->page_size
= fthumb
;
4084 float fpos
= (float)pos
;
4085 float frange
= (float)range
;
4086 float fthumb
= (float)thumbVisible
;
4087 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4088 if (fpos
< 0.0) fpos
= 0.0;
4090 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4091 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4093 SetScrollPos( orient
, pos
, refresh
);
4097 m_oldVerticalPos
= fpos
;
4099 m_vAdjust
->lower
= 0.0;
4100 m_vAdjust
->upper
= frange
;
4101 m_vAdjust
->value
= fpos
;
4102 m_vAdjust
->step_increment
= 1.0;
4103 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4104 m_vAdjust
->page_size
= fthumb
;
4107 if (orient
== wxHORIZONTAL
)
4108 g_signal_emit_by_name (m_hAdjust
, "changed");
4110 g_signal_emit_by_name (m_vAdjust
, "changed");
4113 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4115 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4116 gpointer fn
= orient
== wxHORIZONTAL
4117 ? (gpointer
) gtk_window_hscroll_callback
4118 : (gpointer
) gtk_window_vscroll_callback
;
4120 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4121 g_signal_emit_by_name (adj
, "value_changed");
4122 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4125 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4127 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4128 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4130 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4132 float fpos
= (float)pos
;
4133 if (fpos
> adj
->upper
- adj
->page_size
)
4134 fpos
= adj
->upper
- adj
->page_size
;
4137 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4139 if (fabs(fpos
-adj
->value
) < 0.2)
4143 if ( m_wxwindow
->window
)
4148 int wxWindowGTK::GetScrollThumb( int orient
) const
4150 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4152 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4154 if (orient
== wxHORIZONTAL
)
4155 return (int)(m_hAdjust
->page_size
+0.5);
4157 return (int)(m_vAdjust
->page_size
+0.5);
4160 int wxWindowGTK::GetScrollPos( int orient
) const
4162 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4164 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4166 if (orient
== wxHORIZONTAL
)
4167 return (int)(m_hAdjust
->value
+0.5);
4169 return (int)(m_vAdjust
->value
+0.5);
4172 int wxWindowGTK::GetScrollRange( int orient
) const
4174 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4176 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4178 if (orient
== wxHORIZONTAL
)
4179 return (int)(m_hAdjust
->upper
+0.5);
4181 return (int)(m_vAdjust
->upper
+0.5);
4184 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4186 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4188 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4190 // No scrolling requested.
4191 if ((dx
== 0) && (dy
== 0)) return;
4193 m_clipPaintRegion
= true;
4195 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4197 m_clipPaintRegion
= false;
4200 void wxWindowGTK::SetWindowStyleFlag( long style
)
4202 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4203 wxWindowBase::SetWindowStyleFlag(style
);
4206 // Find the wxWindow at the current mouse position, also returning the mouse
4208 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4210 pt
= wxGetMousePosition();
4211 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4215 // Get the current mouse position.
4216 wxPoint
wxGetMousePosition()
4218 /* This crashes when used within wxHelpContext,
4219 so we have to use the X-specific implementation below.
4221 GdkModifierType *mask;
4222 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4224 return wxPoint(x, y);
4228 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4230 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4231 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4232 Window rootReturn
, childReturn
;
4233 int rootX
, rootY
, winX
, winY
;
4234 unsigned int maskReturn
;
4236 XQueryPointer (display
,
4240 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4241 return wxPoint(rootX
, rootY
);
4245 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4246 void wxAddGrab(wxWindow
* window
)
4248 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4251 void wxRemoveGrab(wxWindow
* window
)
4253 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4256 // ----------------------------------------------------------------------------
4258 // ----------------------------------------------------------------------------
4260 class wxWinModule
: public wxModule
4267 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4270 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4272 bool wxWinModule::OnInit()
4274 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4275 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4280 void wxWinModule::OnExit()
4283 gdk_gc_unref( g_eraseGC
);