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_draw_shadow( widget
->style
,
366 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
370 if (win
->HasFlag(wxSUNKEN_BORDER
))
372 gtk_draw_shadow( widget
->style
,
377 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
381 if (win
->HasFlag(wxSIMPLE_BORDER
))
384 gc
= gdk_gc_new( widget
->window
);
385 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
386 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
388 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
392 #endif // __WXUNIVERSAL__
395 //-----------------------------------------------------------------------------
396 // "expose_event" of m_widget
397 //-----------------------------------------------------------------------------
400 static gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
402 if (gdk_event
->count
> 0) return FALSE
;
404 draw_frame( widget
, win
);
406 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
412 //-----------------------------------------------------------------------------
413 // "size_request" of m_widget
414 //-----------------------------------------------------------------------------
416 // make it extern because wxStaticText needs to disconnect this one
418 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
419 GtkRequisition
*requisition
,
423 win
->GetSize( &w
, &h
);
429 requisition
->height
= h
;
430 requisition
->width
= w
;
436 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
437 GtkRequisition
*requisition
,
440 // This callback is actually hooked into the text entry
441 // of the combo box, not the GtkHBox.
444 win
->GetSize( &w
, &h
);
450 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
452 GtkRequisition entry_req
;
454 entry_req
.height
= 2;
455 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
456 (gcombo
->button
, &entry_req
);
458 requisition
->width
= w
- entry_req
.width
;
459 requisition
->height
= entry_req
.height
;
463 //-----------------------------------------------------------------------------
464 // "expose_event" of m_wxwindow
465 //-----------------------------------------------------------------------------
468 static int gtk_window_expose_callback( GtkWidget
*widget
,
469 GdkEventExpose
*gdk_event
,
475 wxapp_install_idle_handler();
477 // This callback gets called in drawing-idle time under
478 // GTK 2.0, so we don't need to defer anything to idle
481 GtkPizza
*pizza
= GTK_PIZZA( widget
);
482 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
487 wxPrintf( wxT("OnExpose from ") );
488 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
489 wxPrintf( win
->GetClassInfo()->GetClassName() );
490 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
491 (int)gdk_event
->area
.y
,
492 (int)gdk_event
->area
.width
,
493 (int)gdk_event
->area
.height
);
498 win
->m_wxwindow
->style
,
502 (GdkRectangle
*) NULL
,
504 (char *)"button", // const_cast
509 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
511 win
->GtkSendPaintEvents();
514 // Let parent window draw window-less widgets
515 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
521 //-----------------------------------------------------------------------------
522 // "key_press_event" from any window
523 //-----------------------------------------------------------------------------
525 // set WXTRACE to this to see the key event codes on the console
526 #define TRACE_KEYS _T("keyevent")
528 // translates an X key symbol to WXK_XXX value
530 // if isChar is true it means that the value returned will be used for EVT_CHAR
531 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
532 // for example, while if it is false it means that the value is going to be
533 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
535 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
541 // Shift, Control and Alt don't generate the CHAR events at all
544 key_code
= isChar
? 0 : WXK_SHIFT
;
548 key_code
= isChar
? 0 : WXK_CONTROL
;
556 key_code
= isChar
? 0 : WXK_ALT
;
559 // neither do the toggle modifies
560 case GDK_Scroll_Lock
:
561 key_code
= isChar
? 0 : WXK_SCROLL
;
565 key_code
= isChar
? 0 : WXK_CAPITAL
;
569 key_code
= isChar
? 0 : WXK_NUMLOCK
;
573 // various other special keys
586 case GDK_ISO_Left_Tab
:
593 key_code
= WXK_RETURN
;
597 key_code
= WXK_CLEAR
;
601 key_code
= WXK_PAUSE
;
605 key_code
= WXK_SELECT
;
609 key_code
= WXK_PRINT
;
613 key_code
= WXK_EXECUTE
;
617 key_code
= WXK_ESCAPE
;
620 // cursor and other extended keyboard keys
622 key_code
= WXK_DELETE
;
638 key_code
= WXK_RIGHT
;
645 case GDK_Prior
: // == GDK_Page_Up
646 key_code
= WXK_PRIOR
;
649 case GDK_Next
: // == GDK_Page_Down
662 key_code
= WXK_INSERT
;
677 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
681 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
685 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
689 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
693 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
697 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
701 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
705 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
709 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
713 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
717 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
721 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
725 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
728 case GDK_KP_Prior
: // == GDK_KP_Page_Up
729 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
732 case GDK_KP_Next
: // == GDK_KP_Page_Down
733 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
737 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
741 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
745 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
749 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
753 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
756 case GDK_KP_Multiply
:
757 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
761 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
764 case GDK_KP_Separator
:
765 // FIXME: what is this?
766 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
769 case GDK_KP_Subtract
:
770 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
774 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
778 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
795 key_code
= WXK_F1
+ keysym
- GDK_F1
;
805 static inline bool wxIsAsciiKeysym(KeySym ks
)
810 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
812 GdkEventKey
*gdk_event
)
816 GdkModifierType state
;
817 if (gdk_event
->window
)
818 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
820 event
.SetTimestamp( gdk_event
->time
);
821 event
.SetId(win
->GetId());
822 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
823 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
824 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
825 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
826 event
.m_scanCode
= gdk_event
->keyval
;
827 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
828 event
.m_rawFlags
= 0;
830 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
832 wxGetMousePosition( &x
, &y
);
833 win
->ScreenToClient( &x
, &y
);
836 event
.SetEventObject( win
);
841 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
843 GdkEventKey
*gdk_event
)
845 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
846 // but only event->keyval which is quite useless to us, so remember
847 // the last character from GDK_KEY_PRESS and reuse it as last resort
849 // NB: should be MT-safe as we're always called from the main thread only
854 } s_lastKeyPress
= { 0, 0 };
856 KeySym keysym
= gdk_event
->keyval
;
858 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
859 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
863 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
867 // do we have the translation or is it a plain ASCII character?
868 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
870 // we should use keysym if it is ASCII as X does some translations
871 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
872 // which we don't want here (but which we do use for OnChar())
873 if ( !wxIsAsciiKeysym(keysym
) )
875 keysym
= (KeySym
)gdk_event
->string
[0];
878 // we want to always get the same key code when the same key is
879 // pressed regardless of the state of the modifiers, i.e. on a
880 // standard US keyboard pressing '5' or '%' ('5' key with
881 // Shift) should result in the same key code in OnKeyDown():
882 // '5' (although OnChar() will get either '5' or '%').
884 // to do it we first translate keysym to keycode (== scan code)
885 // and then back but always using the lower register
886 Display
*dpy
= (Display
*)wxGetDisplay();
887 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
889 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
891 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
893 // use the normalized, i.e. lower register, keysym if we've
895 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
897 // as explained above, we want to have lower register key codes
898 // normally but for the letter keys we want to have the upper ones
900 // NB: don't use XConvertCase() here, we want to do it for letters
902 key_code
= toupper(key_code
);
904 else // non ASCII key, what to do?
906 // by default, ignore it
909 // but if we have cached information from the last KEY_PRESS
910 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
913 if ( keysym
== s_lastKeyPress
.keysym
)
915 key_code
= s_lastKeyPress
.keycode
;
920 if ( gdk_event
->type
== GDK_KEY_PRESS
)
922 // remember it to be reused for KEY_UP event later
923 s_lastKeyPress
.keysym
= keysym
;
924 s_lastKeyPress
.keycode
= key_code
;
928 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
930 // sending unknown key events doesn't really make sense
934 // now fill all the other fields
935 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
937 event
.m_keyCode
= key_code
;
945 GtkIMContext
*context
;
946 GdkEventKey
*lastKeyEvent
;
950 context
= gtk_im_multicontext_new();
955 g_object_unref(context
);
960 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
961 GdkEventKey
*gdk_event
,
967 wxapp_install_idle_handler();
971 if (g_blockEventsOnDrag
)
975 wxKeyEvent
event( wxEVT_KEY_DOWN
);
977 bool return_after_IM
= false;
979 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) == false )
981 // Return after IM processing as we cannot do
982 // anything with it anyhow.
983 return_after_IM
= true;
986 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
987 // When we get a key_press event here, it could be originate
988 // from the current widget or its child widgets. However, only the widget
989 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
990 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
991 // originated from its child widgets and shouldn't be passed to IM context.
992 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
993 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
994 // widgets has both IM context and input focus, the event should be filtered
995 // by gtk_im_context_filter_keypress().
996 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
997 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
999 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1000 // docs, if IM filter returns true, no further processing should be done.
1001 // we should send the key_down event anyway.
1002 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1003 win
->m_imData
->lastKeyEvent
= NULL
;
1004 if (intercepted_by_IM
)
1006 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1011 if (return_after_IM
)
1014 // Emit KEY_DOWN event
1015 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1020 wxWindowGTK
*ancestor
= win
;
1023 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1026 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1027 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1030 if (ancestor
->IsTopLevel())
1032 ancestor
= ancestor
->GetParent();
1035 #endif // wxUSE_ACCEL
1037 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1038 // will only be sent if it is not in an accelerator table.
1042 KeySym keysym
= gdk_event
->keyval
;
1043 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1044 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1047 if ( wxIsAsciiKeysym(keysym
) )
1050 key_code
= (unsigned char)keysym
;
1052 // gdk_event->string is actually deprecated
1053 else if ( gdk_event
->length
== 1 )
1055 key_code
= (unsigned char)gdk_event
->string
[0];
1061 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1063 event
.m_keyCode
= key_code
;
1065 // Implement OnCharHook by checking ancestor top level windows
1066 wxWindow
*parent
= win
;
1067 while (parent
&& !parent
->IsTopLevel())
1068 parent
= parent
->GetParent();
1071 event
.SetEventType( wxEVT_CHAR_HOOK
);
1072 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1077 event
.SetEventType(wxEVT_CHAR
);
1078 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1087 // win is a control: tab can be propagated up
1089 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1090 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1091 // have this style, yet choose not to process this particular TAB in which
1092 // case TAB must still work as a navigational character
1093 // JS: enabling again to make consistent with other platforms
1094 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1095 // navigation behaviour)
1097 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1099 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1101 wxNavigationKeyEvent new_event
;
1102 new_event
.SetEventObject( win
->GetParent() );
1103 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1104 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1105 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1106 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1107 new_event
.SetCurrentFocus( win
);
1108 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1111 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1113 (gdk_event
->keyval
== GDK_Escape
) )
1115 // however only do it if we have a Cancel button in the dialog,
1116 // otherwise the user code may get confused by the events from a
1117 // non-existing button and, worse, a wxButton might get button event
1118 // from another button which is not really expected
1119 wxWindow
*winForCancel
= win
,
1121 while ( winForCancel
)
1123 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1126 // found a cancel button
1130 if ( winForCancel
->IsTopLevel() )
1132 // no need to look further
1136 // maybe our parent has a cancel button?
1137 winForCancel
= winForCancel
->GetParent();
1142 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1143 eventClick
.SetEventObject(btnCancel
);
1144 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1150 g_signal_stop_emission_by_name (widget
, "key_press_event");
1159 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1163 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1165 // take modifiers, cursor position, timestamp etc. from the last
1166 // key_press_event that was fed into Input Method:
1167 if (window
->m_imData
->lastKeyEvent
)
1169 wxFillOtherKeyEventFields(event
,
1170 window
, window
->m_imData
->lastKeyEvent
);
1174 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1176 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1177 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1178 #endif // wxUSE_UNICODE
1179 if( !(const wxChar
*)data
)
1184 // Implement OnCharHook by checking ancestor top level windows
1185 wxWindow
*parent
= window
;
1186 while (parent
&& !parent
->IsTopLevel())
1187 parent
= parent
->GetParent();
1189 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1192 event
.m_uniChar
= *pstr
;
1193 // Backward compatible for ISO-8859-1
1194 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1195 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1197 event
.m_keyCode
= *pstr
;
1198 #endif // wxUSE_UNICODE
1201 event
.SetEventType( wxEVT_CHAR_HOOK
);
1202 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1207 event
.SetEventType(wxEVT_CHAR
);
1208 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1215 //-----------------------------------------------------------------------------
1216 // "key_release_event" from any window
1217 //-----------------------------------------------------------------------------
1220 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1221 GdkEventKey
*gdk_event
,
1227 wxapp_install_idle_handler();
1232 if (g_blockEventsOnDrag
)
1235 wxKeyEvent
event( wxEVT_KEY_UP
);
1236 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1238 // unknown key pressed, ignore (the event would be useless anyhow)
1242 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1245 g_signal_stop_emission_by_name (widget
, "key_release_event");
1250 // ============================================================================
1252 // ============================================================================
1254 // ----------------------------------------------------------------------------
1255 // mouse event processing helpers
1256 // ----------------------------------------------------------------------------
1258 // init wxMouseEvent with the info from GdkEventXXX struct
1259 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1260 wxMouseEvent
& event
,
1263 event
.SetTimestamp( gdk_event
->time
);
1264 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1265 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1266 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1267 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1268 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1269 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1270 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1271 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1273 event
.m_linesPerAction
= 3;
1274 event
.m_wheelDelta
= 120;
1275 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1276 event
.m_wheelRotation
= 120;
1277 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1278 event
.m_wheelRotation
= -120;
1281 wxPoint pt
= win
->GetClientAreaOrigin();
1282 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1283 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1285 event
.SetEventObject( win
);
1286 event
.SetId( win
->GetId() );
1287 event
.SetTimestamp( gdk_event
->time
);
1290 static void AdjustEventButtonState(wxMouseEvent
& event
)
1292 // GDK reports the old state of the button for a button press event, but
1293 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1294 // for a LEFT_DOWN event, not FALSE, so we will invert
1295 // left/right/middleDown for the corresponding click events
1297 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1298 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1299 (event
.GetEventType() == wxEVT_LEFT_UP
))
1301 event
.m_leftDown
= !event
.m_leftDown
;
1305 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1306 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1307 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1309 event
.m_middleDown
= !event
.m_middleDown
;
1313 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1314 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1315 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1317 event
.m_rightDown
= !event
.m_rightDown
;
1322 // find the window to send the mouse event too
1324 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1329 if (win
->m_wxwindow
)
1331 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1332 xx
+= pizza
->xoffset
;
1333 yy
+= pizza
->yoffset
;
1336 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1339 wxWindowGTK
*child
= node
->GetData();
1341 node
= node
->GetNext();
1342 if (!child
->IsShown())
1345 if (child
->IsTransparentForMouse())
1347 // wxStaticBox is transparent in the box itself
1348 int xx1
= child
->m_x
;
1349 int yy1
= child
->m_y
;
1350 int xx2
= child
->m_x
+ child
->m_width
;
1351 int yy2
= child
->m_y
+ child
->m_height
;
1354 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1356 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1358 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1360 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1371 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1372 (child
->m_x
<= xx
) &&
1373 (child
->m_y
<= yy
) &&
1374 (child
->m_x
+child
->m_width
>= xx
) &&
1375 (child
->m_y
+child
->m_height
>= yy
))
1388 //-----------------------------------------------------------------------------
1389 // "button_press_event"
1390 //-----------------------------------------------------------------------------
1393 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1394 GdkEventButton
*gdk_event
,
1400 wxapp_install_idle_handler();
1403 wxPrintf( wxT("1) OnButtonPress from ") );
1404 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1405 wxPrintf( win->GetClassInfo()->GetClassName() );
1406 wxPrintf( wxT(".\n") );
1408 if (!win
->m_hasVMT
) return FALSE
;
1409 if (g_blockEventsOnDrag
) return TRUE
;
1410 if (g_blockEventsOnScroll
) return TRUE
;
1412 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1414 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1416 gtk_widget_grab_focus( win
->m_wxwindow
);
1418 wxPrintf( wxT("GrabFocus from ") );
1419 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1420 wxPrintf( win->GetClassInfo()->GetClassName() );
1421 wxPrintf( wxT(".\n") );
1425 // GDK sends surplus button down events
1426 // before a double click event. We
1427 // need to filter these out.
1428 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1430 GdkEvent
*peek_event
= gdk_event_peek();
1433 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1434 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1436 gdk_event_free( peek_event
);
1441 gdk_event_free( peek_event
);
1446 wxEventType event_type
= wxEVT_NULL
;
1448 // GdkDisplay is a GTK+ 2.2.0 thing
1449 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1450 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1451 !gtk_check_version(2,2,0) &&
1452 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1454 // Reset GDK internal timestamp variables in order to disable GDK
1455 // triple click events. GDK will then next time believe no button has
1456 // been clicked just before, and send a normal button click event.
1457 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1458 display
->button_click_time
[1] = 0;
1459 display
->button_click_time
[0] = 0;
1463 if (gdk_event
->button
== 1)
1465 // note that GDK generates triple click events which are not supported
1466 // by wxWidgets but still have to be passed to the app as otherwise
1467 // clicks would simply go missing
1468 switch (gdk_event
->type
)
1470 // we shouldn't get triple clicks at all for GTK2 because we
1471 // suppress them artificially using the code above but we still
1472 // should map them to something for GTK1 and not just ignore them
1473 // as this would lose clicks
1474 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1475 case GDK_BUTTON_PRESS
:
1476 event_type
= wxEVT_LEFT_DOWN
;
1479 case GDK_2BUTTON_PRESS
:
1480 event_type
= wxEVT_LEFT_DCLICK
;
1484 // just to silence gcc warnings
1488 else if (gdk_event
->button
== 2)
1490 switch (gdk_event
->type
)
1492 case GDK_3BUTTON_PRESS
:
1493 case GDK_BUTTON_PRESS
:
1494 event_type
= wxEVT_MIDDLE_DOWN
;
1497 case GDK_2BUTTON_PRESS
:
1498 event_type
= wxEVT_MIDDLE_DCLICK
;
1505 else if (gdk_event
->button
== 3)
1507 switch (gdk_event
->type
)
1509 case GDK_3BUTTON_PRESS
:
1510 case GDK_BUTTON_PRESS
:
1511 event_type
= wxEVT_RIGHT_DOWN
;
1514 case GDK_2BUTTON_PRESS
:
1515 event_type
= wxEVT_RIGHT_DCLICK
;
1522 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1524 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1526 event_type
= wxEVT_MOUSEWHEEL
;
1530 if ( event_type
== wxEVT_NULL
)
1532 // unknown mouse button or click type
1536 wxMouseEvent
event( event_type
);
1537 InitMouseEvent( win
, event
, gdk_event
);
1539 AdjustEventButtonState(event
);
1541 // wxListBox actually gets mouse events from the item, so we need to give it
1542 // a chance to correct this
1543 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1545 // find the correct window to send the event to: it may be a different one
1546 // from the one which got it at GTK+ level because some controls don't have
1547 // their own X window and thus cannot get any events.
1548 if ( !g_captureWindow
)
1549 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1551 if (win
->GetEventHandler()->ProcessEvent( event
))
1553 g_signal_stop_emission_by_name (widget
, "button_press_event");
1557 if (event_type
== wxEVT_RIGHT_DOWN
)
1559 // generate a "context menu" event: this is similar to right mouse
1560 // click under many GUIs except that it is generated differently
1561 // (right up under MSW, ctrl-click under Mac, right down here) and
1563 // (a) it's a command event and so is propagated to the parent
1564 // (b) under some ports it can be generated from kbd too
1565 // (c) it uses screen coords (because of (a))
1566 wxContextMenuEvent
evtCtx(
1569 win
->ClientToScreen(event
.GetPosition()));
1570 evtCtx
.SetEventObject(win
);
1571 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1578 //-----------------------------------------------------------------------------
1579 // "button_release_event"
1580 //-----------------------------------------------------------------------------
1583 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1584 GdkEventButton
*gdk_event
,
1590 wxapp_install_idle_handler();
1592 if (!win
->m_hasVMT
) return FALSE
;
1593 if (g_blockEventsOnDrag
) return FALSE
;
1594 if (g_blockEventsOnScroll
) return FALSE
;
1596 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1598 wxEventType event_type
= wxEVT_NULL
;
1600 switch (gdk_event
->button
)
1603 event_type
= wxEVT_LEFT_UP
;
1607 event_type
= wxEVT_MIDDLE_UP
;
1611 event_type
= wxEVT_RIGHT_UP
;
1615 // unknwon button, don't process
1619 wxMouseEvent
event( event_type
);
1620 InitMouseEvent( win
, event
, gdk_event
);
1622 AdjustEventButtonState(event
);
1624 // same wxListBox hack as above
1625 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1627 if ( !g_captureWindow
)
1628 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1630 if (win
->GetEventHandler()->ProcessEvent( event
))
1632 g_signal_stop_emission_by_name (widget
, "button_release_event");
1640 //-----------------------------------------------------------------------------
1641 // "motion_notify_event"
1642 //-----------------------------------------------------------------------------
1645 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1646 GdkEventMotion
*gdk_event
,
1652 wxapp_install_idle_handler();
1654 if (!win
->m_hasVMT
) return FALSE
;
1655 if (g_blockEventsOnDrag
) return FALSE
;
1656 if (g_blockEventsOnScroll
) return FALSE
;
1658 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1660 if (gdk_event
->is_hint
)
1664 GdkModifierType state
;
1665 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1671 printf( "OnMotion from " );
1672 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1673 printf( win->GetClassInfo()->GetClassName() );
1677 wxMouseEvent
event( wxEVT_MOTION
);
1678 InitMouseEvent(win
, event
, gdk_event
);
1680 if ( g_captureWindow
)
1682 // synthetize a mouse enter or leave event if needed
1683 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1684 // This seems to be necessary and actually been added to
1685 // GDK itself in version 2.0.X
1688 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1689 if ( hasMouse
!= g_captureWindowHasMouse
)
1691 // the mouse changed window
1692 g_captureWindowHasMouse
= hasMouse
;
1694 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1695 : wxEVT_LEAVE_WINDOW
);
1696 InitMouseEvent(win
, eventM
, gdk_event
);
1697 eventM
.SetEventObject(win
);
1698 win
->GetEventHandler()->ProcessEvent(eventM
);
1703 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1706 if (win
->GetEventHandler()->ProcessEvent( event
))
1708 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1716 //-----------------------------------------------------------------------------
1717 // "mouse_wheel_event"
1718 //-----------------------------------------------------------------------------
1721 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1722 GdkEventScroll
* gdk_event
,
1728 wxapp_install_idle_handler();
1730 wxEventType event_type
= wxEVT_NULL
;
1731 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1732 event_type
= wxEVT_MOUSEWHEEL
;
1733 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1734 event_type
= wxEVT_MOUSEWHEEL
;
1738 wxMouseEvent
event( event_type
);
1739 // Can't use InitMouse macro because scroll events don't have button
1740 event
.SetTimestamp( gdk_event
->time
);
1741 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1742 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1743 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1744 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1745 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1746 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1747 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1748 event
.m_linesPerAction
= 3;
1749 event
.m_wheelDelta
= 120;
1750 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1751 event
.m_wheelRotation
= 120;
1753 event
.m_wheelRotation
= -120;
1755 wxPoint pt
= win
->GetClientAreaOrigin();
1756 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1757 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1759 event
.SetEventObject( win
);
1760 event
.SetId( win
->GetId() );
1761 event
.SetTimestamp( gdk_event
->time
);
1763 if (win
->GetEventHandler()->ProcessEvent( event
))
1765 g_signal_stop_emission_by_name (widget
, "scroll_event");
1773 //-----------------------------------------------------------------------------
1775 //-----------------------------------------------------------------------------
1777 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1779 wxContextMenuEvent
event(
1783 event
.SetEventObject(win
);
1784 return win
->GetEventHandler()->ProcessEvent(event
);
1788 //-----------------------------------------------------------------------------
1790 //-----------------------------------------------------------------------------
1792 // send the wxChildFocusEvent and wxFocusEvent, common code of
1793 // gtk_window_focus_in_callback() and SetFocus()
1794 static bool DoSendFocusEvents(wxWindow
*win
)
1796 // Notify the parent keeping track of focus for the kbd navigation
1797 // purposes that we got it.
1798 wxChildFocusEvent
eventChildFocus(win
);
1799 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1801 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1802 eventFocus
.SetEventObject(win
);
1804 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1808 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1809 GdkEvent
*WXUNUSED(event
),
1815 wxapp_install_idle_handler();
1818 gtk_im_context_focus_in(win
->m_imData
->context
);
1821 g_focusWindow
= win
;
1823 wxLogTrace(TRACE_FOCUS
,
1824 _T("%s: focus in"), win
->GetName().c_str());
1828 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1832 // caret needs to be informed about focus change
1833 wxCaret
*caret
= win
->GetCaret();
1836 caret
->OnSetFocus();
1838 #endif // wxUSE_CARET
1840 // does the window itself think that it has the focus?
1841 if ( !win
->m_hasFocus
)
1843 // not yet, notify it
1844 win
->m_hasFocus
= true;
1846 if ( DoSendFocusEvents(win
) )
1848 g_signal_stop_emission_by_name (widget
, "focus_in_event");
1857 //-----------------------------------------------------------------------------
1858 // "focus_out_event"
1859 //-----------------------------------------------------------------------------
1862 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1867 wxapp_install_idle_handler();
1870 gtk_im_context_focus_out(win
->m_imData
->context
);
1872 wxLogTrace( TRACE_FOCUS
,
1873 _T("%s: focus out"), win
->GetName().c_str() );
1876 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1880 g_focusWindow
= (wxWindowGTK
*)NULL
;
1888 // caret needs to be informed about focus change
1889 wxCaret
*caret
= win
->GetCaret();
1892 caret
->OnKillFocus();
1894 #endif // wxUSE_CARET
1896 // don't send the window a kill focus event if it thinks that it doesn't
1897 // have focus already
1898 if ( win
->m_hasFocus
)
1900 win
->m_hasFocus
= false;
1902 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1903 event
.SetEventObject( win
);
1905 // even if we did process the event in wx code, still let GTK itself
1906 // process it too as otherwise bad things happen, especially in GTK2
1907 // where the text control simply aborts the program if it doesn't get
1908 // the matching focus out event
1909 (void)win
->GetEventHandler()->ProcessEvent( event
);
1916 //-----------------------------------------------------------------------------
1917 // "enter_notify_event"
1918 //-----------------------------------------------------------------------------
1922 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1923 GdkEventCrossing
*gdk_event
,
1929 wxapp_install_idle_handler();
1931 if (!win
->m_hasVMT
) return FALSE
;
1932 if (g_blockEventsOnDrag
) return FALSE
;
1934 // Event was emitted after a grab
1935 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1937 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1941 GdkModifierType state
= (GdkModifierType
)0;
1943 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1945 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1946 InitMouseEvent(win
, event
, gdk_event
);
1947 wxPoint pt
= win
->GetClientAreaOrigin();
1948 event
.m_x
= x
+ pt
.x
;
1949 event
.m_y
= y
+ pt
.y
;
1951 if (win
->GetEventHandler()->ProcessEvent( event
))
1953 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
1961 //-----------------------------------------------------------------------------
1962 // "leave_notify_event"
1963 //-----------------------------------------------------------------------------
1966 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1971 wxapp_install_idle_handler();
1973 if (!win
->m_hasVMT
) return FALSE
;
1974 if (g_blockEventsOnDrag
) return FALSE
;
1976 // Event was emitted after an ungrab
1977 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1979 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1981 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1982 event
.SetTimestamp( gdk_event
->time
);
1983 event
.SetEventObject( win
);
1987 GdkModifierType state
= (GdkModifierType
)0;
1989 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1991 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1992 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1993 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1994 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1995 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1996 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1997 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1999 wxPoint pt
= win
->GetClientAreaOrigin();
2000 event
.m_x
= x
+ pt
.x
;
2001 event
.m_y
= y
+ pt
.y
;
2003 if (win
->GetEventHandler()->ProcessEvent( event
))
2005 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2013 //-----------------------------------------------------------------------------
2014 // "value_changed" from m_vAdjust
2015 //-----------------------------------------------------------------------------
2018 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2025 wxapp_install_idle_handler();
2027 if (g_blockEventsOnDrag
) return;
2029 if (!win
->m_hasVMT
) return;
2031 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2032 if (fabs(diff
) < 0.2) return;
2034 win
->m_oldVerticalPos
= adjust
->value
;
2036 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2038 int value
= (int)(adjust
->value
+0.5);
2040 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2041 event
.SetEventObject( win
);
2042 win
->GetEventHandler()->ProcessEvent( event
);
2046 //-----------------------------------------------------------------------------
2047 // "value_changed" from m_hAdjust
2048 //-----------------------------------------------------------------------------
2051 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2058 wxapp_install_idle_handler();
2060 if (g_blockEventsOnDrag
) return;
2061 if (!win
->m_hasVMT
) return;
2063 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2064 if (fabs(diff
) < 0.2) return;
2066 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2068 win
->m_oldHorizontalPos
= adjust
->value
;
2070 int value
= (int)(adjust
->value
+0.5);
2072 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2073 event
.SetEventObject( win
);
2074 win
->GetEventHandler()->ProcessEvent( event
);
2078 //-----------------------------------------------------------------------------
2079 // "button_press_event" from scrollbar
2080 //-----------------------------------------------------------------------------
2083 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2084 GdkEventButton
*gdk_event
,
2090 wxapp_install_idle_handler();
2093 g_blockEventsOnScroll
= true;
2095 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2097 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2104 //-----------------------------------------------------------------------------
2105 // "button_release_event" from scrollbar
2106 //-----------------------------------------------------------------------------
2109 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2110 GdkEventButton
*WXUNUSED(gdk_event
),
2115 // don't test here as we can release the mouse while being over
2116 // a different window than the slider
2118 // if (gdk_event->window != widget->slider) return FALSE;
2120 g_blockEventsOnScroll
= false;
2122 if (win
->m_isScrolling
)
2124 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2128 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2129 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2131 value
= (int)(win
->m_hAdjust
->value
+0.5);
2134 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2136 value
= (int)(win
->m_vAdjust
->value
+0.5);
2140 wxScrollWinEvent
event( command
, value
, dir
);
2141 event
.SetEventObject( win
);
2142 win
->GetEventHandler()->ProcessEvent( event
);
2145 win
->m_isScrolling
= false;
2151 // ----------------------------------------------------------------------------
2152 // this wxWindowBase function is implemented here (in platform-specific file)
2153 // because it is static and so couldn't be made virtual
2154 // ----------------------------------------------------------------------------
2156 wxWindow
*wxWindowBase::DoFindFocus()
2158 // the cast is necessary when we compile in wxUniversal mode
2159 return (wxWindow
*)g_focusWindow
;
2162 //-----------------------------------------------------------------------------
2163 // "realize" from m_widget
2164 //-----------------------------------------------------------------------------
2166 /* We cannot set colours and fonts before the widget has
2167 been realized, so we do this directly after realization. */
2171 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2176 wxapp_install_idle_handler();
2180 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2181 gtk_im_context_set_client_window( win
->m_imData
->context
,
2182 pizza
->bin_window
);
2185 wxWindowCreateEvent
event( win
);
2186 event
.SetEventObject( win
);
2187 win
->GetEventHandler()->ProcessEvent( event
);
2193 //-----------------------------------------------------------------------------
2195 //-----------------------------------------------------------------------------
2199 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2200 GtkAllocation
*WXUNUSED(alloc
),
2204 wxapp_install_idle_handler();
2206 if (!win
->m_hasScrolling
) return;
2208 int client_width
= 0;
2209 int client_height
= 0;
2210 win
->GetClientSize( &client_width
, &client_height
);
2211 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2214 win
->m_oldClientWidth
= client_width
;
2215 win
->m_oldClientHeight
= client_height
;
2217 if (!win
->m_nativeSizeEvent
)
2219 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2220 event
.SetEventObject( win
);
2221 win
->GetEventHandler()->ProcessEvent( event
);
2228 #define WXUNUSED_UNLESS_XIM(param) param
2230 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2233 /* Resize XIM window */
2237 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2238 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2239 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2242 wxapp_install_idle_handler();
2248 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2252 gdk_window_get_size (widget
->window
, &width
, &height
);
2253 win
->m_icattr
->preedit_area
.width
= width
;
2254 win
->m_icattr
->preedit_area
.height
= height
;
2255 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2261 //-----------------------------------------------------------------------------
2262 // "realize" from m_wxwindow
2263 //-----------------------------------------------------------------------------
2265 /* Initialize XIM support */
2269 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2270 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2273 wxapp_install_idle_handler();
2276 if (win
->m_ic
) return FALSE
;
2277 if (!widget
) return FALSE
;
2278 if (!gdk_im_ready()) return FALSE
;
2280 win
->m_icattr
= gdk_ic_attr_new();
2281 if (!win
->m_icattr
) return FALSE
;
2285 GdkColormap
*colormap
;
2286 GdkICAttr
*attr
= win
->m_icattr
;
2287 unsigned attrmask
= GDK_IC_ALL_REQ
;
2289 GdkIMStyle supported_style
= (GdkIMStyle
)
2290 (GDK_IM_PREEDIT_NONE
|
2291 GDK_IM_PREEDIT_NOTHING
|
2292 GDK_IM_PREEDIT_POSITION
|
2293 GDK_IM_STATUS_NONE
|
2294 GDK_IM_STATUS_NOTHING
);
2296 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2297 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2299 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2300 attr
->client_window
= widget
->window
;
2302 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2303 gtk_widget_get_default_colormap ())
2305 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2306 attr
->preedit_colormap
= colormap
;
2309 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2310 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2311 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2312 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2314 switch (style
& GDK_IM_PREEDIT_MASK
)
2316 case GDK_IM_PREEDIT_POSITION
:
2317 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2319 g_warning ("over-the-spot style requires fontset");
2323 gdk_window_get_size (widget
->window
, &width
, &height
);
2325 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2326 attr
->spot_location
.x
= 0;
2327 attr
->spot_location
.y
= height
;
2328 attr
->preedit_area
.x
= 0;
2329 attr
->preedit_area
.y
= 0;
2330 attr
->preedit_area
.width
= width
;
2331 attr
->preedit_area
.height
= height
;
2332 attr
->preedit_fontset
= widget
->style
->font
;
2337 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2339 if (win
->m_ic
== NULL
)
2340 g_warning ("Can't create input context.");
2343 mask
= gdk_window_get_events (widget
->window
);
2344 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2345 gdk_window_set_events (widget
->window
, mask
);
2347 if (GTK_WIDGET_HAS_FOCUS(widget
))
2348 gdk_im_begin (win
->m_ic
, widget
->window
);
2356 //-----------------------------------------------------------------------------
2357 // InsertChild for wxWindowGTK.
2358 //-----------------------------------------------------------------------------
2360 /* Callback for wxWindowGTK. This very strange beast has to be used because
2361 * C++ has no virtual methods in a constructor. We have to emulate a
2362 * virtual function here as wxNotebook requires a different way to insert
2363 * a child in it. I had opted for creating a wxNotebookPage window class
2364 * which would have made this superfluous (such in the MDI window system),
2365 * but no-one was listening to me... */
2367 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2369 /* the window might have been scrolled already, do we
2370 have to adapt the position */
2371 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2372 child
->m_x
+= pizza
->xoffset
;
2373 child
->m_y
+= pizza
->yoffset
;
2375 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2376 GTK_WIDGET(child
->m_widget
),
2383 //-----------------------------------------------------------------------------
2385 //-----------------------------------------------------------------------------
2387 wxWindow
*wxGetActiveWindow()
2389 return wxWindow::FindFocus();
2393 wxMouseState
wxGetMouseState()
2399 GdkModifierType mask
;
2401 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2405 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2406 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2407 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2409 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2410 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2411 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2412 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2417 //-----------------------------------------------------------------------------
2419 //-----------------------------------------------------------------------------
2421 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2423 #ifdef __WXUNIVERSAL__
2424 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2426 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2427 #endif // __WXUNIVERSAL__/__WXGTK__
2429 void wxWindowGTK::Init()
2432 m_widget
= (GtkWidget
*) NULL
;
2433 m_wxwindow
= (GtkWidget
*) NULL
;
2434 m_focusWidget
= (GtkWidget
*) NULL
;
2444 m_needParent
= true;
2445 m_isBeingDeleted
= false;
2448 m_nativeSizeEvent
= false;
2450 m_hasScrolling
= false;
2451 m_isScrolling
= false;
2453 m_hAdjust
= (GtkAdjustment
*) NULL
;
2454 m_vAdjust
= (GtkAdjustment
*) NULL
;
2455 m_oldHorizontalPos
=
2456 m_oldVerticalPos
= 0.0;
2458 m_oldClientHeight
= 0;
2462 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2464 m_acceptsFocus
= false;
2467 m_clipPaintRegion
= false;
2469 m_needsStyleChange
= false;
2471 m_cursor
= *wxSTANDARD_CURSOR
;
2474 m_dirtyTabOrder
= false;
2477 wxWindowGTK::wxWindowGTK()
2482 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2487 const wxString
&name
)
2491 Create( parent
, id
, pos
, size
, style
, name
);
2494 bool wxWindowGTK::Create( wxWindow
*parent
,
2499 const wxString
&name
)
2501 if (!PreCreation( parent
, pos
, size
) ||
2502 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2504 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2508 m_insertCallback
= wxInsertChildInWindow
;
2510 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2511 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2513 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2515 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2516 scroll_class
->scrollbar_spacing
= 0;
2518 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2520 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2521 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2523 m_wxwindow
= gtk_pizza_new();
2525 #ifndef __WXUNIVERSAL__
2526 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2528 if (HasFlag(wxRAISED_BORDER
))
2530 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2532 else if (HasFlag(wxSUNKEN_BORDER
))
2534 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2536 else if (HasFlag(wxSIMPLE_BORDER
))
2538 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2542 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2544 #endif // __WXUNIVERSAL__
2546 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2548 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2549 m_acceptsFocus
= true;
2551 // I _really_ don't want scrollbars in the beginning
2552 m_vAdjust
->lower
= 0.0;
2553 m_vAdjust
->upper
= 1.0;
2554 m_vAdjust
->value
= 0.0;
2555 m_vAdjust
->step_increment
= 1.0;
2556 m_vAdjust
->page_increment
= 1.0;
2557 m_vAdjust
->page_size
= 5.0;
2558 g_signal_emit_by_name (m_vAdjust
, "changed");
2559 m_hAdjust
->lower
= 0.0;
2560 m_hAdjust
->upper
= 1.0;
2561 m_hAdjust
->value
= 0.0;
2562 m_hAdjust
->step_increment
= 1.0;
2563 m_hAdjust
->page_increment
= 1.0;
2564 m_hAdjust
->page_size
= 5.0;
2565 g_signal_emit_by_name (m_hAdjust
, "changed");
2567 // these handlers block mouse events to any window during scrolling such as
2568 // motion events and prevent GTK and wxWidgets from fighting over where the
2570 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2571 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2572 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2573 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2574 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2575 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2576 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2577 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2579 // these handlers get notified when screen updates are required either when
2580 // scrolling or when the window size (and therefore scrollbar configuration)
2583 g_signal_connect (m_hAdjust
, "value_changed",
2584 G_CALLBACK (gtk_window_hscroll_callback
), this);
2585 g_signal_connect (m_vAdjust
, "value_changed",
2586 G_CALLBACK (gtk_window_vscroll_callback
), this);
2588 gtk_widget_show( m_wxwindow
);
2591 m_parent
->DoAddChild( this );
2593 m_focusWidget
= m_wxwindow
;
2600 wxWindowGTK::~wxWindowGTK()
2604 if (g_focusWindow
== this)
2605 g_focusWindow
= NULL
;
2607 if ( g_delayedFocus
== this )
2608 g_delayedFocus
= NULL
;
2610 m_isBeingDeleted
= true;
2613 // destroy children before destroying this window itself
2616 // unhook focus handlers to prevent stray events being
2617 // propagated to this (soon to be) dead object
2618 if (m_focusWidget
!= NULL
)
2620 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2621 (gpointer
) gtk_window_focus_in_callback
,
2623 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2624 (gpointer
) gtk_window_focus_out_callback
,
2633 gdk_ic_destroy (m_ic
);
2635 gdk_ic_attr_destroy (m_icattr
);
2638 // delete before the widgets to avoid a crash on solaris
2643 gtk_widget_destroy( m_wxwindow
);
2644 m_wxwindow
= (GtkWidget
*) NULL
;
2649 gtk_widget_destroy( m_widget
);
2650 m_widget
= (GtkWidget
*) NULL
;
2654 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2656 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2658 // Use either the given size, or the default if -1 is given.
2659 // See wxWindowBase for these functions.
2660 m_width
= WidthDefault(size
.x
) ;
2661 m_height
= HeightDefault(size
.y
);
2669 void wxWindowGTK::PostCreation()
2671 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2677 // these get reported to wxWidgets -> wxPaintEvent
2679 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2681 g_signal_connect (m_wxwindow
, "expose_event",
2682 G_CALLBACK (gtk_window_expose_callback
), this);
2684 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2687 // Create input method handler
2688 m_imData
= new wxGtkIMData
;
2690 // Cannot handle drawing preedited text yet
2691 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2693 g_signal_connect (m_imData
->context
, "commit",
2694 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2696 // these are called when the "sunken" or "raised" borders are drawn
2697 g_signal_connect (m_widget
, "expose_event",
2698 G_CALLBACK (gtk_window_own_expose_callback
), this);
2703 if (!GTK_IS_WINDOW(m_widget
))
2705 if (m_focusWidget
== NULL
)
2706 m_focusWidget
= m_widget
;
2708 g_signal_connect (m_focusWidget
, "focus_in_event",
2709 G_CALLBACK (gtk_window_focus_in_callback
), this);
2710 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2711 G_CALLBACK (gtk_window_focus_out_callback
), this);
2714 // connect to the various key and mouse handlers
2716 GtkWidget
*connect_widget
= GetConnectWidget();
2718 ConnectWidget( connect_widget
);
2720 /* We cannot set colours, fonts and cursors before the widget has
2721 been realized, so we do this directly after realization */
2722 g_signal_connect (connect_widget
, "realize",
2723 G_CALLBACK (gtk_window_realized_callback
), this);
2727 // Catch native resize events
2728 g_signal_connect (m_wxwindow
, "size_allocate",
2729 G_CALLBACK (gtk_window_size_callback
), this);
2731 // Initialize XIM support
2732 g_signal_connect (m_wxwindow
, "realize",
2733 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2735 // And resize XIM window
2736 g_signal_connect (m_wxwindow
, "size_allocate",
2737 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2740 if (GTK_IS_COMBO(m_widget
))
2742 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2744 g_signal_connect (gcombo
->entry
, "size_request",
2745 G_CALLBACK (wxgtk_combo_size_request_callback
),
2750 // This is needed if we want to add our windows into native
2751 // GTK controls, such as the toolbar. With this callback, the
2752 // toolbar gets to know the correct size (the one set by the
2753 // programmer). Sadly, it misbehaves for wxComboBox.
2754 g_signal_connect (m_widget
, "size_request",
2755 G_CALLBACK (wxgtk_window_size_request_callback
),
2759 InheritAttributes();
2763 // unless the window was created initially hidden (i.e. Hide() had been
2764 // called before Create()), we should show it at GTK+ level as well
2766 gtk_widget_show( m_widget
);
2769 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2771 g_signal_connect (widget
, "key_press_event",
2772 G_CALLBACK (gtk_window_key_press_callback
), this);
2773 g_signal_connect (widget
, "key_release_event",
2774 G_CALLBACK (gtk_window_key_release_callback
), this);
2775 g_signal_connect (widget
, "button_press_event",
2776 G_CALLBACK (gtk_window_button_press_callback
), this);
2777 g_signal_connect (widget
, "button_release_event",
2778 G_CALLBACK (gtk_window_button_release_callback
), this);
2779 g_signal_connect (widget
, "motion_notify_event",
2780 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2781 g_signal_connect (widget
, "scroll_event",
2782 G_CALLBACK (gtk_window_wheel_callback
), this);
2783 g_signal_connect (widget
, "popup_menu",
2784 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2785 g_signal_connect (widget
, "enter_notify_event",
2786 G_CALLBACK (gtk_window_enter_callback
), this);
2787 g_signal_connect (widget
, "leave_notify_event",
2788 G_CALLBACK (gtk_window_leave_callback
), this);
2791 bool wxWindowGTK::Destroy()
2793 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2797 return wxWindowBase::Destroy();
2800 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2802 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2805 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2807 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2808 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2811 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2814 if (m_resizing
) return; /* I don't like recursions */
2817 int currentX
, currentY
;
2818 GetPosition(¤tX
, ¤tY
);
2819 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2821 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2823 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2825 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2827 /* don't set the size for children of wxNotebook, just take the values. */
2835 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2836 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2838 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2839 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2843 m_x
= x
+ pizza
->xoffset
;
2844 m_y
= y
+ pizza
->yoffset
;
2847 // calculate the best size if we should auto size the window
2848 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2849 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2851 const wxSize sizeBest
= GetBestSize();
2852 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2854 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2855 height
= sizeBest
.y
;
2863 int minWidth
= GetMinWidth(),
2864 minHeight
= GetMinHeight(),
2865 maxWidth
= GetMaxWidth(),
2866 maxHeight
= GetMaxHeight();
2868 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2869 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2870 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2871 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2873 int left_border
= 0;
2874 int right_border
= 0;
2876 int bottom_border
= 0;
2878 /* the default button has a border around it */
2879 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2881 GtkBorder
*default_border
= NULL
;
2882 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2885 left_border
+= default_border
->left
;
2886 right_border
+= default_border
->right
;
2887 top_border
+= default_border
->top
;
2888 bottom_border
+= default_border
->bottom
;
2889 g_free( default_border
);
2893 DoMoveWindow( m_x
-top_border
,
2895 m_width
+left_border
+right_border
,
2896 m_height
+top_border
+bottom_border
);
2901 /* Sometimes the client area changes size without the
2902 whole windows's size changing, but if the whole
2903 windows's size doesn't change, no wxSizeEvent will
2904 normally be sent. Here we add an extra test if
2905 the client test has been changed and this will
2907 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2911 wxPrintf( "OnSize sent from " );
2912 if (GetClassInfo() && GetClassInfo()->GetClassName())
2913 wxPrintf( GetClassInfo()->GetClassName() );
2914 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2917 if (!m_nativeSizeEvent
)
2919 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2920 event
.SetEventObject( this );
2921 GetEventHandler()->ProcessEvent( event
);
2927 void wxWindowGTK::OnInternalIdle()
2929 if ( m_dirtyTabOrder
)
2932 // Update style if the window was not yet realized
2933 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2934 if (m_needsStyleChange
)
2936 SetBackgroundStyle(GetBackgroundStyle());
2937 m_needsStyleChange
= false;
2940 // Update invalidated regions.
2943 wxCursor cursor
= m_cursor
;
2944 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2948 /* I now set the cursor anew in every OnInternalIdle call
2949 as setting the cursor in a parent window also effects the
2950 windows above so that checking for the current cursor is
2955 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2957 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2959 if (!g_globalCursor
.Ok())
2960 cursor
= *wxSTANDARD_CURSOR
;
2962 window
= m_widget
->window
;
2963 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2964 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2970 GdkWindow
*window
= m_widget
->window
;
2971 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2972 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2977 if (wxUpdateUIEvent::CanUpdate(this))
2978 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2981 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2983 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2985 if (width
) (*width
) = m_width
;
2986 if (height
) (*height
) = m_height
;
2989 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2991 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2995 SetSize( width
, height
);
3002 #ifndef __WXUNIVERSAL__
3003 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3005 /* when using GTK 1.2 we set the shadow border size to 2 */
3009 if (HasFlag(wxSIMPLE_BORDER
))
3011 /* when using GTK 1.2 we set the simple border size to 1 */
3015 #endif // __WXUNIVERSAL__
3019 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3021 GtkRequisition vscroll_req
;
3022 vscroll_req
.width
= 2;
3023 vscroll_req
.height
= 2;
3024 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3025 (scroll_window
->vscrollbar
, &vscroll_req
);
3027 GtkRequisition hscroll_req
;
3028 hscroll_req
.width
= 2;
3029 hscroll_req
.height
= 2;
3030 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3031 (scroll_window
->hscrollbar
, &hscroll_req
);
3033 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3035 if (scroll_window
->vscrollbar_visible
)
3037 dw
+= vscroll_req
.width
;
3038 dw
+= scroll_class
->scrollbar_spacing
;
3041 if (scroll_window
->hscrollbar_visible
)
3043 dh
+= hscroll_req
.height
;
3044 dh
+= scroll_class
->scrollbar_spacing
;
3048 SetSize( width
+dw
, height
+dh
);
3052 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3054 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3058 if (width
) (*width
) = m_width
;
3059 if (height
) (*height
) = m_height
;
3066 #ifndef __WXUNIVERSAL__
3067 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3069 /* when using GTK 1.2 we set the shadow border size to 2 */
3073 if (HasFlag(wxSIMPLE_BORDER
))
3075 /* when using GTK 1.2 we set the simple border size to 1 */
3079 #endif // __WXUNIVERSAL__
3083 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3085 GtkRequisition vscroll_req
;
3086 vscroll_req
.width
= 2;
3087 vscroll_req
.height
= 2;
3088 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3089 (scroll_window
->vscrollbar
, &vscroll_req
);
3091 GtkRequisition hscroll_req
;
3092 hscroll_req
.width
= 2;
3093 hscroll_req
.height
= 2;
3094 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3095 (scroll_window
->hscrollbar
, &hscroll_req
);
3097 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3099 if (scroll_window
->vscrollbar_visible
)
3101 dw
+= vscroll_req
.width
;
3102 dw
+= scroll_class
->scrollbar_spacing
;
3105 if (scroll_window
->hscrollbar_visible
)
3107 dh
+= hscroll_req
.height
;
3108 dh
+= scroll_class
->scrollbar_spacing
;
3112 if (width
) (*width
) = m_width
- dw
;
3113 if (height
) (*height
) = m_height
- dh
;
3117 printf( "GetClientSize, name %s ", GetName().c_str() );
3118 if (width) printf( " width = %d", (*width) );
3119 if (height) printf( " height = %d", (*height) );
3124 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3126 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3130 if (m_parent
&& m_parent
->m_wxwindow
)
3132 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3133 dx
= pizza
->xoffset
;
3134 dy
= pizza
->yoffset
;
3137 if (x
) (*x
) = m_x
- dx
;
3138 if (y
) (*y
) = m_y
- dy
;
3141 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3143 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3145 if (!m_widget
->window
) return;
3147 GdkWindow
*source
= (GdkWindow
*) NULL
;
3149 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3151 source
= m_widget
->window
;
3155 gdk_window_get_origin( source
, &org_x
, &org_y
);
3159 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3161 org_x
+= m_widget
->allocation
.x
;
3162 org_y
+= m_widget
->allocation
.y
;
3170 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3172 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3174 if (!m_widget
->window
) return;
3176 GdkWindow
*source
= (GdkWindow
*) NULL
;
3178 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3180 source
= m_widget
->window
;
3184 gdk_window_get_origin( source
, &org_x
, &org_y
);
3188 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3190 org_x
+= m_widget
->allocation
.x
;
3191 org_y
+= m_widget
->allocation
.y
;
3199 bool wxWindowGTK::Show( bool show
)
3201 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3203 if (!wxWindowBase::Show(show
))
3210 gtk_widget_show( m_widget
);
3212 gtk_widget_hide( m_widget
);
3214 wxShowEvent
eventShow(GetId(), show
);
3215 eventShow
.SetEventObject(this);
3217 GetEventHandler()->ProcessEvent(eventShow
);
3222 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3224 win
->OnParentEnable(enable
);
3226 // Recurse, so that children have the opportunity to Do The Right Thing
3227 // and reset colours that have been messed up by a parent's (really ancestor's)
3229 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3231 node
= node
->GetNext() )
3233 wxWindow
*child
= node
->GetData();
3234 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3235 wxWindowNotifyEnable(child
, enable
);
3239 bool wxWindowGTK::Enable( bool enable
)
3241 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3243 if (!wxWindowBase::Enable(enable
))
3249 gtk_widget_set_sensitive( m_widget
, enable
);
3251 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3253 wxWindowNotifyEnable(this, enable
);
3258 int wxWindowGTK::GetCharHeight() const
3260 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3262 wxFont font
= GetFont();
3263 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3265 PangoContext
*context
= NULL
;
3267 context
= gtk_widget_get_pango_context( m_widget
);
3272 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3273 PangoLayout
*layout
= pango_layout_new(context
);
3274 pango_layout_set_font_description(layout
, desc
);
3275 pango_layout_set_text(layout
, "H", 1);
3276 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3278 PangoRectangle rect
;
3279 pango_layout_line_get_extents(line
, NULL
, &rect
);
3281 g_object_unref( G_OBJECT( layout
) );
3283 return (int) PANGO_PIXELS(rect
.height
);
3286 int wxWindowGTK::GetCharWidth() const
3288 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3290 wxFont font
= GetFont();
3291 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3293 PangoContext
*context
= NULL
;
3295 context
= gtk_widget_get_pango_context( m_widget
);
3300 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3301 PangoLayout
*layout
= pango_layout_new(context
);
3302 pango_layout_set_font_description(layout
, desc
);
3303 pango_layout_set_text(layout
, "g", 1);
3304 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3306 PangoRectangle rect
;
3307 pango_layout_line_get_extents(line
, NULL
, &rect
);
3309 g_object_unref( G_OBJECT( layout
) );
3311 return (int) PANGO_PIXELS(rect
.width
);
3314 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3318 int *externalLeading
,
3319 const wxFont
*theFont
) const
3321 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3323 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3332 PangoContext
*context
= NULL
;
3334 context
= gtk_widget_get_pango_context( m_widget
);
3343 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3344 PangoLayout
*layout
= pango_layout_new(context
);
3345 pango_layout_set_font_description(layout
, desc
);
3348 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3349 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3351 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3352 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3353 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3357 PangoRectangle rect
;
3358 pango_layout_get_extents(layout
, NULL
, &rect
);
3360 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3361 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3364 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3365 int baseline
= pango_layout_iter_get_baseline(iter
);
3366 pango_layout_iter_free(iter
);
3367 *descent
= *y
- PANGO_PIXELS(baseline
);
3369 if (externalLeading
) (*externalLeading
) = 0; // ??
3371 g_object_unref( G_OBJECT( layout
) );
3374 void wxWindowGTK::SetFocus()
3376 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3379 // don't do anything if we already have focus
3385 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3387 gtk_widget_grab_focus (m_wxwindow
);
3392 if (GTK_IS_CONTAINER(m_widget
))
3394 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3397 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3400 if (!GTK_WIDGET_REALIZED(m_widget
))
3402 // we can't set the focus to the widget now so we remember that
3403 // it should be focused and will do it later, during the idle
3404 // time, as soon as we can
3405 wxLogTrace(TRACE_FOCUS
,
3406 _T("Delaying setting focus to %s(%s)"),
3407 GetClassInfo()->GetClassName(), GetLabel().c_str());
3409 g_delayedFocus
= this;
3413 wxLogTrace(TRACE_FOCUS
,
3414 _T("Setting focus to %s(%s)"),
3415 GetClassInfo()->GetClassName(), GetLabel().c_str());
3417 gtk_widget_grab_focus (m_widget
);
3422 wxLogTrace(TRACE_FOCUS
,
3423 _T("Can't set focus to %s(%s)"),
3424 GetClassInfo()->GetClassName(), GetLabel().c_str());
3429 bool wxWindowGTK::AcceptsFocus() const
3431 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3434 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3436 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3438 wxWindowGTK
*oldParent
= m_parent
,
3439 *newParent
= (wxWindowGTK
*)newParentBase
;
3441 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3443 if ( !wxWindowBase::Reparent(newParent
) )
3446 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3448 /* prevent GTK from deleting the widget arbitrarily */
3449 gtk_widget_ref( m_widget
);
3453 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3456 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3460 /* insert GTK representation */
3461 (*(newParent
->m_insertCallback
))(newParent
, this);
3464 /* reverse: prevent GTK from deleting the widget arbitrarily */
3465 gtk_widget_unref( m_widget
);
3470 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3472 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3474 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3476 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3481 /* insert GTK representation */
3482 (*m_insertCallback
)(this, child
);
3485 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3487 wxWindowBase::AddChild(child
);
3488 m_dirtyTabOrder
= true;
3490 wxapp_install_idle_handler();
3493 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3495 wxWindowBase::RemoveChild(child
);
3496 m_dirtyTabOrder
= true;
3498 wxapp_install_idle_handler();
3501 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3503 wxWindowBase::DoMoveInTabOrder(win
, move
);
3504 m_dirtyTabOrder
= true;
3506 wxapp_install_idle_handler();
3509 void wxWindowGTK::RealizeTabOrder()
3513 if (m_children
.size() > 0)
3515 GList
*chain
= NULL
;
3517 for (wxWindowList::const_iterator i
= m_children
.begin();
3518 i
!= m_children
.end(); ++i
)
3520 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3523 chain
= g_list_reverse(chain
);
3525 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3530 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3534 m_dirtyTabOrder
= false;
3537 void wxWindowGTK::Raise()
3539 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3541 if (m_wxwindow
&& m_wxwindow
->window
)
3543 gdk_window_raise( m_wxwindow
->window
);
3545 else if (m_widget
->window
)
3547 gdk_window_raise( m_widget
->window
);
3551 void wxWindowGTK::Lower()
3553 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3555 if (m_wxwindow
&& m_wxwindow
->window
)
3557 gdk_window_lower( m_wxwindow
->window
);
3559 else if (m_widget
->window
)
3561 gdk_window_lower( m_widget
->window
);
3565 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3567 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3569 if (cursor
== m_cursor
)
3573 wxapp_install_idle_handler();
3575 if (cursor
== wxNullCursor
)
3576 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3578 return wxWindowBase::SetCursor( cursor
);
3581 void wxWindowGTK::WarpPointer( int x
, int y
)
3583 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3585 // We provide this function ourselves as it is
3586 // missing in GDK (top of this file).
3588 GdkWindow
*window
= (GdkWindow
*) NULL
;
3590 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3592 window
= GetConnectWidget()->window
;
3595 gdk_window_warp_pointer( window
, x
, y
);
3599 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3603 if (!m_widget
->window
)
3608 GdkRectangle gdk_rect
,
3612 gdk_rect
.x
= rect
->x
;
3613 gdk_rect
.y
= rect
->y
;
3614 gdk_rect
.width
= rect
->width
;
3615 gdk_rect
.height
= rect
->height
;
3618 else // invalidate everything
3623 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3627 void wxWindowGTK::Update()
3631 // when we call Update() we really want to update the window immediately on
3632 // screen, even if it means flushing the entire queue and hence slowing down
3633 // everything -- but it should still be done, it's just that Update() should
3634 // be called very rarely
3638 void wxWindowGTK::GtkUpdate()
3640 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3641 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3643 // for consistency with other platforms (and also because it's convenient
3644 // to be able to update an entire TLW by calling Update() only once), we
3645 // should also update all our children here
3646 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3648 node
= node
->GetNext() )
3650 node
->GetData()->GtkUpdate();
3654 void wxWindowGTK::GtkSendPaintEvents()
3658 m_updateRegion
.Clear();
3662 // Clip to paint region in wxClientDC
3663 m_clipPaintRegion
= true;
3665 // widget to draw on
3666 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3668 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3670 // find ancestor from which to steal background
3671 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3673 parent
= (wxWindow
*)this;
3675 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3677 wxRegionIterator
upd( m_updateRegion
);
3681 rect
.x
= upd
.GetX();
3682 rect
.y
= upd
.GetY();
3683 rect
.width
= upd
.GetWidth();
3684 rect
.height
= upd
.GetHeight();
3686 gtk_paint_flat_box( parent
->m_widget
->style
,
3688 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3702 wxWindowDC
dc( (wxWindow
*)this );
3703 dc
.SetClippingRegion( m_updateRegion
);
3705 wxEraseEvent
erase_event( GetId(), &dc
);
3706 erase_event
.SetEventObject( this );
3708 GetEventHandler()->ProcessEvent(erase_event
);
3711 wxNcPaintEvent
nc_paint_event( GetId() );
3712 nc_paint_event
.SetEventObject( this );
3713 GetEventHandler()->ProcessEvent( nc_paint_event
);
3715 wxPaintEvent
paint_event( GetId() );
3716 paint_event
.SetEventObject( this );
3717 GetEventHandler()->ProcessEvent( paint_event
);
3719 m_clipPaintRegion
= false;
3721 m_updateRegion
.Clear();
3724 void wxWindowGTK::ClearBackground()
3726 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3730 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3732 wxWindowBase::DoSetToolTip(tip
);
3735 m_tooltip
->Apply( (wxWindow
*)this );
3738 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3740 wxString
tmp( tip
);
3741 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3743 #endif // wxUSE_TOOLTIPS
3745 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3747 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3749 if (!wxWindowBase::SetBackgroundColour(colour
))
3754 // We need the pixel value e.g. for background clearing.
3755 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3758 // apply style change (forceStyle=true so that new style is applied
3759 // even if the bg colour changed from valid to wxNullColour)
3760 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3761 ApplyWidgetStyle(true);
3766 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3768 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3770 if (!wxWindowBase::SetForegroundColour(colour
))
3777 // We need the pixel value e.g. for background clearing.
3778 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3781 // apply style change (forceStyle=true so that new style is applied
3782 // even if the bg colour changed from valid to wxNullColour):
3783 ApplyWidgetStyle(true);
3788 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3790 return gtk_widget_get_pango_context( m_widget
);
3793 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3795 // do we need to apply any changes at all?
3798 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3803 GtkRcStyle
*style
= gtk_rc_style_new();
3808 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3811 if ( m_foregroundColour
.Ok() )
3813 GdkColor
*fg
= m_foregroundColour
.GetColor();
3815 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3816 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3818 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3819 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3821 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3822 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3825 if ( m_backgroundColour
.Ok() )
3827 GdkColor
*bg
= m_backgroundColour
.GetColor();
3829 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3830 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3831 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3832 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3834 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3835 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3836 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3837 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3839 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3840 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3841 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3842 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3844 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3845 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3846 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3847 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3853 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3855 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3858 DoApplyWidgetStyle(style
);
3859 gtk_rc_style_unref(style
);
3862 // Style change may affect GTK+'s size calculation:
3863 InvalidateBestSize();
3866 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3869 gtk_widget_modify_style(m_wxwindow
, style
);
3871 gtk_widget_modify_style(m_widget
, style
);
3874 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3876 wxWindowBase::SetBackgroundStyle(style
);
3878 if (style
== wxBG_STYLE_CUSTOM
)
3880 GdkWindow
*window
= (GdkWindow
*) NULL
;
3882 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3884 window
= GetConnectWidget()->window
;
3888 // Make sure GDK/X11 doesn't refresh the window
3890 gdk_window_set_back_pixmap( window
, None
, False
);
3892 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3895 m_needsStyleChange
= false;
3898 // Do in OnIdle, because the window is not yet available
3899 m_needsStyleChange
= true;
3901 // Don't apply widget style, or we get a grey background
3905 // apply style change (forceStyle=true so that new style is applied
3906 // even if the bg colour changed from valid to wxNullColour):
3907 ApplyWidgetStyle(true);
3912 #if wxUSE_DRAG_AND_DROP
3914 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3916 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3918 GtkWidget
*dnd_widget
= GetConnectWidget();
3920 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3922 if (m_dropTarget
) delete m_dropTarget
;
3923 m_dropTarget
= dropTarget
;
3925 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3928 #endif // wxUSE_DRAG_AND_DROP
3930 GtkWidget
* wxWindowGTK::GetConnectWidget()
3932 GtkWidget
*connect_widget
= m_widget
;
3933 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3935 return connect_widget
;
3938 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3941 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3943 return (window
== m_widget
->window
);
3946 bool wxWindowGTK::SetFont( const wxFont
&font
)
3948 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3950 if (!wxWindowBase::SetFont(font
))
3953 // apply style change (forceStyle=true so that new style is applied
3954 // even if the font changed from valid to wxNullFont):
3955 ApplyWidgetStyle(true);
3960 void wxWindowGTK::DoCaptureMouse()
3962 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3964 GdkWindow
*window
= (GdkWindow
*) NULL
;
3966 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3968 window
= GetConnectWidget()->window
;
3970 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3972 wxCursor
* cursor
= & m_cursor
;
3974 cursor
= wxSTANDARD_CURSOR
;
3976 gdk_pointer_grab( window
, FALSE
,
3978 (GDK_BUTTON_PRESS_MASK
|
3979 GDK_BUTTON_RELEASE_MASK
|
3980 GDK_POINTER_MOTION_HINT_MASK
|
3981 GDK_POINTER_MOTION_MASK
),
3983 cursor
->GetCursor(),
3984 (guint32
)GDK_CURRENT_TIME
);
3985 g_captureWindow
= this;
3986 g_captureWindowHasMouse
= true;
3989 void wxWindowGTK::DoReleaseMouse()
3991 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3993 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3995 g_captureWindow
= (wxWindowGTK
*) NULL
;
3997 GdkWindow
*window
= (GdkWindow
*) NULL
;
3999 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4001 window
= GetConnectWidget()->window
;
4006 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4010 wxWindow
*wxWindowBase::GetCapture()
4012 return (wxWindow
*)g_captureWindow
;
4015 bool wxWindowGTK::IsRetained() const
4020 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4021 int range
, bool refresh
)
4023 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4025 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4027 m_hasScrolling
= true;
4029 if (orient
== wxHORIZONTAL
)
4031 float fpos
= (float)pos
;
4032 float frange
= (float)range
;
4033 float fthumb
= (float)thumbVisible
;
4034 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4035 if (fpos
< 0.0) fpos
= 0.0;
4037 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4038 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4040 SetScrollPos( orient
, pos
, refresh
);
4044 m_oldHorizontalPos
= fpos
;
4046 m_hAdjust
->lower
= 0.0;
4047 m_hAdjust
->upper
= frange
;
4048 m_hAdjust
->value
= fpos
;
4049 m_hAdjust
->step_increment
= 1.0;
4050 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4051 m_hAdjust
->page_size
= fthumb
;
4055 float fpos
= (float)pos
;
4056 float frange
= (float)range
;
4057 float fthumb
= (float)thumbVisible
;
4058 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4059 if (fpos
< 0.0) fpos
= 0.0;
4061 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4062 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4064 SetScrollPos( orient
, pos
, refresh
);
4068 m_oldVerticalPos
= fpos
;
4070 m_vAdjust
->lower
= 0.0;
4071 m_vAdjust
->upper
= frange
;
4072 m_vAdjust
->value
= fpos
;
4073 m_vAdjust
->step_increment
= 1.0;
4074 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4075 m_vAdjust
->page_size
= fthumb
;
4078 if (orient
== wxHORIZONTAL
)
4079 g_signal_emit_by_name (m_hAdjust
, "changed");
4081 g_signal_emit_by_name (m_vAdjust
, "changed");
4084 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4086 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4087 gpointer fn
= orient
== wxHORIZONTAL
4088 ? (gpointer
) gtk_window_hscroll_callback
4089 : (gpointer
) gtk_window_vscroll_callback
;
4091 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4092 g_signal_emit_by_name (adj
, "value_changed");
4093 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4096 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4098 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4099 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4101 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4103 float fpos
= (float)pos
;
4104 if (fpos
> adj
->upper
- adj
->page_size
)
4105 fpos
= adj
->upper
- adj
->page_size
;
4108 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4110 if (fabs(fpos
-adj
->value
) < 0.2)
4114 if ( m_wxwindow
->window
)
4119 int wxWindowGTK::GetScrollThumb( int orient
) const
4121 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4123 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4125 if (orient
== wxHORIZONTAL
)
4126 return (int)(m_hAdjust
->page_size
+0.5);
4128 return (int)(m_vAdjust
->page_size
+0.5);
4131 int wxWindowGTK::GetScrollPos( int orient
) const
4133 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4135 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4137 if (orient
== wxHORIZONTAL
)
4138 return (int)(m_hAdjust
->value
+0.5);
4140 return (int)(m_vAdjust
->value
+0.5);
4143 int wxWindowGTK::GetScrollRange( int orient
) const
4145 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4147 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4149 if (orient
== wxHORIZONTAL
)
4150 return (int)(m_hAdjust
->upper
+0.5);
4152 return (int)(m_vAdjust
->upper
+0.5);
4155 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4157 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4159 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4161 // No scrolling requested.
4162 if ((dx
== 0) && (dy
== 0)) return;
4164 m_clipPaintRegion
= true;
4166 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4168 m_clipPaintRegion
= false;
4171 void wxWindowGTK::SetWindowStyleFlag( long style
)
4173 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4174 wxWindowBase::SetWindowStyleFlag(style
);
4177 // Find the wxWindow at the current mouse position, also returning the mouse
4179 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4181 pt
= wxGetMousePosition();
4182 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4186 // Get the current mouse position.
4187 wxPoint
wxGetMousePosition()
4189 /* This crashes when used within wxHelpContext,
4190 so we have to use the X-specific implementation below.
4192 GdkModifierType *mask;
4193 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4195 return wxPoint(x, y);
4199 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4201 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4202 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4203 Window rootReturn
, childReturn
;
4204 int rootX
, rootY
, winX
, winY
;
4205 unsigned int maskReturn
;
4207 XQueryPointer (display
,
4211 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4212 return wxPoint(rootX
, rootY
);
4216 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4217 void wxAddGrab(wxWindow
* window
)
4219 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4222 void wxRemoveGrab(wxWindow
* window
)
4224 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4227 // ----------------------------------------------------------------------------
4229 // ----------------------------------------------------------------------------
4231 class wxWinModule
: public wxModule
4238 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4241 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4243 bool wxWinModule::OnInit()
4245 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4246 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4251 void wxWinModule::OnExit()
4254 gdk_gc_unref( g_eraseGC
);