1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
18 #include "wx/dcclient.h"
21 #include "wx/layout.h"
23 #include "wx/dialog.h"
24 #include "wx/msgdlg.h"
25 #include "wx/module.h"
26 #include "wx/combobox.h"
28 #if wxUSE_DRAG_AND_DROP
33 #include "wx/tooltip.h"
41 #include "wx/textctrl.h"
45 #include "wx/statusbr.h"
47 #include "wx/settings.h"
49 #include "wx/fontutil.h"
52 #include "wx/thread.h"
58 #include "wx/gtk/private.h"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
68 #include <pango/pangox.h>
74 extern GtkContainerClass
*pizza_parent_class
;
76 //-----------------------------------------------------------------------------
77 // documentation on internals
78 //-----------------------------------------------------------------------------
81 I have been asked several times about writing some documentation about
82 the GTK port of wxWidgets, especially its internal structures. Obviously,
83 you cannot understand wxGTK without knowing a little about the GTK, but
84 some more information about what the wxWindow, which is the base class
85 for all other window classes, does seems required as well.
89 What does wxWindow do? It contains the common interface for the following
90 jobs of its descendants:
92 1) Define the rudimentary behaviour common to all window classes, such as
93 resizing, intercepting user input (so as to make it possible to use these
94 events for special purposes in a derived class), window names etc.
96 2) Provide the possibility to contain and manage children, if the derived
97 class is allowed to contain children, which holds true for those window
98 classes which do not display a native GTK widget. To name them, these
99 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
100 work classes are a special case and are handled a bit differently from
101 the rest. The same holds true for the wxNotebook class.
103 3) Provide the possibility to draw into a client area of a window. This,
104 too, only holds true for classes that do not display a native GTK widget
107 4) Provide the entire mechanism for scrolling widgets. This actual inter-
108 face for this is usually in wxScrolledWindow, but the GTK implementation
111 5) A multitude of helper or extra methods for special purposes, such as
112 Drag'n'Drop, managing validators etc.
114 6) Display a border (sunken, raised, simple or none).
116 Normally one might expect, that one wxWidgets window would always correspond
117 to one GTK widget. Under GTK, there is no such allround widget that has all
118 the functionality. Moreover, the GTK defines a client area as a different
119 widget from the actual widget you are handling. Last but not least some
120 special classes (e.g. wxFrame) handle different categories of widgets and
121 still have the possibility to draw something in the client area.
122 It was therefore required to write a special purpose GTK widget, that would
123 represent a client area in the sense of wxWidgets capable to do the jobs
124 2), 3) and 4). I have written this class and it resides in win_gtk.c of
127 All windows must have a widget, with which they interact with other under-
128 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
129 the wxWindow class has a member variable called m_widget which holds a
130 pointer to this widget. When the window class represents a GTK native widget,
131 this is (in most cases) the only GTK widget the class manages. E.g. the
132 wxStaticText class handles only a GtkLabel widget a pointer to which you
133 can find in m_widget (defined in wxWindow)
135 When the class has a client area for drawing into and for containing children
136 it has to handle the client area widget (of the type GtkPizza, defined in
137 win_gtk.c), but there could be any number of widgets, handled by a class
138 The common rule for all windows is only, that the widget that interacts with
139 the rest of GTK must be referenced in m_widget and all other widgets must be
140 children of this widget on the GTK level. The top-most widget, which also
141 represents the client area, must be in the m_wxwindow field and must be of
144 As I said, the window classes that display a GTK native widget only have
145 one widget, so in the case of e.g. the wxButton class m_widget holds a
146 pointer to a GtkButton widget. But windows with client areas (for drawing
147 and children) have a m_widget field that is a pointer to a GtkScrolled-
148 Window and a m_wxwindow field that is pointer to a GtkPizza and this
149 one is (in the GTK sense) a child of the GtkScrolledWindow.
151 If the m_wxwindow field is set, then all input to this widget is inter-
152 cepted and sent to the wxWidgets class. If not, all input to the widget
153 that gets pointed to by m_widget gets intercepted and sent to the class.
157 The design of scrolling in wxWidgets is markedly different from that offered
158 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
159 clicking on a scrollbar belonging to scrolled window will inevitably move
160 the window. In wxWidgets, the scrollbar will only emit an event, send this
161 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
162 which actually moves the window and its subchildren. Note that GtkPizza
163 memorizes how much it has been scrolled but that wxWidgets forgets this
164 so that the two coordinates systems have to be kept in synch. This is done
165 in various places using the pizza->xoffset and pizza->yoffset values.
169 Singularily the most broken code in GTK is the code that is supposed to
170 inform subwindows (child windows) about new positions. Very often, duplicate
171 events are sent without changes in size or position, equally often no
172 events are sent at all (All this is due to a bug in the GtkContainer code
173 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
174 GTK's own system and it simply waits for size events for toplevel windows
175 and then iterates down the respective size events to all window. This has
176 the disadvantage that windows might get size events before the GTK widget
177 actually has the reported size. This doesn't normally pose any problem, but
178 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
179 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
180 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
181 window that is used for OpenGL output really has that size (as reported by
186 If someone at some point of time feels the immense desire to have a look at,
187 change or attempt to optimise the Refresh() logic, this person will need an
188 intimate understanding of what "draw" and "expose" events are and what
189 they are used for, in particular when used in connection with GTK's
190 own windowless widgets. Beware.
194 Cursors, too, have been a constant source of pleasure. The main difficulty
195 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
196 for the parent. To prevent this from doing too much harm, I use idle time
197 to set the cursor over and over again, starting from the toplevel windows
198 and ending with the youngest generation (speaking of parent and child windows).
199 Also don't forget that cursors (like much else) are connected to GdkWindows,
200 not GtkWidgets and that the "window" field of a GtkWidget might very well
201 point to the GdkWindow of the parent widget (-> "window-less widget") and
202 that the two obviously have very different meanings.
206 //-----------------------------------------------------------------------------
208 //-----------------------------------------------------------------------------
210 extern wxList wxPendingDelete
;
211 extern bool g_blockEventsOnDrag
;
212 extern bool g_blockEventsOnScroll
;
213 extern wxCursor g_globalCursor
;
215 static GdkGC
*g_eraseGC
= NULL
;
217 // mouse capture state: the window which has it and if the mouse is currently
219 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
220 static bool g_captureWindowHasMouse
= false;
222 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
224 // the last window which had the focus - this is normally never NULL (except
225 // if we never had focus at all) as even when g_focusWindow is NULL it still
226 // keeps its previous value
227 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
229 // If a window get the focus set but has not been realized
230 // yet, defer setting the focus to idle time.
231 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
233 extern bool g_mainThreadLocked
;
235 //-----------------------------------------------------------------------------
237 //-----------------------------------------------------------------------------
242 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
244 # define DEBUG_MAIN_THREAD
247 #define DEBUG_MAIN_THREAD
250 // the trace mask used for the focus debugging messages
251 #define TRACE_FOCUS _T("focus")
253 //-----------------------------------------------------------------------------
254 // missing gdk functions
255 //-----------------------------------------------------------------------------
258 gdk_window_warp_pointer (GdkWindow
*window
,
263 window
= GDK_ROOT_PARENT();
265 if (!GDK_WINDOW_DESTROYED(window
))
267 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
268 None
, /* not source window -> move from anywhere */
269 GDK_WINDOW_XID(window
), /* dest window */
270 0, 0, 0, 0, /* not source window -> move from anywhere */
275 //-----------------------------------------------------------------------------
277 //-----------------------------------------------------------------------------
279 extern void wxapp_install_idle_handler();
280 extern bool g_isIdle
;
282 //-----------------------------------------------------------------------------
283 // local code (see below)
284 //-----------------------------------------------------------------------------
286 // returns the child of win which currently has focus or NULL if not found
288 // Note: can't be static, needed by textctrl.cpp.
289 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
291 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
293 return (wxWindow
*)NULL
;
295 if ( winFocus
== win
)
296 return (wxWindow
*)win
;
298 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
300 node
= node
->GetNext() )
302 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
307 return (wxWindow
*)NULL
;
310 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
312 // wxUniversal widgets draw the borders and scrollbars themselves
313 #ifndef __WXUNIVERSAL__
320 if (win
->m_hasScrolling
)
322 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
324 GtkRequisition vscroll_req
;
325 vscroll_req
.width
= 2;
326 vscroll_req
.height
= 2;
327 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
328 (scroll_window
->vscrollbar
, &vscroll_req
);
330 GtkRequisition hscroll_req
;
331 hscroll_req
.width
= 2;
332 hscroll_req
.height
= 2;
333 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
334 (scroll_window
->hscrollbar
, &hscroll_req
);
336 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
338 if (scroll_window
->vscrollbar_visible
)
340 dw
+= vscroll_req
.width
;
341 dw
+= scroll_class
->scrollbar_spacing
;
344 if (scroll_window
->hscrollbar_visible
)
346 dh
+= hscroll_req
.height
;
347 dh
+= scroll_class
->scrollbar_spacing
;
353 if (GTK_WIDGET_NO_WINDOW (widget
))
355 dx
+= widget
->allocation
.x
;
356 dy
+= widget
->allocation
.y
;
359 if (win
->HasFlag(wxRAISED_BORDER
))
361 gtk_paint_shadow (widget
->style
,
365 NULL
, NULL
, NULL
, // FIXME: No clipping?
367 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
371 if (win
->HasFlag(wxSUNKEN_BORDER
))
373 gtk_paint_shadow (widget
->style
,
377 NULL
, NULL
, NULL
, // FIXME: No clipping?
379 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
383 if (win
->HasFlag(wxSIMPLE_BORDER
))
386 gc
= gdk_gc_new( widget
->window
);
387 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
388 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
390 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
394 #endif // __WXUNIVERSAL__
397 //-----------------------------------------------------------------------------
398 // "expose_event" of m_widget
399 //-----------------------------------------------------------------------------
402 static gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
404 if (gdk_event
->count
> 0) return FALSE
;
406 draw_frame( widget
, win
);
408 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
414 //-----------------------------------------------------------------------------
415 // "size_request" of m_widget
416 //-----------------------------------------------------------------------------
418 // make it extern because wxStaticText needs to disconnect this one
420 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
421 GtkRequisition
*requisition
,
425 win
->GetSize( &w
, &h
);
431 requisition
->height
= h
;
432 requisition
->width
= w
;
438 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
439 GtkRequisition
*requisition
,
442 // This callback is actually hooked into the text entry
443 // of the combo box, not the GtkHBox.
446 win
->GetSize( &w
, &h
);
452 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
454 GtkRequisition entry_req
;
456 entry_req
.height
= 2;
457 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
458 (gcombo
->button
, &entry_req
);
460 requisition
->width
= w
- entry_req
.width
;
461 requisition
->height
= entry_req
.height
;
465 //-----------------------------------------------------------------------------
466 // "expose_event" of m_wxwindow
467 //-----------------------------------------------------------------------------
470 static int gtk_window_expose_callback( GtkWidget
*widget
,
471 GdkEventExpose
*gdk_event
,
477 wxapp_install_idle_handler();
479 // This callback gets called in drawing-idle time under
480 // GTK 2.0, so we don't need to defer anything to idle
483 GtkPizza
*pizza
= GTK_PIZZA( widget
);
484 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
489 wxPrintf( wxT("OnExpose from ") );
490 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
491 wxPrintf( win
->GetClassInfo()->GetClassName() );
492 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
493 (int)gdk_event
->area
.y
,
494 (int)gdk_event
->area
.width
,
495 (int)gdk_event
->area
.height
);
500 win
->m_wxwindow
->style
,
504 (GdkRectangle
*) NULL
,
506 (char *)"button", // const_cast
511 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
513 win
->GtkSendPaintEvents();
516 // Let parent window draw window-less widgets
517 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
523 //-----------------------------------------------------------------------------
524 // "key_press_event" from any window
525 //-----------------------------------------------------------------------------
527 // set WXTRACE to this to see the key event codes on the console
528 #define TRACE_KEYS _T("keyevent")
530 // translates an X key symbol to WXK_XXX value
532 // if isChar is true it means that the value returned will be used for EVT_CHAR
533 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
534 // for example, while if it is false it means that the value is going to be
535 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
537 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
543 // Shift, Control and Alt don't generate the CHAR events at all
546 key_code
= isChar
? 0 : WXK_SHIFT
;
550 key_code
= isChar
? 0 : WXK_CONTROL
;
558 key_code
= isChar
? 0 : WXK_ALT
;
561 // neither do the toggle modifies
562 case GDK_Scroll_Lock
:
563 key_code
= isChar
? 0 : WXK_SCROLL
;
567 key_code
= isChar
? 0 : WXK_CAPITAL
;
571 key_code
= isChar
? 0 : WXK_NUMLOCK
;
575 // various other special keys
588 case GDK_ISO_Left_Tab
:
595 key_code
= WXK_RETURN
;
599 key_code
= WXK_CLEAR
;
603 key_code
= WXK_PAUSE
;
607 key_code
= WXK_SELECT
;
611 key_code
= WXK_PRINT
;
615 key_code
= WXK_EXECUTE
;
619 key_code
= WXK_ESCAPE
;
622 // cursor and other extended keyboard keys
624 key_code
= WXK_DELETE
;
640 key_code
= WXK_RIGHT
;
647 case GDK_Prior
: // == GDK_Page_Up
648 key_code
= WXK_PRIOR
;
651 case GDK_Next
: // == GDK_Page_Down
664 key_code
= WXK_INSERT
;
679 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
683 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
687 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
691 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
695 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
699 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
703 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
707 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
711 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
715 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
719 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
723 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
727 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
730 case GDK_KP_Prior
: // == GDK_KP_Page_Up
731 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
734 case GDK_KP_Next
: // == GDK_KP_Page_Down
735 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
739 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
743 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
747 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
751 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
755 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
758 case GDK_KP_Multiply
:
759 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
763 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
766 case GDK_KP_Separator
:
767 // FIXME: what is this?
768 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
771 case GDK_KP_Subtract
:
772 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
776 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
780 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
797 key_code
= WXK_F1
+ keysym
- GDK_F1
;
807 static inline bool wxIsAsciiKeysym(KeySym ks
)
812 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
814 GdkEventKey
*gdk_event
)
818 GdkModifierType state
;
819 if (gdk_event
->window
)
820 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
822 event
.SetTimestamp( gdk_event
->time
);
823 event
.SetId(win
->GetId());
824 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
825 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
826 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
827 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
828 event
.m_scanCode
= gdk_event
->keyval
;
829 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
830 event
.m_rawFlags
= 0;
832 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
834 wxGetMousePosition( &x
, &y
);
835 win
->ScreenToClient( &x
, &y
);
838 event
.SetEventObject( win
);
843 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
845 GdkEventKey
*gdk_event
)
847 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
848 // but only event->keyval which is quite useless to us, so remember
849 // the last character from GDK_KEY_PRESS and reuse it as last resort
851 // NB: should be MT-safe as we're always called from the main thread only
856 } s_lastKeyPress
= { 0, 0 };
858 KeySym keysym
= gdk_event
->keyval
;
860 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
861 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
865 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
869 // do we have the translation or is it a plain ASCII character?
870 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
872 // we should use keysym if it is ASCII as X does some translations
873 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
874 // which we don't want here (but which we do use for OnChar())
875 if ( !wxIsAsciiKeysym(keysym
) )
877 keysym
= (KeySym
)gdk_event
->string
[0];
880 // we want to always get the same key code when the same key is
881 // pressed regardless of the state of the modifiers, i.e. on a
882 // standard US keyboard pressing '5' or '%' ('5' key with
883 // Shift) should result in the same key code in OnKeyDown():
884 // '5' (although OnChar() will get either '5' or '%').
886 // to do it we first translate keysym to keycode (== scan code)
887 // and then back but always using the lower register
888 Display
*dpy
= (Display
*)wxGetDisplay();
889 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
891 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
893 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
895 // use the normalized, i.e. lower register, keysym if we've
897 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
899 // as explained above, we want to have lower register key codes
900 // normally but for the letter keys we want to have the upper ones
902 // NB: don't use XConvertCase() here, we want to do it for letters
904 key_code
= toupper(key_code
);
906 else // non ASCII key, what to do?
908 // by default, ignore it
911 // but if we have cached information from the last KEY_PRESS
912 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
915 if ( keysym
== s_lastKeyPress
.keysym
)
917 key_code
= s_lastKeyPress
.keycode
;
922 if ( gdk_event
->type
== GDK_KEY_PRESS
)
924 // remember it to be reused for KEY_UP event later
925 s_lastKeyPress
.keysym
= keysym
;
926 s_lastKeyPress
.keycode
= key_code
;
930 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
932 // sending unknown key events doesn't really make sense
936 // now fill all the other fields
937 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
939 event
.m_keyCode
= key_code
;
947 GtkIMContext
*context
;
948 GdkEventKey
*lastKeyEvent
;
952 context
= gtk_im_multicontext_new();
957 g_object_unref(context
);
962 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
963 GdkEventKey
*gdk_event
,
969 wxapp_install_idle_handler();
973 if (g_blockEventsOnDrag
)
977 wxKeyEvent
event( wxEVT_KEY_DOWN
);
979 bool return_after_IM
= false;
981 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
983 // Emit KEY_DOWN event
984 ret
= win
->GetEventHandler()->ProcessEvent( event
);
988 // Return after IM processing as we cannot do
989 // anything with it anyhow.
990 return_after_IM
= true;
993 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
994 // When we get a key_press event here, it could be originate
995 // from the current widget or its child widgets. However, only the widget
996 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
997 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
998 // originated from its child widgets and shouldn't be passed to IM context.
999 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1000 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1001 // widgets has both IM context and input focus, the event should be filtered
1002 // by gtk_im_context_filter_keypress().
1003 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1004 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1006 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1007 // docs, if IM filter returns true, no further processing should be done.
1008 // we should send the key_down event anyway.
1009 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1010 win
->m_imData
->lastKeyEvent
= NULL
;
1011 if (intercepted_by_IM
)
1013 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1018 if (return_after_IM
)
1024 wxWindowGTK
*ancestor
= win
;
1027 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1030 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1031 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1034 if (ancestor
->IsTopLevel())
1036 ancestor
= ancestor
->GetParent();
1039 #endif // wxUSE_ACCEL
1041 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1042 // will only be sent if it is not in an accelerator table.
1046 KeySym keysym
= gdk_event
->keyval
;
1047 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1048 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1051 if ( wxIsAsciiKeysym(keysym
) )
1054 key_code
= (unsigned char)keysym
;
1056 // gdk_event->string is actually deprecated
1057 else if ( gdk_event
->length
== 1 )
1059 key_code
= (unsigned char)gdk_event
->string
[0];
1065 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1067 event
.m_keyCode
= key_code
;
1069 // Implement OnCharHook by checking ancestor top level windows
1070 wxWindow
*parent
= win
;
1071 while (parent
&& !parent
->IsTopLevel())
1072 parent
= parent
->GetParent();
1075 event
.SetEventType( wxEVT_CHAR_HOOK
);
1076 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1081 event
.SetEventType(wxEVT_CHAR
);
1082 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1091 // win is a control: tab can be propagated up
1093 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1094 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1095 // have this style, yet choose not to process this particular TAB in which
1096 // case TAB must still work as a navigational character
1097 // JS: enabling again to make consistent with other platforms
1098 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1099 // navigation behaviour)
1101 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1103 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1105 wxNavigationKeyEvent new_event
;
1106 new_event
.SetEventObject( win
->GetParent() );
1107 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1108 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1109 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1110 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1111 new_event
.SetCurrentFocus( win
);
1112 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1115 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1117 (gdk_event
->keyval
== GDK_Escape
) )
1119 // however only do it if we have a Cancel button in the dialog,
1120 // otherwise the user code may get confused by the events from a
1121 // non-existing button and, worse, a wxButton might get button event
1122 // from another button which is not really expected
1123 wxWindow
*winForCancel
= win
,
1125 while ( winForCancel
)
1127 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1130 // found a cancel button
1134 if ( winForCancel
->IsTopLevel() )
1136 // no need to look further
1140 // maybe our parent has a cancel button?
1141 winForCancel
= winForCancel
->GetParent();
1146 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1147 eventClick
.SetEventObject(btnCancel
);
1148 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1154 g_signal_stop_emission_by_name (widget
, "key_press_event");
1163 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1167 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1169 // take modifiers, cursor position, timestamp etc. from the last
1170 // key_press_event that was fed into Input Method:
1171 if (window
->m_imData
->lastKeyEvent
)
1173 wxFillOtherKeyEventFields(event
,
1174 window
, window
->m_imData
->lastKeyEvent
);
1178 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1180 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1181 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1182 #endif // wxUSE_UNICODE
1183 if( !(const wxChar
*)data
)
1188 // Implement OnCharHook by checking ancestor top level windows
1189 wxWindow
*parent
= window
;
1190 while (parent
&& !parent
->IsTopLevel())
1191 parent
= parent
->GetParent();
1193 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1196 event
.m_uniChar
= *pstr
;
1197 // Backward compatible for ISO-8859-1
1198 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1199 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1201 event
.m_keyCode
= *pstr
;
1202 #endif // wxUSE_UNICODE
1205 event
.SetEventType( wxEVT_CHAR_HOOK
);
1206 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1211 event
.SetEventType(wxEVT_CHAR
);
1212 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1219 //-----------------------------------------------------------------------------
1220 // "key_release_event" from any window
1221 //-----------------------------------------------------------------------------
1224 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1225 GdkEventKey
*gdk_event
,
1231 wxapp_install_idle_handler();
1236 if (g_blockEventsOnDrag
)
1239 wxKeyEvent
event( wxEVT_KEY_UP
);
1240 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1242 // unknown key pressed, ignore (the event would be useless anyhow)
1246 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1249 g_signal_stop_emission_by_name (widget
, "key_release_event");
1254 // ============================================================================
1256 // ============================================================================
1258 // ----------------------------------------------------------------------------
1259 // mouse event processing helpers
1260 // ----------------------------------------------------------------------------
1262 // init wxMouseEvent with the info from GdkEventXXX struct
1263 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1264 wxMouseEvent
& event
,
1267 event
.SetTimestamp( gdk_event
->time
);
1268 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1269 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1270 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1271 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1272 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1273 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1274 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1275 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1277 event
.m_linesPerAction
= 3;
1278 event
.m_wheelDelta
= 120;
1279 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1280 event
.m_wheelRotation
= 120;
1281 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1282 event
.m_wheelRotation
= -120;
1285 wxPoint pt
= win
->GetClientAreaOrigin();
1286 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1287 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1289 event
.SetEventObject( win
);
1290 event
.SetId( win
->GetId() );
1291 event
.SetTimestamp( gdk_event
->time
);
1294 static void AdjustEventButtonState(wxMouseEvent
& event
)
1296 // GDK reports the old state of the button for a button press event, but
1297 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1298 // for a LEFT_DOWN event, not FALSE, so we will invert
1299 // left/right/middleDown for the corresponding click events
1301 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1302 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1303 (event
.GetEventType() == wxEVT_LEFT_UP
))
1305 event
.m_leftDown
= !event
.m_leftDown
;
1309 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1310 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1311 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1313 event
.m_middleDown
= !event
.m_middleDown
;
1317 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1318 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1319 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1321 event
.m_rightDown
= !event
.m_rightDown
;
1326 // find the window to send the mouse event too
1328 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1333 if (win
->m_wxwindow
)
1335 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1336 xx
+= pizza
->xoffset
;
1337 yy
+= pizza
->yoffset
;
1340 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1343 wxWindowGTK
*child
= node
->GetData();
1345 node
= node
->GetNext();
1346 if (!child
->IsShown())
1349 if (child
->IsTransparentForMouse())
1351 // wxStaticBox is transparent in the box itself
1352 int xx1
= child
->m_x
;
1353 int yy1
= child
->m_y
;
1354 int xx2
= child
->m_x
+ child
->m_width
;
1355 int yy2
= child
->m_y
+ child
->m_height
;
1358 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1360 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1362 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1364 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1375 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1376 (child
->m_x
<= xx
) &&
1377 (child
->m_y
<= yy
) &&
1378 (child
->m_x
+child
->m_width
>= xx
) &&
1379 (child
->m_y
+child
->m_height
>= yy
))
1392 //-----------------------------------------------------------------------------
1393 // "button_press_event"
1394 //-----------------------------------------------------------------------------
1397 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1398 GdkEventButton
*gdk_event
,
1404 wxapp_install_idle_handler();
1407 wxPrintf( wxT("1) OnButtonPress from ") );
1408 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1409 wxPrintf( win->GetClassInfo()->GetClassName() );
1410 wxPrintf( wxT(".\n") );
1412 if (!win
->m_hasVMT
) return FALSE
;
1413 if (g_blockEventsOnDrag
) return TRUE
;
1414 if (g_blockEventsOnScroll
) return TRUE
;
1416 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1418 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1420 gtk_widget_grab_focus( win
->m_wxwindow
);
1422 wxPrintf( wxT("GrabFocus from ") );
1423 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1424 wxPrintf( win->GetClassInfo()->GetClassName() );
1425 wxPrintf( wxT(".\n") );
1429 // GDK sends surplus button down events
1430 // before a double click event. We
1431 // need to filter these out.
1432 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1434 GdkEvent
*peek_event
= gdk_event_peek();
1437 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1438 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1440 gdk_event_free( peek_event
);
1445 gdk_event_free( peek_event
);
1450 wxEventType event_type
= wxEVT_NULL
;
1452 // GdkDisplay is a GTK+ 2.2.0 thing
1453 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1454 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1455 !gtk_check_version(2,2,0) &&
1456 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1458 // Reset GDK internal timestamp variables in order to disable GDK
1459 // triple click events. GDK will then next time believe no button has
1460 // been clicked just before, and send a normal button click event.
1461 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1462 display
->button_click_time
[1] = 0;
1463 display
->button_click_time
[0] = 0;
1467 if (gdk_event
->button
== 1)
1469 // note that GDK generates triple click events which are not supported
1470 // by wxWidgets but still have to be passed to the app as otherwise
1471 // clicks would simply go missing
1472 switch (gdk_event
->type
)
1474 // we shouldn't get triple clicks at all for GTK2 because we
1475 // suppress them artificially using the code above but we still
1476 // should map them to something for GTK1 and not just ignore them
1477 // as this would lose clicks
1478 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1479 case GDK_BUTTON_PRESS
:
1480 event_type
= wxEVT_LEFT_DOWN
;
1483 case GDK_2BUTTON_PRESS
:
1484 event_type
= wxEVT_LEFT_DCLICK
;
1488 // just to silence gcc warnings
1492 else if (gdk_event
->button
== 2)
1494 switch (gdk_event
->type
)
1496 case GDK_3BUTTON_PRESS
:
1497 case GDK_BUTTON_PRESS
:
1498 event_type
= wxEVT_MIDDLE_DOWN
;
1501 case GDK_2BUTTON_PRESS
:
1502 event_type
= wxEVT_MIDDLE_DCLICK
;
1509 else if (gdk_event
->button
== 3)
1511 switch (gdk_event
->type
)
1513 case GDK_3BUTTON_PRESS
:
1514 case GDK_BUTTON_PRESS
:
1515 event_type
= wxEVT_RIGHT_DOWN
;
1518 case GDK_2BUTTON_PRESS
:
1519 event_type
= wxEVT_RIGHT_DCLICK
;
1526 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1528 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1530 event_type
= wxEVT_MOUSEWHEEL
;
1534 if ( event_type
== wxEVT_NULL
)
1536 // unknown mouse button or click type
1540 wxMouseEvent
event( event_type
);
1541 InitMouseEvent( win
, event
, gdk_event
);
1543 AdjustEventButtonState(event
);
1545 // wxListBox actually gets mouse events from the item, so we need to give it
1546 // a chance to correct this
1547 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1549 // find the correct window to send the event to: it may be a different one
1550 // from the one which got it at GTK+ level because some controls don't have
1551 // their own X window and thus cannot get any events.
1552 if ( !g_captureWindow
)
1553 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1555 if (win
->GetEventHandler()->ProcessEvent( event
))
1557 g_signal_stop_emission_by_name (widget
, "button_press_event");
1561 if (event_type
== wxEVT_RIGHT_DOWN
)
1563 // generate a "context menu" event: this is similar to right mouse
1564 // click under many GUIs except that it is generated differently
1565 // (right up under MSW, ctrl-click under Mac, right down here) and
1567 // (a) it's a command event and so is propagated to the parent
1568 // (b) under some ports it can be generated from kbd too
1569 // (c) it uses screen coords (because of (a))
1570 wxContextMenuEvent
evtCtx(
1573 win
->ClientToScreen(event
.GetPosition()));
1574 evtCtx
.SetEventObject(win
);
1575 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1582 //-----------------------------------------------------------------------------
1583 // "button_release_event"
1584 //-----------------------------------------------------------------------------
1587 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1588 GdkEventButton
*gdk_event
,
1594 wxapp_install_idle_handler();
1596 if (!win
->m_hasVMT
) return FALSE
;
1597 if (g_blockEventsOnDrag
) return FALSE
;
1598 if (g_blockEventsOnScroll
) return FALSE
;
1600 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1602 wxEventType event_type
= wxEVT_NULL
;
1604 switch (gdk_event
->button
)
1607 event_type
= wxEVT_LEFT_UP
;
1611 event_type
= wxEVT_MIDDLE_UP
;
1615 event_type
= wxEVT_RIGHT_UP
;
1619 // unknwon button, don't process
1623 wxMouseEvent
event( event_type
);
1624 InitMouseEvent( win
, event
, gdk_event
);
1626 AdjustEventButtonState(event
);
1628 // same wxListBox hack as above
1629 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1631 if ( !g_captureWindow
)
1632 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1634 if (win
->GetEventHandler()->ProcessEvent( event
))
1636 g_signal_stop_emission_by_name (widget
, "button_release_event");
1644 //-----------------------------------------------------------------------------
1645 // "motion_notify_event"
1646 //-----------------------------------------------------------------------------
1649 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1650 GdkEventMotion
*gdk_event
,
1656 wxapp_install_idle_handler();
1658 if (!win
->m_hasVMT
) return FALSE
;
1659 if (g_blockEventsOnDrag
) return FALSE
;
1660 if (g_blockEventsOnScroll
) return FALSE
;
1662 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1664 if (gdk_event
->is_hint
)
1668 GdkModifierType state
;
1669 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1675 printf( "OnMotion from " );
1676 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1677 printf( win->GetClassInfo()->GetClassName() );
1681 wxMouseEvent
event( wxEVT_MOTION
);
1682 InitMouseEvent(win
, event
, gdk_event
);
1684 if ( g_captureWindow
)
1686 // synthetize a mouse enter or leave event if needed
1687 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1688 // This seems to be necessary and actually been added to
1689 // GDK itself in version 2.0.X
1692 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1693 if ( hasMouse
!= g_captureWindowHasMouse
)
1695 // the mouse changed window
1696 g_captureWindowHasMouse
= hasMouse
;
1698 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1699 : wxEVT_LEAVE_WINDOW
);
1700 InitMouseEvent(win
, eventM
, gdk_event
);
1701 eventM
.SetEventObject(win
);
1702 win
->GetEventHandler()->ProcessEvent(eventM
);
1707 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1710 if (win
->GetEventHandler()->ProcessEvent( event
))
1712 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1720 //-----------------------------------------------------------------------------
1721 // "mouse_wheel_event"
1722 //-----------------------------------------------------------------------------
1725 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1726 GdkEventScroll
* gdk_event
,
1732 wxapp_install_idle_handler();
1734 wxEventType event_type
= wxEVT_NULL
;
1735 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1736 event_type
= wxEVT_MOUSEWHEEL
;
1737 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1738 event_type
= wxEVT_MOUSEWHEEL
;
1742 wxMouseEvent
event( event_type
);
1743 // Can't use InitMouse macro because scroll events don't have button
1744 event
.SetTimestamp( gdk_event
->time
);
1745 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1746 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1747 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1748 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1749 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1750 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1751 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1752 event
.m_linesPerAction
= 3;
1753 event
.m_wheelDelta
= 120;
1754 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1755 event
.m_wheelRotation
= 120;
1757 event
.m_wheelRotation
= -120;
1759 wxPoint pt
= win
->GetClientAreaOrigin();
1760 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1761 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1763 event
.SetEventObject( win
);
1764 event
.SetId( win
->GetId() );
1765 event
.SetTimestamp( gdk_event
->time
);
1767 if (win
->GetEventHandler()->ProcessEvent( event
))
1769 g_signal_stop_emission_by_name (widget
, "scroll_event");
1777 //-----------------------------------------------------------------------------
1779 //-----------------------------------------------------------------------------
1781 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1783 wxContextMenuEvent
event(
1787 event
.SetEventObject(win
);
1788 return win
->GetEventHandler()->ProcessEvent(event
);
1792 //-----------------------------------------------------------------------------
1794 //-----------------------------------------------------------------------------
1796 // send the wxChildFocusEvent and wxFocusEvent, common code of
1797 // gtk_window_focus_in_callback() and SetFocus()
1798 static bool DoSendFocusEvents(wxWindow
*win
)
1800 // Notify the parent keeping track of focus for the kbd navigation
1801 // purposes that we got it.
1802 wxChildFocusEvent
eventChildFocus(win
);
1803 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1805 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1806 eventFocus
.SetEventObject(win
);
1808 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1812 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1813 GdkEvent
*WXUNUSED(event
),
1819 wxapp_install_idle_handler();
1822 gtk_im_context_focus_in(win
->m_imData
->context
);
1825 g_focusWindow
= win
;
1827 wxLogTrace(TRACE_FOCUS
,
1828 _T("%s: focus in"), win
->GetName().c_str());
1832 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1836 // caret needs to be informed about focus change
1837 wxCaret
*caret
= win
->GetCaret();
1840 caret
->OnSetFocus();
1842 #endif // wxUSE_CARET
1844 // does the window itself think that it has the focus?
1845 if ( !win
->m_hasFocus
)
1847 // not yet, notify it
1848 win
->m_hasFocus
= true;
1850 if ( DoSendFocusEvents(win
) )
1852 g_signal_stop_emission_by_name (widget
, "focus_in_event");
1861 //-----------------------------------------------------------------------------
1862 // "focus_out_event"
1863 //-----------------------------------------------------------------------------
1866 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1871 wxapp_install_idle_handler();
1874 gtk_im_context_focus_out(win
->m_imData
->context
);
1876 wxLogTrace( TRACE_FOCUS
,
1877 _T("%s: focus out"), win
->GetName().c_str() );
1880 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1884 g_focusWindow
= (wxWindowGTK
*)NULL
;
1892 // caret needs to be informed about focus change
1893 wxCaret
*caret
= win
->GetCaret();
1896 caret
->OnKillFocus();
1898 #endif // wxUSE_CARET
1900 // don't send the window a kill focus event if it thinks that it doesn't
1901 // have focus already
1902 if ( win
->m_hasFocus
)
1904 win
->m_hasFocus
= false;
1906 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1907 event
.SetEventObject( win
);
1909 // even if we did process the event in wx code, still let GTK itself
1910 // process it too as otherwise bad things happen, especially in GTK2
1911 // where the text control simply aborts the program if it doesn't get
1912 // the matching focus out event
1913 (void)win
->GetEventHandler()->ProcessEvent( event
);
1920 //-----------------------------------------------------------------------------
1921 // "enter_notify_event"
1922 //-----------------------------------------------------------------------------
1926 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1927 GdkEventCrossing
*gdk_event
,
1933 wxapp_install_idle_handler();
1935 if (!win
->m_hasVMT
) return FALSE
;
1936 if (g_blockEventsOnDrag
) return FALSE
;
1938 // Event was emitted after a grab
1939 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1941 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1945 GdkModifierType state
= (GdkModifierType
)0;
1947 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1949 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1950 InitMouseEvent(win
, event
, gdk_event
);
1951 wxPoint pt
= win
->GetClientAreaOrigin();
1952 event
.m_x
= x
+ pt
.x
;
1953 event
.m_y
= y
+ pt
.y
;
1955 if (win
->GetEventHandler()->ProcessEvent( event
))
1957 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
1965 //-----------------------------------------------------------------------------
1966 // "leave_notify_event"
1967 //-----------------------------------------------------------------------------
1970 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1975 wxapp_install_idle_handler();
1977 if (!win
->m_hasVMT
) return FALSE
;
1978 if (g_blockEventsOnDrag
) return FALSE
;
1980 // Event was emitted after an ungrab
1981 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1983 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1985 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1986 event
.SetTimestamp( gdk_event
->time
);
1987 event
.SetEventObject( win
);
1991 GdkModifierType state
= (GdkModifierType
)0;
1993 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1995 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1996 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1997 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1998 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1999 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2000 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2001 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2003 wxPoint pt
= win
->GetClientAreaOrigin();
2004 event
.m_x
= x
+ pt
.x
;
2005 event
.m_y
= y
+ pt
.y
;
2007 if (win
->GetEventHandler()->ProcessEvent( event
))
2009 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2017 //-----------------------------------------------------------------------------
2018 // "value_changed" from m_vAdjust
2019 //-----------------------------------------------------------------------------
2022 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2028 wxapp_install_idle_handler();
2030 if (g_blockEventsOnDrag
) return;
2032 if (!win
->m_hasVMT
) return;
2034 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2035 if (fabs(diff
) < 0.2) return;
2037 win
->m_oldVerticalPos
= adjust
->value
;
2039 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2041 int value
= (int)(adjust
->value
+0.5);
2043 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2044 event
.SetEventObject( win
);
2045 win
->GetEventHandler()->ProcessEvent( event
);
2049 //-----------------------------------------------------------------------------
2050 // "value_changed" from m_hAdjust
2051 //-----------------------------------------------------------------------------
2054 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2060 wxapp_install_idle_handler();
2062 if (g_blockEventsOnDrag
) return;
2063 if (!win
->m_hasVMT
) return;
2065 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2066 if (fabs(diff
) < 0.2) return;
2068 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2070 win
->m_oldHorizontalPos
= adjust
->value
;
2072 int value
= (int)(adjust
->value
+0.5);
2074 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2075 event
.SetEventObject( win
);
2076 win
->GetEventHandler()->ProcessEvent( event
);
2080 //-----------------------------------------------------------------------------
2081 // "button_press_event" from scrollbar
2082 //-----------------------------------------------------------------------------
2085 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2086 GdkEventButton
*gdk_event
,
2092 wxapp_install_idle_handler();
2095 g_blockEventsOnScroll
= true;
2097 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2099 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2106 //-----------------------------------------------------------------------------
2107 // "button_release_event" from scrollbar
2108 //-----------------------------------------------------------------------------
2111 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2112 GdkEventButton
*WXUNUSED(gdk_event
),
2117 // don't test here as we can release the mouse while being over
2118 // a different window than the slider
2120 // if (gdk_event->window != widget->slider) return FALSE;
2122 g_blockEventsOnScroll
= false;
2124 if (win
->m_isScrolling
)
2126 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2130 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2131 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2133 value
= (int)(win
->m_hAdjust
->value
+0.5);
2136 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2138 value
= (int)(win
->m_vAdjust
->value
+0.5);
2142 wxScrollWinEvent
event( command
, value
, dir
);
2143 event
.SetEventObject( win
);
2144 win
->GetEventHandler()->ProcessEvent( event
);
2147 win
->m_isScrolling
= false;
2153 // ----------------------------------------------------------------------------
2154 // this wxWindowBase function is implemented here (in platform-specific file)
2155 // because it is static and so couldn't be made virtual
2156 // ----------------------------------------------------------------------------
2158 wxWindow
*wxWindowBase::DoFindFocus()
2160 // the cast is necessary when we compile in wxUniversal mode
2161 return (wxWindow
*)g_focusWindow
;
2164 //-----------------------------------------------------------------------------
2165 // "realize" from m_widget
2166 //-----------------------------------------------------------------------------
2168 /* We cannot set colours and fonts before the widget has
2169 been realized, so we do this directly after realization. */
2173 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2178 wxapp_install_idle_handler();
2182 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2183 gtk_im_context_set_client_window( win
->m_imData
->context
,
2184 pizza
->bin_window
);
2187 wxWindowCreateEvent
event( win
);
2188 event
.SetEventObject( win
);
2189 win
->GetEventHandler()->ProcessEvent( event
);
2195 //-----------------------------------------------------------------------------
2197 //-----------------------------------------------------------------------------
2201 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2202 GtkAllocation
*WXUNUSED(alloc
),
2206 wxapp_install_idle_handler();
2208 if (!win
->m_hasScrolling
) return;
2210 int client_width
= 0;
2211 int client_height
= 0;
2212 win
->GetClientSize( &client_width
, &client_height
);
2213 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2216 win
->m_oldClientWidth
= client_width
;
2217 win
->m_oldClientHeight
= client_height
;
2219 if (!win
->m_nativeSizeEvent
)
2221 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2222 event
.SetEventObject( win
);
2223 win
->GetEventHandler()->ProcessEvent( event
);
2230 #define WXUNUSED_UNLESS_XIM(param) param
2232 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2235 /* Resize XIM window */
2239 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2240 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2241 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2244 wxapp_install_idle_handler();
2250 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2254 gdk_window_get_size (widget
->window
, &width
, &height
);
2255 win
->m_icattr
->preedit_area
.width
= width
;
2256 win
->m_icattr
->preedit_area
.height
= height
;
2257 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2263 //-----------------------------------------------------------------------------
2264 // "realize" from m_wxwindow
2265 //-----------------------------------------------------------------------------
2267 /* Initialize XIM support */
2271 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2272 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2275 wxapp_install_idle_handler();
2278 if (win
->m_ic
) return FALSE
;
2279 if (!widget
) return FALSE
;
2280 if (!gdk_im_ready()) return FALSE
;
2282 win
->m_icattr
= gdk_ic_attr_new();
2283 if (!win
->m_icattr
) return FALSE
;
2287 GdkColormap
*colormap
;
2288 GdkICAttr
*attr
= win
->m_icattr
;
2289 unsigned attrmask
= GDK_IC_ALL_REQ
;
2291 GdkIMStyle supported_style
= (GdkIMStyle
)
2292 (GDK_IM_PREEDIT_NONE
|
2293 GDK_IM_PREEDIT_NOTHING
|
2294 GDK_IM_PREEDIT_POSITION
|
2295 GDK_IM_STATUS_NONE
|
2296 GDK_IM_STATUS_NOTHING
);
2298 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2299 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2301 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2302 attr
->client_window
= widget
->window
;
2304 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2305 gtk_widget_get_default_colormap ())
2307 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2308 attr
->preedit_colormap
= colormap
;
2311 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2312 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2313 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2314 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2316 switch (style
& GDK_IM_PREEDIT_MASK
)
2318 case GDK_IM_PREEDIT_POSITION
:
2319 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2321 g_warning ("over-the-spot style requires fontset");
2325 gdk_window_get_size (widget
->window
, &width
, &height
);
2327 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2328 attr
->spot_location
.x
= 0;
2329 attr
->spot_location
.y
= height
;
2330 attr
->preedit_area
.x
= 0;
2331 attr
->preedit_area
.y
= 0;
2332 attr
->preedit_area
.width
= width
;
2333 attr
->preedit_area
.height
= height
;
2334 attr
->preedit_fontset
= widget
->style
->font
;
2339 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2341 if (win
->m_ic
== NULL
)
2342 g_warning ("Can't create input context.");
2345 mask
= gdk_window_get_events (widget
->window
);
2346 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2347 gdk_window_set_events (widget
->window
, mask
);
2349 if (GTK_WIDGET_HAS_FOCUS(widget
))
2350 gdk_im_begin (win
->m_ic
, widget
->window
);
2358 //-----------------------------------------------------------------------------
2359 // InsertChild for wxWindowGTK.
2360 //-----------------------------------------------------------------------------
2362 /* Callback for wxWindowGTK. This very strange beast has to be used because
2363 * C++ has no virtual methods in a constructor. We have to emulate a
2364 * virtual function here as wxNotebook requires a different way to insert
2365 * a child in it. I had opted for creating a wxNotebookPage window class
2366 * which would have made this superfluous (such in the MDI window system),
2367 * but no-one was listening to me... */
2369 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2371 /* the window might have been scrolled already, do we
2372 have to adapt the position */
2373 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2374 child
->m_x
+= pizza
->xoffset
;
2375 child
->m_y
+= pizza
->yoffset
;
2377 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2378 GTK_WIDGET(child
->m_widget
),
2385 //-----------------------------------------------------------------------------
2387 //-----------------------------------------------------------------------------
2389 wxWindow
*wxGetActiveWindow()
2391 return wxWindow::FindFocus();
2395 wxMouseState
wxGetMouseState()
2401 GdkModifierType mask
;
2403 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2407 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2408 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2409 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2411 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2412 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2413 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2414 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2419 //-----------------------------------------------------------------------------
2421 //-----------------------------------------------------------------------------
2423 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2425 #ifdef __WXUNIVERSAL__
2426 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2428 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2429 #endif // __WXUNIVERSAL__/__WXGTK__
2431 void wxWindowGTK::Init()
2434 m_widget
= (GtkWidget
*) NULL
;
2435 m_wxwindow
= (GtkWidget
*) NULL
;
2436 m_focusWidget
= (GtkWidget
*) NULL
;
2446 m_needParent
= true;
2447 m_isBeingDeleted
= false;
2450 m_nativeSizeEvent
= false;
2452 m_hasScrolling
= false;
2453 m_isScrolling
= false;
2455 m_hAdjust
= (GtkAdjustment
*) NULL
;
2456 m_vAdjust
= (GtkAdjustment
*) NULL
;
2457 m_oldHorizontalPos
=
2458 m_oldVerticalPos
= 0.0;
2460 m_oldClientHeight
= 0;
2464 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2466 m_acceptsFocus
= false;
2469 m_clipPaintRegion
= false;
2471 m_needsStyleChange
= false;
2473 m_cursor
= *wxSTANDARD_CURSOR
;
2476 m_dirtyTabOrder
= false;
2479 wxWindowGTK::wxWindowGTK()
2484 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2489 const wxString
&name
)
2493 Create( parent
, id
, pos
, size
, style
, name
);
2496 bool wxWindowGTK::Create( wxWindow
*parent
,
2501 const wxString
&name
)
2503 if (!PreCreation( parent
, pos
, size
) ||
2504 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2506 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2510 m_insertCallback
= wxInsertChildInWindow
;
2512 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2513 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2515 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2517 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2518 scroll_class
->scrollbar_spacing
= 0;
2520 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2522 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2523 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2525 m_wxwindow
= gtk_pizza_new();
2527 #ifndef __WXUNIVERSAL__
2528 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2530 if (HasFlag(wxRAISED_BORDER
))
2532 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2534 else if (HasFlag(wxSUNKEN_BORDER
))
2536 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2538 else if (HasFlag(wxSIMPLE_BORDER
))
2540 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2544 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2546 #endif // __WXUNIVERSAL__
2548 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2550 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2551 m_acceptsFocus
= true;
2553 // I _really_ don't want scrollbars in the beginning
2554 m_vAdjust
->lower
= 0.0;
2555 m_vAdjust
->upper
= 1.0;
2556 m_vAdjust
->value
= 0.0;
2557 m_vAdjust
->step_increment
= 1.0;
2558 m_vAdjust
->page_increment
= 1.0;
2559 m_vAdjust
->page_size
= 5.0;
2560 g_signal_emit_by_name (m_vAdjust
, "changed");
2561 m_hAdjust
->lower
= 0.0;
2562 m_hAdjust
->upper
= 1.0;
2563 m_hAdjust
->value
= 0.0;
2564 m_hAdjust
->step_increment
= 1.0;
2565 m_hAdjust
->page_increment
= 1.0;
2566 m_hAdjust
->page_size
= 5.0;
2567 g_signal_emit_by_name (m_hAdjust
, "changed");
2569 // these handlers block mouse events to any window during scrolling such as
2570 // motion events and prevent GTK and wxWidgets from fighting over where the
2572 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2573 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2574 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2575 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2576 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2577 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2578 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2579 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2581 // these handlers get notified when screen updates are required either when
2582 // scrolling or when the window size (and therefore scrollbar configuration)
2585 g_signal_connect (m_hAdjust
, "value_changed",
2586 G_CALLBACK (gtk_window_hscroll_callback
), this);
2587 g_signal_connect (m_vAdjust
, "value_changed",
2588 G_CALLBACK (gtk_window_vscroll_callback
), this);
2590 gtk_widget_show( m_wxwindow
);
2593 m_parent
->DoAddChild( this );
2595 m_focusWidget
= m_wxwindow
;
2602 wxWindowGTK::~wxWindowGTK()
2606 if (g_focusWindow
== this)
2607 g_focusWindow
= NULL
;
2609 if ( g_delayedFocus
== this )
2610 g_delayedFocus
= NULL
;
2612 m_isBeingDeleted
= true;
2615 // destroy children before destroying this window itself
2618 // unhook focus handlers to prevent stray events being
2619 // propagated to this (soon to be) dead object
2620 if (m_focusWidget
!= NULL
)
2622 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2623 (gpointer
) gtk_window_focus_in_callback
,
2625 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2626 (gpointer
) gtk_window_focus_out_callback
,
2635 gdk_ic_destroy (m_ic
);
2637 gdk_ic_attr_destroy (m_icattr
);
2640 // delete before the widgets to avoid a crash on solaris
2645 gtk_widget_destroy( m_wxwindow
);
2646 m_wxwindow
= (GtkWidget
*) NULL
;
2651 gtk_widget_destroy( m_widget
);
2652 m_widget
= (GtkWidget
*) NULL
;
2656 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2658 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2660 // Use either the given size, or the default if -1 is given.
2661 // See wxWindowBase for these functions.
2662 m_width
= WidthDefault(size
.x
) ;
2663 m_height
= HeightDefault(size
.y
);
2671 void wxWindowGTK::PostCreation()
2673 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2679 // these get reported to wxWidgets -> wxPaintEvent
2681 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2683 g_signal_connect (m_wxwindow
, "expose_event",
2684 G_CALLBACK (gtk_window_expose_callback
), this);
2686 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2689 // Create input method handler
2690 m_imData
= new wxGtkIMData
;
2692 // Cannot handle drawing preedited text yet
2693 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2695 g_signal_connect (m_imData
->context
, "commit",
2696 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2698 // these are called when the "sunken" or "raised" borders are drawn
2699 g_signal_connect (m_widget
, "expose_event",
2700 G_CALLBACK (gtk_window_own_expose_callback
), this);
2705 if (!GTK_IS_WINDOW(m_widget
))
2707 if (m_focusWidget
== NULL
)
2708 m_focusWidget
= m_widget
;
2710 g_signal_connect (m_focusWidget
, "focus_in_event",
2711 G_CALLBACK (gtk_window_focus_in_callback
), this);
2712 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2713 G_CALLBACK (gtk_window_focus_out_callback
), this);
2716 // connect to the various key and mouse handlers
2718 GtkWidget
*connect_widget
= GetConnectWidget();
2720 ConnectWidget( connect_widget
);
2722 /* We cannot set colours, fonts and cursors before the widget has
2723 been realized, so we do this directly after realization */
2724 g_signal_connect (connect_widget
, "realize",
2725 G_CALLBACK (gtk_window_realized_callback
), this);
2729 // Catch native resize events
2730 g_signal_connect (m_wxwindow
, "size_allocate",
2731 G_CALLBACK (gtk_window_size_callback
), this);
2733 // Initialize XIM support
2734 g_signal_connect (m_wxwindow
, "realize",
2735 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2737 // And resize XIM window
2738 g_signal_connect (m_wxwindow
, "size_allocate",
2739 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2742 if (GTK_IS_COMBO(m_widget
))
2744 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2746 g_signal_connect (gcombo
->entry
, "size_request",
2747 G_CALLBACK (wxgtk_combo_size_request_callback
),
2752 // This is needed if we want to add our windows into native
2753 // GTK controls, such as the toolbar. With this callback, the
2754 // toolbar gets to know the correct size (the one set by the
2755 // programmer). Sadly, it misbehaves for wxComboBox.
2756 g_signal_connect (m_widget
, "size_request",
2757 G_CALLBACK (wxgtk_window_size_request_callback
),
2761 InheritAttributes();
2765 // unless the window was created initially hidden (i.e. Hide() had been
2766 // called before Create()), we should show it at GTK+ level as well
2768 gtk_widget_show( m_widget
);
2771 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2773 g_signal_connect (widget
, "key_press_event",
2774 G_CALLBACK (gtk_window_key_press_callback
), this);
2775 g_signal_connect (widget
, "key_release_event",
2776 G_CALLBACK (gtk_window_key_release_callback
), this);
2777 g_signal_connect (widget
, "button_press_event",
2778 G_CALLBACK (gtk_window_button_press_callback
), this);
2779 g_signal_connect (widget
, "button_release_event",
2780 G_CALLBACK (gtk_window_button_release_callback
), this);
2781 g_signal_connect (widget
, "motion_notify_event",
2782 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2783 g_signal_connect (widget
, "scroll_event",
2784 G_CALLBACK (gtk_window_wheel_callback
), this);
2785 g_signal_connect (widget
, "popup_menu",
2786 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2787 g_signal_connect (widget
, "enter_notify_event",
2788 G_CALLBACK (gtk_window_enter_callback
), this);
2789 g_signal_connect (widget
, "leave_notify_event",
2790 G_CALLBACK (gtk_window_leave_callback
), this);
2793 bool wxWindowGTK::Destroy()
2795 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2799 return wxWindowBase::Destroy();
2802 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2804 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2807 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2809 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2810 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2813 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2816 if (m_resizing
) return; /* I don't like recursions */
2819 int currentX
, currentY
;
2820 GetPosition(¤tX
, ¤tY
);
2821 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2823 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2825 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2827 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2829 /* don't set the size for children of wxNotebook, just take the values. */
2837 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2838 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2840 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2841 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2845 m_x
= x
+ pizza
->xoffset
;
2846 m_y
= y
+ pizza
->yoffset
;
2849 // calculate the best size if we should auto size the window
2850 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2851 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2853 const wxSize sizeBest
= GetBestSize();
2854 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2856 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2857 height
= sizeBest
.y
;
2865 int minWidth
= GetMinWidth(),
2866 minHeight
= GetMinHeight(),
2867 maxWidth
= GetMaxWidth(),
2868 maxHeight
= GetMaxHeight();
2870 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2871 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2872 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2873 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2875 int left_border
= 0;
2876 int right_border
= 0;
2878 int bottom_border
= 0;
2880 /* the default button has a border around it */
2881 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2883 GtkBorder
*default_border
= NULL
;
2884 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2887 left_border
+= default_border
->left
;
2888 right_border
+= default_border
->right
;
2889 top_border
+= default_border
->top
;
2890 bottom_border
+= default_border
->bottom
;
2891 g_free( default_border
);
2895 DoMoveWindow( m_x
-top_border
,
2897 m_width
+left_border
+right_border
,
2898 m_height
+top_border
+bottom_border
);
2903 /* Sometimes the client area changes size without the
2904 whole windows's size changing, but if the whole
2905 windows's size doesn't change, no wxSizeEvent will
2906 normally be sent. Here we add an extra test if
2907 the client test has been changed and this will
2909 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2913 wxPrintf( "OnSize sent from " );
2914 if (GetClassInfo() && GetClassInfo()->GetClassName())
2915 wxPrintf( GetClassInfo()->GetClassName() );
2916 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2919 if (!m_nativeSizeEvent
)
2921 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2922 event
.SetEventObject( this );
2923 GetEventHandler()->ProcessEvent( event
);
2929 void wxWindowGTK::OnInternalIdle()
2931 if ( m_dirtyTabOrder
)
2934 // Update style if the window was not yet realized
2935 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2936 if (m_needsStyleChange
)
2938 SetBackgroundStyle(GetBackgroundStyle());
2939 m_needsStyleChange
= false;
2942 // Update invalidated regions.
2945 wxCursor cursor
= m_cursor
;
2946 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2950 /* I now set the cursor anew in every OnInternalIdle call
2951 as setting the cursor in a parent window also effects the
2952 windows above so that checking for the current cursor is
2957 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2959 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2961 if (!g_globalCursor
.Ok())
2962 cursor
= *wxSTANDARD_CURSOR
;
2964 window
= m_widget
->window
;
2965 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2966 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2972 GdkWindow
*window
= m_widget
->window
;
2973 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2974 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2979 if (wxUpdateUIEvent::CanUpdate(this))
2980 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2983 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2985 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2987 if (width
) (*width
) = m_width
;
2988 if (height
) (*height
) = m_height
;
2991 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2993 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2997 SetSize( width
, height
);
3004 #ifndef __WXUNIVERSAL__
3005 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3007 /* when using GTK 1.2 we set the shadow border size to 2 */
3011 if (HasFlag(wxSIMPLE_BORDER
))
3013 /* when using GTK 1.2 we set the simple border size to 1 */
3017 #endif // __WXUNIVERSAL__
3021 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3023 GtkRequisition vscroll_req
;
3024 vscroll_req
.width
= 2;
3025 vscroll_req
.height
= 2;
3026 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3027 (scroll_window
->vscrollbar
, &vscroll_req
);
3029 GtkRequisition hscroll_req
;
3030 hscroll_req
.width
= 2;
3031 hscroll_req
.height
= 2;
3032 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3033 (scroll_window
->hscrollbar
, &hscroll_req
);
3035 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3037 if (scroll_window
->vscrollbar_visible
)
3039 dw
+= vscroll_req
.width
;
3040 dw
+= scroll_class
->scrollbar_spacing
;
3043 if (scroll_window
->hscrollbar_visible
)
3045 dh
+= hscroll_req
.height
;
3046 dh
+= scroll_class
->scrollbar_spacing
;
3050 SetSize( width
+dw
, height
+dh
);
3054 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3056 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3060 if (width
) (*width
) = m_width
;
3061 if (height
) (*height
) = m_height
;
3068 #ifndef __WXUNIVERSAL__
3069 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3071 /* when using GTK 1.2 we set the shadow border size to 2 */
3075 if (HasFlag(wxSIMPLE_BORDER
))
3077 /* when using GTK 1.2 we set the simple border size to 1 */
3081 #endif // __WXUNIVERSAL__
3085 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3087 GtkRequisition vscroll_req
;
3088 vscroll_req
.width
= 2;
3089 vscroll_req
.height
= 2;
3090 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3091 (scroll_window
->vscrollbar
, &vscroll_req
);
3093 GtkRequisition hscroll_req
;
3094 hscroll_req
.width
= 2;
3095 hscroll_req
.height
= 2;
3096 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3097 (scroll_window
->hscrollbar
, &hscroll_req
);
3099 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3101 if (scroll_window
->vscrollbar_visible
)
3103 dw
+= vscroll_req
.width
;
3104 dw
+= scroll_class
->scrollbar_spacing
;
3107 if (scroll_window
->hscrollbar_visible
)
3109 dh
+= hscroll_req
.height
;
3110 dh
+= scroll_class
->scrollbar_spacing
;
3114 if (width
) (*width
) = m_width
- dw
;
3115 if (height
) (*height
) = m_height
- dh
;
3119 printf( "GetClientSize, name %s ", GetName().c_str() );
3120 if (width) printf( " width = %d", (*width) );
3121 if (height) printf( " height = %d", (*height) );
3126 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3128 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3132 if (m_parent
&& m_parent
->m_wxwindow
)
3134 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3135 dx
= pizza
->xoffset
;
3136 dy
= pizza
->yoffset
;
3139 if (x
) (*x
) = m_x
- dx
;
3140 if (y
) (*y
) = m_y
- dy
;
3143 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3145 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3147 if (!m_widget
->window
) return;
3149 GdkWindow
*source
= (GdkWindow
*) NULL
;
3151 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3153 source
= m_widget
->window
;
3157 gdk_window_get_origin( source
, &org_x
, &org_y
);
3161 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3163 org_x
+= m_widget
->allocation
.x
;
3164 org_y
+= m_widget
->allocation
.y
;
3172 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3174 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3176 if (!m_widget
->window
) return;
3178 GdkWindow
*source
= (GdkWindow
*) NULL
;
3180 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3182 source
= m_widget
->window
;
3186 gdk_window_get_origin( source
, &org_x
, &org_y
);
3190 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3192 org_x
+= m_widget
->allocation
.x
;
3193 org_y
+= m_widget
->allocation
.y
;
3201 bool wxWindowGTK::Show( bool show
)
3203 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3205 if (!wxWindowBase::Show(show
))
3212 gtk_widget_show( m_widget
);
3214 gtk_widget_hide( m_widget
);
3216 wxShowEvent
eventShow(GetId(), show
);
3217 eventShow
.SetEventObject(this);
3219 GetEventHandler()->ProcessEvent(eventShow
);
3224 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3226 win
->OnParentEnable(enable
);
3228 // Recurse, so that children have the opportunity to Do The Right Thing
3229 // and reset colours that have been messed up by a parent's (really ancestor's)
3231 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3233 node
= node
->GetNext() )
3235 wxWindow
*child
= node
->GetData();
3236 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3237 wxWindowNotifyEnable(child
, enable
);
3241 bool wxWindowGTK::Enable( bool enable
)
3243 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3245 if (!wxWindowBase::Enable(enable
))
3251 gtk_widget_set_sensitive( m_widget
, enable
);
3253 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3255 wxWindowNotifyEnable(this, enable
);
3260 int wxWindowGTK::GetCharHeight() const
3262 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3264 wxFont font
= GetFont();
3265 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3267 PangoContext
*context
= NULL
;
3269 context
= gtk_widget_get_pango_context( m_widget
);
3274 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3275 PangoLayout
*layout
= pango_layout_new(context
);
3276 pango_layout_set_font_description(layout
, desc
);
3277 pango_layout_set_text(layout
, "H", 1);
3278 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3280 PangoRectangle rect
;
3281 pango_layout_line_get_extents(line
, NULL
, &rect
);
3283 g_object_unref( G_OBJECT( layout
) );
3285 return (int) PANGO_PIXELS(rect
.height
);
3288 int wxWindowGTK::GetCharWidth() const
3290 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3292 wxFont font
= GetFont();
3293 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3295 PangoContext
*context
= NULL
;
3297 context
= gtk_widget_get_pango_context( m_widget
);
3302 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3303 PangoLayout
*layout
= pango_layout_new(context
);
3304 pango_layout_set_font_description(layout
, desc
);
3305 pango_layout_set_text(layout
, "g", 1);
3306 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3308 PangoRectangle rect
;
3309 pango_layout_line_get_extents(line
, NULL
, &rect
);
3311 g_object_unref( G_OBJECT( layout
) );
3313 return (int) PANGO_PIXELS(rect
.width
);
3316 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3320 int *externalLeading
,
3321 const wxFont
*theFont
) const
3323 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3325 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3334 PangoContext
*context
= NULL
;
3336 context
= gtk_widget_get_pango_context( m_widget
);
3345 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3346 PangoLayout
*layout
= pango_layout_new(context
);
3347 pango_layout_set_font_description(layout
, desc
);
3350 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3351 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3353 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3354 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3355 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3359 PangoRectangle rect
;
3360 pango_layout_get_extents(layout
, NULL
, &rect
);
3362 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3363 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3366 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3367 int baseline
= pango_layout_iter_get_baseline(iter
);
3368 pango_layout_iter_free(iter
);
3369 *descent
= *y
- PANGO_PIXELS(baseline
);
3371 if (externalLeading
) (*externalLeading
) = 0; // ??
3373 g_object_unref( G_OBJECT( layout
) );
3376 void wxWindowGTK::SetFocus()
3378 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3381 // don't do anything if we already have focus
3387 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3389 gtk_widget_grab_focus (m_wxwindow
);
3394 if (GTK_IS_CONTAINER(m_widget
))
3396 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3399 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3402 if (!GTK_WIDGET_REALIZED(m_widget
))
3404 // we can't set the focus to the widget now so we remember that
3405 // it should be focused and will do it later, during the idle
3406 // time, as soon as we can
3407 wxLogTrace(TRACE_FOCUS
,
3408 _T("Delaying setting focus to %s(%s)"),
3409 GetClassInfo()->GetClassName(), GetLabel().c_str());
3411 g_delayedFocus
= this;
3415 wxLogTrace(TRACE_FOCUS
,
3416 _T("Setting focus to %s(%s)"),
3417 GetClassInfo()->GetClassName(), GetLabel().c_str());
3419 gtk_widget_grab_focus (m_widget
);
3424 wxLogTrace(TRACE_FOCUS
,
3425 _T("Can't set focus to %s(%s)"),
3426 GetClassInfo()->GetClassName(), GetLabel().c_str());
3431 bool wxWindowGTK::AcceptsFocus() const
3433 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3436 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3438 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3440 wxWindowGTK
*oldParent
= m_parent
,
3441 *newParent
= (wxWindowGTK
*)newParentBase
;
3443 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3445 if ( !wxWindowBase::Reparent(newParent
) )
3448 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3450 /* prevent GTK from deleting the widget arbitrarily */
3451 gtk_widget_ref( m_widget
);
3455 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3458 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3462 /* insert GTK representation */
3463 (*(newParent
->m_insertCallback
))(newParent
, this);
3466 /* reverse: prevent GTK from deleting the widget arbitrarily */
3467 gtk_widget_unref( m_widget
);
3472 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3474 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3476 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3478 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3483 /* insert GTK representation */
3484 (*m_insertCallback
)(this, child
);
3487 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3489 wxWindowBase::AddChild(child
);
3490 m_dirtyTabOrder
= true;
3492 wxapp_install_idle_handler();
3495 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3497 wxWindowBase::RemoveChild(child
);
3498 m_dirtyTabOrder
= true;
3500 wxapp_install_idle_handler();
3503 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3505 wxWindowBase::DoMoveInTabOrder(win
, move
);
3506 m_dirtyTabOrder
= true;
3508 wxapp_install_idle_handler();
3511 void wxWindowGTK::RealizeTabOrder()
3515 if (m_children
.size() > 0)
3517 GList
*chain
= NULL
;
3519 for (wxWindowList::const_iterator i
= m_children
.begin();
3520 i
!= m_children
.end(); ++i
)
3522 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3525 chain
= g_list_reverse(chain
);
3527 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3532 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3536 m_dirtyTabOrder
= false;
3539 void wxWindowGTK::Raise()
3541 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3543 if (m_wxwindow
&& m_wxwindow
->window
)
3545 gdk_window_raise( m_wxwindow
->window
);
3547 else if (m_widget
->window
)
3549 gdk_window_raise( m_widget
->window
);
3553 void wxWindowGTK::Lower()
3555 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3557 if (m_wxwindow
&& m_wxwindow
->window
)
3559 gdk_window_lower( m_wxwindow
->window
);
3561 else if (m_widget
->window
)
3563 gdk_window_lower( m_widget
->window
);
3567 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3569 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3571 if (cursor
== m_cursor
)
3575 wxapp_install_idle_handler();
3577 if (cursor
== wxNullCursor
)
3578 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3580 return wxWindowBase::SetCursor( cursor
);
3583 void wxWindowGTK::WarpPointer( int x
, int y
)
3585 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3587 // We provide this function ourselves as it is
3588 // missing in GDK (top of this file).
3590 GdkWindow
*window
= (GdkWindow
*) NULL
;
3592 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3594 window
= GetConnectWidget()->window
;
3597 gdk_window_warp_pointer( window
, x
, y
);
3601 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3605 if (!m_widget
->window
)
3610 GdkRectangle gdk_rect
,
3614 gdk_rect
.x
= rect
->x
;
3615 gdk_rect
.y
= rect
->y
;
3616 gdk_rect
.width
= rect
->width
;
3617 gdk_rect
.height
= rect
->height
;
3620 else // invalidate everything
3625 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3629 void wxWindowGTK::Update()
3633 // when we call Update() we really want to update the window immediately on
3634 // screen, even if it means flushing the entire queue and hence slowing down
3635 // everything -- but it should still be done, it's just that Update() should
3636 // be called very rarely
3640 void wxWindowGTK::GtkUpdate()
3642 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3643 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3645 // for consistency with other platforms (and also because it's convenient
3646 // to be able to update an entire TLW by calling Update() only once), we
3647 // should also update all our children here
3648 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3650 node
= node
->GetNext() )
3652 node
->GetData()->GtkUpdate();
3656 void wxWindowGTK::GtkSendPaintEvents()
3660 m_updateRegion
.Clear();
3664 // Clip to paint region in wxClientDC
3665 m_clipPaintRegion
= true;
3667 // widget to draw on
3668 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3670 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3672 // find ancestor from which to steal background
3673 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3675 parent
= (wxWindow
*)this;
3677 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3679 wxRegionIterator
upd( m_updateRegion
);
3683 rect
.x
= upd
.GetX();
3684 rect
.y
= upd
.GetY();
3685 rect
.width
= upd
.GetWidth();
3686 rect
.height
= upd
.GetHeight();
3688 gtk_paint_flat_box( parent
->m_widget
->style
,
3690 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3704 wxWindowDC
dc( (wxWindow
*)this );
3705 dc
.SetClippingRegion( m_updateRegion
);
3707 wxEraseEvent
erase_event( GetId(), &dc
);
3708 erase_event
.SetEventObject( this );
3710 GetEventHandler()->ProcessEvent(erase_event
);
3713 wxNcPaintEvent
nc_paint_event( GetId() );
3714 nc_paint_event
.SetEventObject( this );
3715 GetEventHandler()->ProcessEvent( nc_paint_event
);
3717 wxPaintEvent
paint_event( GetId() );
3718 paint_event
.SetEventObject( this );
3719 GetEventHandler()->ProcessEvent( paint_event
);
3721 m_clipPaintRegion
= false;
3723 m_updateRegion
.Clear();
3726 void wxWindowGTK::ClearBackground()
3728 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3732 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3734 wxWindowBase::DoSetToolTip(tip
);
3737 m_tooltip
->Apply( (wxWindow
*)this );
3740 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3742 wxString
tmp( tip
);
3743 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3745 #endif // wxUSE_TOOLTIPS
3747 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3749 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3751 if (!wxWindowBase::SetBackgroundColour(colour
))
3756 // We need the pixel value e.g. for background clearing.
3757 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3760 // apply style change (forceStyle=true so that new style is applied
3761 // even if the bg colour changed from valid to wxNullColour)
3762 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3763 ApplyWidgetStyle(true);
3768 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3770 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3772 if (!wxWindowBase::SetForegroundColour(colour
))
3779 // We need the pixel value e.g. for background clearing.
3780 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3783 // apply style change (forceStyle=true so that new style is applied
3784 // even if the bg colour changed from valid to wxNullColour):
3785 ApplyWidgetStyle(true);
3790 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3792 return gtk_widget_get_pango_context( m_widget
);
3795 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3797 // do we need to apply any changes at all?
3800 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3805 GtkRcStyle
*style
= gtk_rc_style_new();
3810 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3813 if ( m_foregroundColour
.Ok() )
3815 GdkColor
*fg
= m_foregroundColour
.GetColor();
3817 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3818 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3820 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3821 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3823 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3824 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3827 if ( m_backgroundColour
.Ok() )
3829 GdkColor
*bg
= m_backgroundColour
.GetColor();
3831 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3832 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3833 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3834 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3836 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3837 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3838 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3839 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3841 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3842 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3843 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3844 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3846 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3847 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3848 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3849 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3855 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3857 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3860 DoApplyWidgetStyle(style
);
3861 gtk_rc_style_unref(style
);
3864 // Style change may affect GTK+'s size calculation:
3865 InvalidateBestSize();
3868 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3871 gtk_widget_modify_style(m_wxwindow
, style
);
3873 gtk_widget_modify_style(m_widget
, style
);
3876 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3878 wxWindowBase::SetBackgroundStyle(style
);
3880 if (style
== wxBG_STYLE_CUSTOM
)
3882 GdkWindow
*window
= (GdkWindow
*) NULL
;
3884 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3886 window
= GetConnectWidget()->window
;
3890 // Make sure GDK/X11 doesn't refresh the window
3892 gdk_window_set_back_pixmap( window
, None
, False
);
3894 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3897 m_needsStyleChange
= false;
3900 // Do in OnIdle, because the window is not yet available
3901 m_needsStyleChange
= true;
3903 // Don't apply widget style, or we get a grey background
3907 // apply style change (forceStyle=true so that new style is applied
3908 // even if the bg colour changed from valid to wxNullColour):
3909 ApplyWidgetStyle(true);
3914 #if wxUSE_DRAG_AND_DROP
3916 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3918 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3920 GtkWidget
*dnd_widget
= GetConnectWidget();
3922 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3924 if (m_dropTarget
) delete m_dropTarget
;
3925 m_dropTarget
= dropTarget
;
3927 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3930 #endif // wxUSE_DRAG_AND_DROP
3932 GtkWidget
* wxWindowGTK::GetConnectWidget()
3934 GtkWidget
*connect_widget
= m_widget
;
3935 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3937 return connect_widget
;
3940 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3943 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3945 return (window
== m_widget
->window
);
3948 bool wxWindowGTK::SetFont( const wxFont
&font
)
3950 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3952 if (!wxWindowBase::SetFont(font
))
3955 // apply style change (forceStyle=true so that new style is applied
3956 // even if the font changed from valid to wxNullFont):
3957 ApplyWidgetStyle(true);
3962 void wxWindowGTK::DoCaptureMouse()
3964 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3966 GdkWindow
*window
= (GdkWindow
*) NULL
;
3968 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3970 window
= GetConnectWidget()->window
;
3972 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3974 wxCursor
* cursor
= & m_cursor
;
3976 cursor
= wxSTANDARD_CURSOR
;
3978 gdk_pointer_grab( window
, FALSE
,
3980 (GDK_BUTTON_PRESS_MASK
|
3981 GDK_BUTTON_RELEASE_MASK
|
3982 GDK_POINTER_MOTION_HINT_MASK
|
3983 GDK_POINTER_MOTION_MASK
),
3985 cursor
->GetCursor(),
3986 (guint32
)GDK_CURRENT_TIME
);
3987 g_captureWindow
= this;
3988 g_captureWindowHasMouse
= true;
3991 void wxWindowGTK::DoReleaseMouse()
3993 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3995 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3997 g_captureWindow
= (wxWindowGTK
*) NULL
;
3999 GdkWindow
*window
= (GdkWindow
*) NULL
;
4001 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4003 window
= GetConnectWidget()->window
;
4008 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4012 wxWindow
*wxWindowBase::GetCapture()
4014 return (wxWindow
*)g_captureWindow
;
4017 bool wxWindowGTK::IsRetained() const
4022 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4023 int range
, bool refresh
)
4025 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4027 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4029 m_hasScrolling
= true;
4031 if (orient
== wxHORIZONTAL
)
4033 float fpos
= (float)pos
;
4034 float frange
= (float)range
;
4035 float fthumb
= (float)thumbVisible
;
4036 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4037 if (fpos
< 0.0) fpos
= 0.0;
4039 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4040 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4042 SetScrollPos( orient
, pos
, refresh
);
4046 m_oldHorizontalPos
= fpos
;
4048 m_hAdjust
->lower
= 0.0;
4049 m_hAdjust
->upper
= frange
;
4050 m_hAdjust
->value
= fpos
;
4051 m_hAdjust
->step_increment
= 1.0;
4052 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4053 m_hAdjust
->page_size
= fthumb
;
4057 float fpos
= (float)pos
;
4058 float frange
= (float)range
;
4059 float fthumb
= (float)thumbVisible
;
4060 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4061 if (fpos
< 0.0) fpos
= 0.0;
4063 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4064 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4066 SetScrollPos( orient
, pos
, refresh
);
4070 m_oldVerticalPos
= fpos
;
4072 m_vAdjust
->lower
= 0.0;
4073 m_vAdjust
->upper
= frange
;
4074 m_vAdjust
->value
= fpos
;
4075 m_vAdjust
->step_increment
= 1.0;
4076 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4077 m_vAdjust
->page_size
= fthumb
;
4080 if (orient
== wxHORIZONTAL
)
4081 g_signal_emit_by_name (m_hAdjust
, "changed");
4083 g_signal_emit_by_name (m_vAdjust
, "changed");
4086 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4088 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4089 gpointer fn
= orient
== wxHORIZONTAL
4090 ? (gpointer
) gtk_window_hscroll_callback
4091 : (gpointer
) gtk_window_vscroll_callback
;
4093 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4094 g_signal_emit_by_name (adj
, "value_changed");
4095 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4098 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4100 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4101 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4103 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4105 float fpos
= (float)pos
;
4106 if (fpos
> adj
->upper
- adj
->page_size
)
4107 fpos
= adj
->upper
- adj
->page_size
;
4110 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4112 if (fabs(fpos
-adj
->value
) < 0.2)
4116 if ( m_wxwindow
->window
)
4121 int wxWindowGTK::GetScrollThumb( int orient
) const
4123 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4125 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4127 if (orient
== wxHORIZONTAL
)
4128 return (int)(m_hAdjust
->page_size
+0.5);
4130 return (int)(m_vAdjust
->page_size
+0.5);
4133 int wxWindowGTK::GetScrollPos( int orient
) const
4135 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4137 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4139 if (orient
== wxHORIZONTAL
)
4140 return (int)(m_hAdjust
->value
+0.5);
4142 return (int)(m_vAdjust
->value
+0.5);
4145 int wxWindowGTK::GetScrollRange( int orient
) const
4147 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4149 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4151 if (orient
== wxHORIZONTAL
)
4152 return (int)(m_hAdjust
->upper
+0.5);
4154 return (int)(m_vAdjust
->upper
+0.5);
4157 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4159 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4161 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4163 // No scrolling requested.
4164 if ((dx
== 0) && (dy
== 0)) return;
4166 m_clipPaintRegion
= true;
4168 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4170 m_clipPaintRegion
= false;
4173 void wxWindowGTK::SetWindowStyleFlag( long style
)
4175 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4176 wxWindowBase::SetWindowStyleFlag(style
);
4179 // Find the wxWindow at the current mouse position, also returning the mouse
4181 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4183 pt
= wxGetMousePosition();
4184 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4188 // Get the current mouse position.
4189 wxPoint
wxGetMousePosition()
4191 /* This crashes when used within wxHelpContext,
4192 so we have to use the X-specific implementation below.
4194 GdkModifierType *mask;
4195 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4197 return wxPoint(x, y);
4201 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4203 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4204 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4205 Window rootReturn
, childReturn
;
4206 int rootX
, rootY
, winX
, winY
;
4207 unsigned int maskReturn
;
4209 XQueryPointer (display
,
4213 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4214 return wxPoint(rootX
, rootY
);
4218 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4219 void wxAddGrab(wxWindow
* window
)
4221 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4224 void wxRemoveGrab(wxWindow
* window
)
4226 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4229 // ----------------------------------------------------------------------------
4231 // ----------------------------------------------------------------------------
4233 class wxWinModule
: public wxModule
4240 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4243 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4245 bool wxWinModule::OnInit()
4247 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4248 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4253 void wxWinModule::OnExit()
4256 gdk_gc_unref( g_eraseGC
);