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"
50 #include "wx/stattext.h"
53 #include "wx/thread.h"
59 #include "wx/gtk/private.h"
60 #include <gdk/gdkprivate.h>
61 #include <gdk/gdkkeysyms.h>
65 #include <gtk/gtkprivate.h>
67 #include "wx/gtk/win_gtk.h"
69 #include <pango/pangox.h>
75 extern GtkContainerClass
*pizza_parent_class
;
77 //-----------------------------------------------------------------------------
78 // documentation on internals
79 //-----------------------------------------------------------------------------
82 I have been asked several times about writing some documentation about
83 the GTK port of wxWidgets, especially its internal structures. Obviously,
84 you cannot understand wxGTK without knowing a little about the GTK, but
85 some more information about what the wxWindow, which is the base class
86 for all other window classes, does seems required as well.
90 What does wxWindow do? It contains the common interface for the following
91 jobs of its descendants:
93 1) Define the rudimentary behaviour common to all window classes, such as
94 resizing, intercepting user input (so as to make it possible to use these
95 events for special purposes in a derived class), window names etc.
97 2) Provide the possibility to contain and manage children, if the derived
98 class is allowed to contain children, which holds true for those window
99 classes which do not display a native GTK widget. To name them, these
100 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
101 work classes are a special case and are handled a bit differently from
102 the rest. The same holds true for the wxNotebook class.
104 3) Provide the possibility to draw into a client area of a window. This,
105 too, only holds true for classes that do not display a native GTK widget
108 4) Provide the entire mechanism for scrolling widgets. This actual inter-
109 face for this is usually in wxScrolledWindow, but the GTK implementation
112 5) A multitude of helper or extra methods for special purposes, such as
113 Drag'n'Drop, managing validators etc.
115 6) Display a border (sunken, raised, simple or none).
117 Normally one might expect, that one wxWidgets window would always correspond
118 to one GTK widget. Under GTK, there is no such allround widget that has all
119 the functionality. Moreover, the GTK defines a client area as a different
120 widget from the actual widget you are handling. Last but not least some
121 special classes (e.g. wxFrame) handle different categories of widgets and
122 still have the possibility to draw something in the client area.
123 It was therefore required to write a special purpose GTK widget, that would
124 represent a client area in the sense of wxWidgets capable to do the jobs
125 2), 3) and 4). I have written this class and it resides in win_gtk.c of
128 All windows must have a widget, with which they interact with other under-
129 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
130 the wxWindow class has a member variable called m_widget which holds a
131 pointer to this widget. When the window class represents a GTK native widget,
132 this is (in most cases) the only GTK widget the class manages. E.g. the
133 wxStaticText class handles only a GtkLabel widget a pointer to which you
134 can find in m_widget (defined in wxWindow)
136 When the class has a client area for drawing into and for containing children
137 it has to handle the client area widget (of the type GtkPizza, defined in
138 win_gtk.c), but there could be any number of widgets, handled by a class
139 The common rule for all windows is only, that the widget that interacts with
140 the rest of GTK must be referenced in m_widget and all other widgets must be
141 children of this widget on the GTK level. The top-most widget, which also
142 represents the client area, must be in the m_wxwindow field and must be of
145 As I said, the window classes that display a GTK native widget only have
146 one widget, so in the case of e.g. the wxButton class m_widget holds a
147 pointer to a GtkButton widget. But windows with client areas (for drawing
148 and children) have a m_widget field that is a pointer to a GtkScrolled-
149 Window and a m_wxwindow field that is pointer to a GtkPizza and this
150 one is (in the GTK sense) a child of the GtkScrolledWindow.
152 If the m_wxwindow field is set, then all input to this widget is inter-
153 cepted and sent to the wxWidgets class. If not, all input to the widget
154 that gets pointed to by m_widget gets intercepted and sent to the class.
158 The design of scrolling in wxWidgets is markedly different from that offered
159 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
160 clicking on a scrollbar belonging to scrolled window will inevitably move
161 the window. In wxWidgets, the scrollbar will only emit an event, send this
162 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
163 which actually moves the window and its subchildren. Note that GtkPizza
164 memorizes how much it has been scrolled but that wxWidgets forgets this
165 so that the two coordinates systems have to be kept in synch. This is done
166 in various places using the pizza->xoffset and pizza->yoffset values.
170 Singularily the most broken code in GTK is the code that is supposed to
171 inform subwindows (child windows) about new positions. Very often, duplicate
172 events are sent without changes in size or position, equally often no
173 events are sent at all (All this is due to a bug in the GtkContainer code
174 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
175 GTK's own system and it simply waits for size events for toplevel windows
176 and then iterates down the respective size events to all window. This has
177 the disadvantage that windows might get size events before the GTK widget
178 actually has the reported size. This doesn't normally pose any problem, but
179 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
180 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
181 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
182 window that is used for OpenGL output really has that size (as reported by
187 If someone at some point of time feels the immense desire to have a look at,
188 change or attempt to optimise the Refresh() logic, this person will need an
189 intimate understanding of what "draw" and "expose" events are and what
190 they are used for, in particular when used in connection with GTK's
191 own windowless widgets. Beware.
195 Cursors, too, have been a constant source of pleasure. The main difficulty
196 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
197 for the parent. To prevent this from doing too much harm, I use idle time
198 to set the cursor over and over again, starting from the toplevel windows
199 and ending with the youngest generation (speaking of parent and child windows).
200 Also don't forget that cursors (like much else) are connected to GdkWindows,
201 not GtkWidgets and that the "window" field of a GtkWidget might very well
202 point to the GdkWindow of the parent widget (-> "window-less widget") and
203 that the two obviously have very different meanings.
207 //-----------------------------------------------------------------------------
209 //-----------------------------------------------------------------------------
211 extern wxList wxPendingDelete
;
212 extern bool g_blockEventsOnDrag
;
213 extern bool g_blockEventsOnScroll
;
214 extern wxCursor g_globalCursor
;
216 static GdkGC
*g_eraseGC
= NULL
;
218 // mouse capture state: the window which has it and if the mouse is currently
220 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
221 static bool g_captureWindowHasMouse
= false;
223 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
225 // the last window which had the focus - this is normally never NULL (except
226 // if we never had focus at all) as even when g_focusWindow is NULL it still
227 // keeps its previous value
228 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
230 // If a window get the focus set but has not been realized
231 // yet, defer setting the focus to idle time.
232 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
234 extern bool g_mainThreadLocked
;
236 //-----------------------------------------------------------------------------
238 //-----------------------------------------------------------------------------
243 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
245 # define DEBUG_MAIN_THREAD
248 #define DEBUG_MAIN_THREAD
251 // the trace mask used for the focus debugging messages
252 #define TRACE_FOCUS _T("focus")
254 //-----------------------------------------------------------------------------
255 // missing gdk functions
256 //-----------------------------------------------------------------------------
259 gdk_window_warp_pointer (GdkWindow
*window
,
264 window
= GDK_ROOT_PARENT();
266 if (!GDK_WINDOW_DESTROYED(window
))
268 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
269 None
, /* not source window -> move from anywhere */
270 GDK_WINDOW_XID(window
), /* dest window */
271 0, 0, 0, 0, /* not source window -> move from anywhere */
276 //-----------------------------------------------------------------------------
278 //-----------------------------------------------------------------------------
280 extern void wxapp_install_idle_handler();
281 extern bool g_isIdle
;
283 //-----------------------------------------------------------------------------
284 // local code (see below)
285 //-----------------------------------------------------------------------------
287 // returns the child of win which currently has focus or NULL if not found
289 // Note: can't be static, needed by textctrl.cpp.
290 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
292 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
294 return (wxWindow
*)NULL
;
296 if ( winFocus
== win
)
297 return (wxWindow
*)win
;
299 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
301 node
= node
->GetNext() )
303 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
308 return (wxWindow
*)NULL
;
311 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
313 // wxUniversal widgets draw the borders and scrollbars themselves
314 #ifndef __WXUNIVERSAL__
321 if (win
->m_hasScrolling
)
323 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
325 GtkRequisition vscroll_req
;
326 vscroll_req
.width
= 2;
327 vscroll_req
.height
= 2;
328 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
329 (scroll_window
->vscrollbar
, &vscroll_req
);
331 GtkRequisition hscroll_req
;
332 hscroll_req
.width
= 2;
333 hscroll_req
.height
= 2;
334 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
335 (scroll_window
->hscrollbar
, &hscroll_req
);
337 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
339 if (scroll_window
->vscrollbar_visible
)
341 dw
+= vscroll_req
.width
;
342 dw
+= scroll_class
->scrollbar_spacing
;
345 if (scroll_window
->hscrollbar_visible
)
347 dh
+= hscroll_req
.height
;
348 dh
+= scroll_class
->scrollbar_spacing
;
354 if (GTK_WIDGET_NO_WINDOW (widget
))
356 dx
+= widget
->allocation
.x
;
357 dy
+= widget
->allocation
.y
;
360 if (win
->HasFlag(wxRAISED_BORDER
))
362 gtk_paint_shadow (widget
->style
,
366 NULL
, NULL
, NULL
, // FIXME: No clipping?
368 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
372 if (win
->HasFlag(wxSUNKEN_BORDER
))
374 gtk_paint_shadow (widget
->style
,
378 NULL
, NULL
, NULL
, // FIXME: No clipping?
380 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
384 if (win
->HasFlag(wxSIMPLE_BORDER
))
387 gc
= gdk_gc_new( widget
->window
);
388 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
389 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
391 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
395 #endif // __WXUNIVERSAL__
398 //-----------------------------------------------------------------------------
399 // "expose_event" of m_widget
400 //-----------------------------------------------------------------------------
403 static gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
405 if (gdk_event
->count
> 0) return FALSE
;
407 draw_frame( widget
, win
);
409 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
415 //-----------------------------------------------------------------------------
416 // "size_request" of m_widget
417 //-----------------------------------------------------------------------------
419 // make it extern because wxStaticText needs to disconnect this one
421 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
422 GtkRequisition
*requisition
,
426 win
->GetSize( &w
, &h
);
432 requisition
->height
= h
;
433 requisition
->width
= w
;
439 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
440 GtkRequisition
*requisition
,
443 // This callback is actually hooked into the text entry
444 // of the combo box, not the GtkHBox.
447 win
->GetSize( &w
, &h
);
453 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
455 GtkRequisition entry_req
;
457 entry_req
.height
= 2;
458 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
459 (gcombo
->button
, &entry_req
);
461 requisition
->width
= w
- entry_req
.width
;
462 requisition
->height
= entry_req
.height
;
466 //-----------------------------------------------------------------------------
467 // "expose_event" of m_wxwindow
468 //-----------------------------------------------------------------------------
471 static int gtk_window_expose_callback( GtkWidget
*widget
,
472 GdkEventExpose
*gdk_event
,
478 wxapp_install_idle_handler();
480 // This callback gets called in drawing-idle time under
481 // GTK 2.0, so we don't need to defer anything to idle
484 GtkPizza
*pizza
= GTK_PIZZA( widget
);
485 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
490 wxPrintf( wxT("OnExpose from ") );
491 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
492 wxPrintf( win
->GetClassInfo()->GetClassName() );
493 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
494 (int)gdk_event
->area
.y
,
495 (int)gdk_event
->area
.width
,
496 (int)gdk_event
->area
.height
);
501 win
->m_wxwindow
->style
,
505 (GdkRectangle
*) NULL
,
507 (char *)"button", // const_cast
512 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
514 win
->GtkSendPaintEvents();
517 // Let parent window draw window-less widgets
518 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
524 //-----------------------------------------------------------------------------
525 // "key_press_event" from any window
526 //-----------------------------------------------------------------------------
528 // set WXTRACE to this to see the key event codes on the console
529 #define TRACE_KEYS _T("keyevent")
531 // translates an X key symbol to WXK_XXX value
533 // if isChar is true it means that the value returned will be used for EVT_CHAR
534 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
535 // for example, while if it is false it means that the value is going to be
536 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
538 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
544 // Shift, Control and Alt don't generate the CHAR events at all
547 key_code
= isChar
? 0 : WXK_SHIFT
;
551 key_code
= isChar
? 0 : WXK_CONTROL
;
559 key_code
= isChar
? 0 : WXK_ALT
;
562 // neither do the toggle modifies
563 case GDK_Scroll_Lock
:
564 key_code
= isChar
? 0 : WXK_SCROLL
;
568 key_code
= isChar
? 0 : WXK_CAPITAL
;
572 key_code
= isChar
? 0 : WXK_NUMLOCK
;
576 // various other special keys
589 case GDK_ISO_Left_Tab
:
596 key_code
= WXK_RETURN
;
600 key_code
= WXK_CLEAR
;
604 key_code
= WXK_PAUSE
;
608 key_code
= WXK_SELECT
;
612 key_code
= WXK_PRINT
;
616 key_code
= WXK_EXECUTE
;
620 key_code
= WXK_ESCAPE
;
623 // cursor and other extended keyboard keys
625 key_code
= WXK_DELETE
;
641 key_code
= WXK_RIGHT
;
648 case GDK_Prior
: // == GDK_Page_Up
649 key_code
= WXK_PRIOR
;
652 case GDK_Next
: // == GDK_Page_Down
665 key_code
= WXK_INSERT
;
680 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
684 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
688 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
692 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
696 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
700 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
704 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
708 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
712 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
716 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
720 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
724 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
728 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
731 case GDK_KP_Prior
: // == GDK_KP_Page_Up
732 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
735 case GDK_KP_Next
: // == GDK_KP_Page_Down
736 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
740 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
744 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
748 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
752 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
756 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
759 case GDK_KP_Multiply
:
760 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
764 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
767 case GDK_KP_Separator
:
768 // FIXME: what is this?
769 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
772 case GDK_KP_Subtract
:
773 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
777 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
781 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
798 key_code
= WXK_F1
+ keysym
- GDK_F1
;
808 static inline bool wxIsAsciiKeysym(KeySym ks
)
813 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
815 GdkEventKey
*gdk_event
)
819 GdkModifierType state
;
820 if (gdk_event
->window
)
821 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
823 event
.SetTimestamp( gdk_event
->time
);
824 event
.SetId(win
->GetId());
825 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
826 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
827 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
828 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
829 event
.m_scanCode
= gdk_event
->keyval
;
830 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
831 event
.m_rawFlags
= 0;
833 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
834 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
836 event
.m_uniChar
= toupper(event
.m_uniChar
);
839 wxGetMousePosition( &x
, &y
);
840 win
->ScreenToClient( &x
, &y
);
843 event
.SetEventObject( win
);
848 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
850 GdkEventKey
*gdk_event
)
852 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
853 // but only event->keyval which is quite useless to us, so remember
854 // the last character from GDK_KEY_PRESS and reuse it as last resort
856 // NB: should be MT-safe as we're always called from the main thread only
861 } s_lastKeyPress
= { 0, 0 };
863 KeySym keysym
= gdk_event
->keyval
;
865 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
866 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
870 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
874 // do we have the translation or is it a plain ASCII character?
875 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
877 // we should use keysym if it is ASCII as X does some translations
878 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
879 // which we don't want here (but which we do use for OnChar())
880 if ( !wxIsAsciiKeysym(keysym
) )
882 keysym
= (KeySym
)gdk_event
->string
[0];
885 // we want to always get the same key code when the same key is
886 // pressed regardless of the state of the modifiers, i.e. on a
887 // standard US keyboard pressing '5' or '%' ('5' key with
888 // Shift) should result in the same key code in OnKeyDown():
889 // '5' (although OnChar() will get either '5' or '%').
891 // to do it we first translate keysym to keycode (== scan code)
892 // and then back but always using the lower register
893 Display
*dpy
= (Display
*)wxGetDisplay();
894 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
896 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
898 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
900 // use the normalized, i.e. lower register, keysym if we've
902 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
904 // as explained above, we want to have lower register key codes
905 // normally but for the letter keys we want to have the upper ones
907 // NB: don't use XConvertCase() here, we want to do it for letters
909 key_code
= toupper(key_code
);
911 else // non ASCII key, what to do?
913 // by default, ignore it
916 // but if we have cached information from the last KEY_PRESS
917 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
920 if ( keysym
== s_lastKeyPress
.keysym
)
922 key_code
= s_lastKeyPress
.keycode
;
927 if ( gdk_event
->type
== GDK_KEY_PRESS
)
929 // remember it to be reused for KEY_UP event later
930 s_lastKeyPress
.keysym
= keysym
;
931 s_lastKeyPress
.keycode
= key_code
;
935 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
937 // sending unknown key events doesn't really make sense
941 // now fill all the other fields
942 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
944 event
.m_keyCode
= key_code
;
952 GtkIMContext
*context
;
953 GdkEventKey
*lastKeyEvent
;
957 context
= gtk_im_multicontext_new();
962 g_object_unref(context
);
967 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
968 GdkEventKey
*gdk_event
,
974 wxapp_install_idle_handler();
978 if (g_blockEventsOnDrag
)
982 wxKeyEvent
event( wxEVT_KEY_DOWN
);
984 bool return_after_IM
= false;
986 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
988 // Emit KEY_DOWN event
989 ret
= win
->GetEventHandler()->ProcessEvent( event
);
993 // Return after IM processing as we cannot do
994 // anything with it anyhow.
995 return_after_IM
= true;
998 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
999 // When we get a key_press event here, it could be originate
1000 // from the current widget or its child widgets. However, only the widget
1001 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1002 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1003 // originated from its child widgets and shouldn't be passed to IM context.
1004 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1005 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1006 // widgets has both IM context and input focus, the event should be filtered
1007 // by gtk_im_context_filter_keypress().
1008 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1009 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1011 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1012 // docs, if IM filter returns true, no further processing should be done.
1013 // we should send the key_down event anyway.
1014 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1015 win
->m_imData
->lastKeyEvent
= NULL
;
1016 if (intercepted_by_IM
)
1018 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1023 if (return_after_IM
)
1029 wxWindowGTK
*ancestor
= win
;
1032 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1035 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1036 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1039 if (ancestor
->IsTopLevel())
1041 ancestor
= ancestor
->GetParent();
1044 #endif // wxUSE_ACCEL
1046 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1047 // will only be sent if it is not in an accelerator table.
1051 KeySym keysym
= gdk_event
->keyval
;
1052 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1053 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1056 if ( wxIsAsciiKeysym(keysym
) )
1059 key_code
= (unsigned char)keysym
;
1061 // gdk_event->string is actually deprecated
1062 else if ( gdk_event
->length
== 1 )
1064 key_code
= (unsigned char)gdk_event
->string
[0];
1070 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1072 event
.m_keyCode
= key_code
;
1074 // To conform to the docs we need to translate Ctrl-alpha
1075 // characters to values in the range 1-26.
1076 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1078 event
.m_keyCode
= key_code
- 'a' + 1;
1080 event
.m_uniChar
= event
.m_keyCode
;
1084 // Implement OnCharHook by checking ancestor top level windows
1085 wxWindow
*parent
= win
;
1086 while (parent
&& !parent
->IsTopLevel())
1087 parent
= parent
->GetParent();
1090 event
.SetEventType( wxEVT_CHAR_HOOK
);
1091 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1096 event
.SetEventType(wxEVT_CHAR
);
1097 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1106 // win is a control: tab can be propagated up
1108 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1109 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1110 // have this style, yet choose not to process this particular TAB in which
1111 // case TAB must still work as a navigational character
1112 // JS: enabling again to make consistent with other platforms
1113 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1114 // navigation behaviour)
1116 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1118 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1120 wxNavigationKeyEvent new_event
;
1121 new_event
.SetEventObject( win
->GetParent() );
1122 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1123 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1124 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1125 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1126 new_event
.SetCurrentFocus( win
);
1127 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1130 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1132 (gdk_event
->keyval
== GDK_Escape
) )
1134 // however only do it if we have a Cancel button in the dialog,
1135 // otherwise the user code may get confused by the events from a
1136 // non-existing button and, worse, a wxButton might get button event
1137 // from another button which is not really expected
1138 wxWindow
*winForCancel
= win
,
1140 while ( winForCancel
)
1142 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1145 // found a cancel button
1149 if ( winForCancel
->IsTopLevel() )
1151 // no need to look further
1155 // maybe our parent has a cancel button?
1156 winForCancel
= winForCancel
->GetParent();
1161 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1162 eventClick
.SetEventObject(btnCancel
);
1163 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1169 g_signal_stop_emission_by_name (widget
, "key_press_event");
1178 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1182 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1184 // take modifiers, cursor position, timestamp etc. from the last
1185 // key_press_event that was fed into Input Method:
1186 if (window
->m_imData
->lastKeyEvent
)
1188 wxFillOtherKeyEventFields(event
,
1189 window
, window
->m_imData
->lastKeyEvent
);
1193 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1195 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1196 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1197 #endif // wxUSE_UNICODE
1198 if( !(const wxChar
*)data
)
1203 // Implement OnCharHook by checking ancestor top level windows
1204 wxWindow
*parent
= window
;
1205 while (parent
&& !parent
->IsTopLevel())
1206 parent
= parent
->GetParent();
1208 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1211 event
.m_uniChar
= *pstr
;
1212 // Backward compatible for ISO-8859-1
1213 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1214 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1216 event
.m_keyCode
= *pstr
;
1217 #endif // wxUSE_UNICODE
1219 // To conform to the docs we need to translate Ctrl-alpha
1220 // characters to values in the range 1-26.
1221 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1223 event
.m_keyCode
= *pstr
- 'a' + 1;
1225 event
.m_uniChar
= event
.m_keyCode
;
1231 event
.SetEventType( wxEVT_CHAR_HOOK
);
1232 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1237 event
.SetEventType(wxEVT_CHAR
);
1238 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1245 //-----------------------------------------------------------------------------
1246 // "key_release_event" from any window
1247 //-----------------------------------------------------------------------------
1250 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1251 GdkEventKey
*gdk_event
,
1257 wxapp_install_idle_handler();
1262 if (g_blockEventsOnDrag
)
1265 wxKeyEvent
event( wxEVT_KEY_UP
);
1266 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1268 // unknown key pressed, ignore (the event would be useless anyhow)
1272 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1275 g_signal_stop_emission_by_name (widget
, "key_release_event");
1280 // ============================================================================
1282 // ============================================================================
1284 // ----------------------------------------------------------------------------
1285 // mouse event processing helpers
1286 // ----------------------------------------------------------------------------
1288 // init wxMouseEvent with the info from GdkEventXXX struct
1289 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1290 wxMouseEvent
& event
,
1293 event
.SetTimestamp( gdk_event
->time
);
1294 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1295 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1296 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1297 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1298 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1299 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1300 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1301 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1303 event
.m_linesPerAction
= 3;
1304 event
.m_wheelDelta
= 120;
1305 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1306 event
.m_wheelRotation
= 120;
1307 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1308 event
.m_wheelRotation
= -120;
1311 wxPoint pt
= win
->GetClientAreaOrigin();
1312 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1313 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1315 event
.SetEventObject( win
);
1316 event
.SetId( win
->GetId() );
1317 event
.SetTimestamp( gdk_event
->time
);
1320 static void AdjustEventButtonState(wxMouseEvent
& event
)
1322 // GDK reports the old state of the button for a button press event, but
1323 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1324 // for a LEFT_DOWN event, not FALSE, so we will invert
1325 // left/right/middleDown for the corresponding click events
1327 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1328 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1329 (event
.GetEventType() == wxEVT_LEFT_UP
))
1331 event
.m_leftDown
= !event
.m_leftDown
;
1335 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1336 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1337 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1339 event
.m_middleDown
= !event
.m_middleDown
;
1343 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1344 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1345 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1347 event
.m_rightDown
= !event
.m_rightDown
;
1352 // find the window to send the mouse event too
1354 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1359 if (win
->m_wxwindow
)
1361 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1362 xx
+= pizza
->xoffset
;
1363 yy
+= pizza
->yoffset
;
1366 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1369 wxWindowGTK
*child
= node
->GetData();
1371 node
= node
->GetNext();
1372 if (!child
->IsShown())
1375 if (child
->IsTransparentForMouse())
1377 // wxStaticBox is transparent in the box itself
1378 int xx1
= child
->m_x
;
1379 int yy1
= child
->m_y
;
1380 int xx2
= child
->m_x
+ child
->m_width
;
1381 int yy2
= child
->m_y
+ child
->m_height
;
1384 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1386 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1388 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1390 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1401 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1402 (child
->m_x
<= xx
) &&
1403 (child
->m_y
<= yy
) &&
1404 (child
->m_x
+child
->m_width
>= xx
) &&
1405 (child
->m_y
+child
->m_height
>= yy
))
1418 //-----------------------------------------------------------------------------
1419 // "button_press_event"
1420 //-----------------------------------------------------------------------------
1423 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1424 GdkEventButton
*gdk_event
,
1430 wxapp_install_idle_handler();
1433 wxPrintf( wxT("1) OnButtonPress from ") );
1434 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1435 wxPrintf( win->GetClassInfo()->GetClassName() );
1436 wxPrintf( wxT(".\n") );
1438 if (!win
->m_hasVMT
) return FALSE
;
1439 if (g_blockEventsOnDrag
) return TRUE
;
1440 if (g_blockEventsOnScroll
) return TRUE
;
1442 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1444 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1446 gtk_widget_grab_focus( win
->m_wxwindow
);
1448 wxPrintf( wxT("GrabFocus from ") );
1449 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1450 wxPrintf( win->GetClassInfo()->GetClassName() );
1451 wxPrintf( wxT(".\n") );
1455 // GDK sends surplus button down events
1456 // before a double click event. We
1457 // need to filter these out.
1458 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1460 GdkEvent
*peek_event
= gdk_event_peek();
1463 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1464 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1466 gdk_event_free( peek_event
);
1471 gdk_event_free( peek_event
);
1476 wxEventType event_type
= wxEVT_NULL
;
1478 // GdkDisplay is a GTK+ 2.2.0 thing
1479 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1480 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1481 !gtk_check_version(2,2,0) &&
1482 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1484 // Reset GDK internal timestamp variables in order to disable GDK
1485 // triple click events. GDK will then next time believe no button has
1486 // been clicked just before, and send a normal button click event.
1487 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1488 display
->button_click_time
[1] = 0;
1489 display
->button_click_time
[0] = 0;
1493 if (gdk_event
->button
== 1)
1495 // note that GDK generates triple click events which are not supported
1496 // by wxWidgets but still have to be passed to the app as otherwise
1497 // clicks would simply go missing
1498 switch (gdk_event
->type
)
1500 // we shouldn't get triple clicks at all for GTK2 because we
1501 // suppress them artificially using the code above but we still
1502 // should map them to something for GTK1 and not just ignore them
1503 // as this would lose clicks
1504 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1505 case GDK_BUTTON_PRESS
:
1506 event_type
= wxEVT_LEFT_DOWN
;
1509 case GDK_2BUTTON_PRESS
:
1510 event_type
= wxEVT_LEFT_DCLICK
;
1514 // just to silence gcc warnings
1518 else if (gdk_event
->button
== 2)
1520 switch (gdk_event
->type
)
1522 case GDK_3BUTTON_PRESS
:
1523 case GDK_BUTTON_PRESS
:
1524 event_type
= wxEVT_MIDDLE_DOWN
;
1527 case GDK_2BUTTON_PRESS
:
1528 event_type
= wxEVT_MIDDLE_DCLICK
;
1535 else if (gdk_event
->button
== 3)
1537 switch (gdk_event
->type
)
1539 case GDK_3BUTTON_PRESS
:
1540 case GDK_BUTTON_PRESS
:
1541 event_type
= wxEVT_RIGHT_DOWN
;
1544 case GDK_2BUTTON_PRESS
:
1545 event_type
= wxEVT_RIGHT_DCLICK
;
1552 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1554 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1556 event_type
= wxEVT_MOUSEWHEEL
;
1560 if ( event_type
== wxEVT_NULL
)
1562 // unknown mouse button or click type
1566 wxMouseEvent
event( event_type
);
1567 InitMouseEvent( win
, event
, gdk_event
);
1569 AdjustEventButtonState(event
);
1571 // wxListBox actually gets mouse events from the item, so we need to give it
1572 // a chance to correct this
1573 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1575 // find the correct window to send the event to: it may be a different one
1576 // from the one which got it at GTK+ level because some controls don't have
1577 // their own X window and thus cannot get any events.
1578 if ( !g_captureWindow
)
1579 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1581 if (win
->GetEventHandler()->ProcessEvent( event
))
1583 g_signal_stop_emission_by_name (widget
, "button_press_event");
1587 if (event_type
== wxEVT_RIGHT_DOWN
)
1589 // generate a "context menu" event: this is similar to right mouse
1590 // click under many GUIs except that it is generated differently
1591 // (right up under MSW, ctrl-click under Mac, right down here) and
1593 // (a) it's a command event and so is propagated to the parent
1594 // (b) under some ports it can be generated from kbd too
1595 // (c) it uses screen coords (because of (a))
1596 wxContextMenuEvent
evtCtx(
1599 win
->ClientToScreen(event
.GetPosition()));
1600 evtCtx
.SetEventObject(win
);
1601 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1608 //-----------------------------------------------------------------------------
1609 // "button_release_event"
1610 //-----------------------------------------------------------------------------
1613 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1614 GdkEventButton
*gdk_event
,
1620 wxapp_install_idle_handler();
1622 if (!win
->m_hasVMT
) return FALSE
;
1623 if (g_blockEventsOnDrag
) return FALSE
;
1624 if (g_blockEventsOnScroll
) return FALSE
;
1626 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1628 wxEventType event_type
= wxEVT_NULL
;
1630 switch (gdk_event
->button
)
1633 event_type
= wxEVT_LEFT_UP
;
1637 event_type
= wxEVT_MIDDLE_UP
;
1641 event_type
= wxEVT_RIGHT_UP
;
1645 // unknwon button, don't process
1649 wxMouseEvent
event( event_type
);
1650 InitMouseEvent( win
, event
, gdk_event
);
1652 AdjustEventButtonState(event
);
1654 // same wxListBox hack as above
1655 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1657 if ( !g_captureWindow
)
1658 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1660 if (win
->GetEventHandler()->ProcessEvent( event
))
1662 g_signal_stop_emission_by_name (widget
, "button_release_event");
1670 //-----------------------------------------------------------------------------
1671 // "motion_notify_event"
1672 //-----------------------------------------------------------------------------
1675 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1676 GdkEventMotion
*gdk_event
,
1682 wxapp_install_idle_handler();
1684 if (!win
->m_hasVMT
) return FALSE
;
1685 if (g_blockEventsOnDrag
) return FALSE
;
1686 if (g_blockEventsOnScroll
) return FALSE
;
1688 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1690 if (gdk_event
->is_hint
)
1694 GdkModifierType state
;
1695 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1701 printf( "OnMotion from " );
1702 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1703 printf( win->GetClassInfo()->GetClassName() );
1707 wxMouseEvent
event( wxEVT_MOTION
);
1708 InitMouseEvent(win
, event
, gdk_event
);
1710 if ( g_captureWindow
)
1712 // synthetize a mouse enter or leave event if needed
1713 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1714 // This seems to be necessary and actually been added to
1715 // GDK itself in version 2.0.X
1718 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1719 if ( hasMouse
!= g_captureWindowHasMouse
)
1721 // the mouse changed window
1722 g_captureWindowHasMouse
= hasMouse
;
1724 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1725 : wxEVT_LEAVE_WINDOW
);
1726 InitMouseEvent(win
, eventM
, gdk_event
);
1727 eventM
.SetEventObject(win
);
1728 win
->GetEventHandler()->ProcessEvent(eventM
);
1733 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1736 if (win
->GetEventHandler()->ProcessEvent( event
))
1738 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1746 //-----------------------------------------------------------------------------
1747 // "mouse_wheel_event"
1748 //-----------------------------------------------------------------------------
1751 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1752 GdkEventScroll
* gdk_event
,
1758 wxapp_install_idle_handler();
1760 wxEventType event_type
= wxEVT_NULL
;
1761 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1762 event_type
= wxEVT_MOUSEWHEEL
;
1763 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1764 event_type
= wxEVT_MOUSEWHEEL
;
1768 wxMouseEvent
event( event_type
);
1769 // Can't use InitMouse macro because scroll events don't have button
1770 event
.SetTimestamp( gdk_event
->time
);
1771 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1772 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1773 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1774 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1775 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1776 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1777 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1778 event
.m_linesPerAction
= 3;
1779 event
.m_wheelDelta
= 120;
1780 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1781 event
.m_wheelRotation
= 120;
1783 event
.m_wheelRotation
= -120;
1785 wxPoint pt
= win
->GetClientAreaOrigin();
1786 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1787 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1789 event
.SetEventObject( win
);
1790 event
.SetId( win
->GetId() );
1791 event
.SetTimestamp( gdk_event
->time
);
1793 if (win
->GetEventHandler()->ProcessEvent( event
))
1795 g_signal_stop_emission_by_name (widget
, "scroll_event");
1803 //-----------------------------------------------------------------------------
1805 //-----------------------------------------------------------------------------
1807 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1809 wxContextMenuEvent
event(
1813 event
.SetEventObject(win
);
1814 return win
->GetEventHandler()->ProcessEvent(event
);
1818 //-----------------------------------------------------------------------------
1820 //-----------------------------------------------------------------------------
1822 // send the wxChildFocusEvent and wxFocusEvent, common code of
1823 // gtk_window_focus_in_callback() and SetFocus()
1824 static bool DoSendFocusEvents(wxWindow
*win
)
1826 // Notify the parent keeping track of focus for the kbd navigation
1827 // purposes that we got it.
1828 wxChildFocusEvent
eventChildFocus(win
);
1829 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1831 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1832 eventFocus
.SetEventObject(win
);
1834 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1838 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1839 GdkEvent
*WXUNUSED(event
),
1845 wxapp_install_idle_handler();
1848 gtk_im_context_focus_in(win
->m_imData
->context
);
1851 g_focusWindow
= win
;
1853 wxLogTrace(TRACE_FOCUS
,
1854 _T("%s: focus in"), win
->GetName().c_str());
1858 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1862 // caret needs to be informed about focus change
1863 wxCaret
*caret
= win
->GetCaret();
1866 caret
->OnSetFocus();
1868 #endif // wxUSE_CARET
1870 // does the window itself think that it has the focus?
1871 if ( !win
->m_hasFocus
)
1873 // not yet, notify it
1874 win
->m_hasFocus
= true;
1876 if ( DoSendFocusEvents(win
) )
1878 g_signal_stop_emission_by_name (widget
, "focus_in_event");
1887 //-----------------------------------------------------------------------------
1888 // "focus_out_event"
1889 //-----------------------------------------------------------------------------
1892 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1897 wxapp_install_idle_handler();
1900 gtk_im_context_focus_out(win
->m_imData
->context
);
1902 wxLogTrace( TRACE_FOCUS
,
1903 _T("%s: focus out"), win
->GetName().c_str() );
1906 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1910 g_focusWindow
= (wxWindowGTK
*)NULL
;
1918 // caret needs to be informed about focus change
1919 wxCaret
*caret
= win
->GetCaret();
1922 caret
->OnKillFocus();
1924 #endif // wxUSE_CARET
1926 // don't send the window a kill focus event if it thinks that it doesn't
1927 // have focus already
1928 if ( win
->m_hasFocus
)
1930 win
->m_hasFocus
= false;
1932 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1933 event
.SetEventObject( win
);
1935 // even if we did process the event in wx code, still let GTK itself
1936 // process it too as otherwise bad things happen, especially in GTK2
1937 // where the text control simply aborts the program if it doesn't get
1938 // the matching focus out event
1939 (void)win
->GetEventHandler()->ProcessEvent( event
);
1946 //-----------------------------------------------------------------------------
1947 // "enter_notify_event"
1948 //-----------------------------------------------------------------------------
1952 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1953 GdkEventCrossing
*gdk_event
,
1959 wxapp_install_idle_handler();
1961 if (!win
->m_hasVMT
) return FALSE
;
1962 if (g_blockEventsOnDrag
) return FALSE
;
1964 // Event was emitted after a grab
1965 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1967 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1971 GdkModifierType state
= (GdkModifierType
)0;
1973 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1975 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1976 InitMouseEvent(win
, event
, gdk_event
);
1977 wxPoint pt
= win
->GetClientAreaOrigin();
1978 event
.m_x
= x
+ pt
.x
;
1979 event
.m_y
= y
+ pt
.y
;
1981 if (win
->GetEventHandler()->ProcessEvent( event
))
1983 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
1991 //-----------------------------------------------------------------------------
1992 // "leave_notify_event"
1993 //-----------------------------------------------------------------------------
1996 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2001 wxapp_install_idle_handler();
2003 if (!win
->m_hasVMT
) return FALSE
;
2004 if (g_blockEventsOnDrag
) return FALSE
;
2006 // Event was emitted after an ungrab
2007 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2009 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2011 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2012 event
.SetTimestamp( gdk_event
->time
);
2013 event
.SetEventObject( win
);
2017 GdkModifierType state
= (GdkModifierType
)0;
2019 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2021 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2022 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2023 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2024 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2025 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2026 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2027 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2029 wxPoint pt
= win
->GetClientAreaOrigin();
2030 event
.m_x
= x
+ pt
.x
;
2031 event
.m_y
= y
+ pt
.y
;
2033 if (win
->GetEventHandler()->ProcessEvent( event
))
2035 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2043 //-----------------------------------------------------------------------------
2044 // "value_changed" from m_vAdjust
2045 //-----------------------------------------------------------------------------
2048 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2054 wxapp_install_idle_handler();
2056 if (g_blockEventsOnDrag
) return;
2058 if (!win
->m_hasVMT
) return;
2060 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2061 if (fabs(diff
) < 0.2) return;
2063 win
->m_oldVerticalPos
= adjust
->value
;
2065 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2067 int value
= (int)(adjust
->value
+0.5);
2069 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2070 event
.SetEventObject( win
);
2071 win
->GetEventHandler()->ProcessEvent( event
);
2075 //-----------------------------------------------------------------------------
2076 // "value_changed" from m_hAdjust
2077 //-----------------------------------------------------------------------------
2080 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2086 wxapp_install_idle_handler();
2088 if (g_blockEventsOnDrag
) return;
2089 if (!win
->m_hasVMT
) return;
2091 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2092 if (fabs(diff
) < 0.2) return;
2094 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2096 win
->m_oldHorizontalPos
= adjust
->value
;
2098 int value
= (int)(adjust
->value
+0.5);
2100 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2101 event
.SetEventObject( win
);
2102 win
->GetEventHandler()->ProcessEvent( event
);
2106 //-----------------------------------------------------------------------------
2107 // "button_press_event" from scrollbar
2108 //-----------------------------------------------------------------------------
2111 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2112 GdkEventButton
*gdk_event
,
2118 wxapp_install_idle_handler();
2121 g_blockEventsOnScroll
= true;
2123 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2125 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2132 //-----------------------------------------------------------------------------
2133 // "button_release_event" from scrollbar
2134 //-----------------------------------------------------------------------------
2137 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2138 GdkEventButton
*WXUNUSED(gdk_event
),
2143 // don't test here as we can release the mouse while being over
2144 // a different window than the slider
2146 // if (gdk_event->window != widget->slider) return FALSE;
2148 g_blockEventsOnScroll
= false;
2150 if (win
->m_isScrolling
)
2152 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2156 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2157 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2159 value
= (int)(win
->m_hAdjust
->value
+0.5);
2162 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2164 value
= (int)(win
->m_vAdjust
->value
+0.5);
2168 wxScrollWinEvent
event( command
, value
, dir
);
2169 event
.SetEventObject( win
);
2170 win
->GetEventHandler()->ProcessEvent( event
);
2173 win
->m_isScrolling
= false;
2179 // ----------------------------------------------------------------------------
2180 // this wxWindowBase function is implemented here (in platform-specific file)
2181 // because it is static and so couldn't be made virtual
2182 // ----------------------------------------------------------------------------
2184 wxWindow
*wxWindowBase::DoFindFocus()
2186 // the cast is necessary when we compile in wxUniversal mode
2187 return (wxWindow
*)g_focusWindow
;
2190 //-----------------------------------------------------------------------------
2191 // "realize" from m_widget
2192 //-----------------------------------------------------------------------------
2194 /* We cannot set colours and fonts before the widget has
2195 been realized, so we do this directly after realization. */
2199 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2204 wxapp_install_idle_handler();
2208 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2209 gtk_im_context_set_client_window( win
->m_imData
->context
,
2210 pizza
->bin_window
);
2213 wxWindowCreateEvent
event( win
);
2214 event
.SetEventObject( win
);
2215 win
->GetEventHandler()->ProcessEvent( event
);
2221 //-----------------------------------------------------------------------------
2223 //-----------------------------------------------------------------------------
2227 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2228 GtkAllocation
*WXUNUSED(alloc
),
2232 wxapp_install_idle_handler();
2234 if (!win
->m_hasScrolling
) return;
2236 int client_width
= 0;
2237 int client_height
= 0;
2238 win
->GetClientSize( &client_width
, &client_height
);
2239 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2242 win
->m_oldClientWidth
= client_width
;
2243 win
->m_oldClientHeight
= client_height
;
2245 if (!win
->m_nativeSizeEvent
)
2247 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2248 event
.SetEventObject( win
);
2249 win
->GetEventHandler()->ProcessEvent( event
);
2256 #define WXUNUSED_UNLESS_XIM(param) param
2258 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2261 /* Resize XIM window */
2265 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2266 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2267 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2270 wxapp_install_idle_handler();
2276 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2280 gdk_window_get_size (widget
->window
, &width
, &height
);
2281 win
->m_icattr
->preedit_area
.width
= width
;
2282 win
->m_icattr
->preedit_area
.height
= height
;
2283 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2289 //-----------------------------------------------------------------------------
2290 // "realize" from m_wxwindow
2291 //-----------------------------------------------------------------------------
2293 /* Initialize XIM support */
2297 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2298 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2301 wxapp_install_idle_handler();
2304 if (win
->m_ic
) return FALSE
;
2305 if (!widget
) return FALSE
;
2306 if (!gdk_im_ready()) return FALSE
;
2308 win
->m_icattr
= gdk_ic_attr_new();
2309 if (!win
->m_icattr
) return FALSE
;
2313 GdkColormap
*colormap
;
2314 GdkICAttr
*attr
= win
->m_icattr
;
2315 unsigned attrmask
= GDK_IC_ALL_REQ
;
2317 GdkIMStyle supported_style
= (GdkIMStyle
)
2318 (GDK_IM_PREEDIT_NONE
|
2319 GDK_IM_PREEDIT_NOTHING
|
2320 GDK_IM_PREEDIT_POSITION
|
2321 GDK_IM_STATUS_NONE
|
2322 GDK_IM_STATUS_NOTHING
);
2324 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2325 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2327 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2328 attr
->client_window
= widget
->window
;
2330 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2331 gtk_widget_get_default_colormap ())
2333 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2334 attr
->preedit_colormap
= colormap
;
2337 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2338 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2339 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2340 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2342 switch (style
& GDK_IM_PREEDIT_MASK
)
2344 case GDK_IM_PREEDIT_POSITION
:
2345 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2347 g_warning ("over-the-spot style requires fontset");
2351 gdk_window_get_size (widget
->window
, &width
, &height
);
2353 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2354 attr
->spot_location
.x
= 0;
2355 attr
->spot_location
.y
= height
;
2356 attr
->preedit_area
.x
= 0;
2357 attr
->preedit_area
.y
= 0;
2358 attr
->preedit_area
.width
= width
;
2359 attr
->preedit_area
.height
= height
;
2360 attr
->preedit_fontset
= widget
->style
->font
;
2365 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2367 if (win
->m_ic
== NULL
)
2368 g_warning ("Can't create input context.");
2371 mask
= gdk_window_get_events (widget
->window
);
2372 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2373 gdk_window_set_events (widget
->window
, mask
);
2375 if (GTK_WIDGET_HAS_FOCUS(widget
))
2376 gdk_im_begin (win
->m_ic
, widget
->window
);
2384 //-----------------------------------------------------------------------------
2385 // InsertChild for wxWindowGTK.
2386 //-----------------------------------------------------------------------------
2388 /* Callback for wxWindowGTK. This very strange beast has to be used because
2389 * C++ has no virtual methods in a constructor. We have to emulate a
2390 * virtual function here as wxNotebook requires a different way to insert
2391 * a child in it. I had opted for creating a wxNotebookPage window class
2392 * which would have made this superfluous (such in the MDI window system),
2393 * but no-one was listening to me... */
2395 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2397 /* the window might have been scrolled already, do we
2398 have to adapt the position */
2399 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2400 child
->m_x
+= pizza
->xoffset
;
2401 child
->m_y
+= pizza
->yoffset
;
2403 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2404 GTK_WIDGET(child
->m_widget
),
2411 //-----------------------------------------------------------------------------
2413 //-----------------------------------------------------------------------------
2415 wxWindow
*wxGetActiveWindow()
2417 return wxWindow::FindFocus();
2421 wxMouseState
wxGetMouseState()
2427 GdkModifierType mask
;
2429 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2433 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2434 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2435 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2437 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2438 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2439 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2440 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2445 //-----------------------------------------------------------------------------
2447 //-----------------------------------------------------------------------------
2449 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2451 #ifdef __WXUNIVERSAL__
2452 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2454 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2455 #endif // __WXUNIVERSAL__/__WXGTK__
2457 void wxWindowGTK::Init()
2460 m_widget
= (GtkWidget
*) NULL
;
2461 m_wxwindow
= (GtkWidget
*) NULL
;
2462 m_focusWidget
= (GtkWidget
*) NULL
;
2472 m_needParent
= true;
2473 m_isBeingDeleted
= false;
2476 m_nativeSizeEvent
= false;
2478 m_hasScrolling
= false;
2479 m_isScrolling
= false;
2481 m_hAdjust
= (GtkAdjustment
*) NULL
;
2482 m_vAdjust
= (GtkAdjustment
*) NULL
;
2483 m_oldHorizontalPos
=
2484 m_oldVerticalPos
= 0.0;
2486 m_oldClientHeight
= 0;
2490 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2492 m_acceptsFocus
= false;
2495 m_clipPaintRegion
= false;
2497 m_needsStyleChange
= false;
2499 m_cursor
= *wxSTANDARD_CURSOR
;
2502 m_dirtyTabOrder
= false;
2505 wxWindowGTK::wxWindowGTK()
2510 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2515 const wxString
&name
)
2519 Create( parent
, id
, pos
, size
, style
, name
);
2522 bool wxWindowGTK::Create( wxWindow
*parent
,
2527 const wxString
&name
)
2529 if (!PreCreation( parent
, pos
, size
) ||
2530 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2532 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2536 m_insertCallback
= wxInsertChildInWindow
;
2538 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2539 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2541 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2543 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2544 scroll_class
->scrollbar_spacing
= 0;
2546 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2548 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2549 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2551 m_wxwindow
= gtk_pizza_new();
2553 #ifndef __WXUNIVERSAL__
2554 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2556 if (HasFlag(wxRAISED_BORDER
))
2558 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2560 else if (HasFlag(wxSUNKEN_BORDER
))
2562 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2564 else if (HasFlag(wxSIMPLE_BORDER
))
2566 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2570 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2572 #endif // __WXUNIVERSAL__
2574 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2576 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2577 m_acceptsFocus
= true;
2579 // I _really_ don't want scrollbars in the beginning
2580 m_vAdjust
->lower
= 0.0;
2581 m_vAdjust
->upper
= 1.0;
2582 m_vAdjust
->value
= 0.0;
2583 m_vAdjust
->step_increment
= 1.0;
2584 m_vAdjust
->page_increment
= 1.0;
2585 m_vAdjust
->page_size
= 5.0;
2586 g_signal_emit_by_name (m_vAdjust
, "changed");
2587 m_hAdjust
->lower
= 0.0;
2588 m_hAdjust
->upper
= 1.0;
2589 m_hAdjust
->value
= 0.0;
2590 m_hAdjust
->step_increment
= 1.0;
2591 m_hAdjust
->page_increment
= 1.0;
2592 m_hAdjust
->page_size
= 5.0;
2593 g_signal_emit_by_name (m_hAdjust
, "changed");
2595 // these handlers block mouse events to any window during scrolling such as
2596 // motion events and prevent GTK and wxWidgets from fighting over where the
2598 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2599 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2600 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2601 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2602 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2603 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2604 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2605 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2607 // these handlers get notified when screen updates are required either when
2608 // scrolling or when the window size (and therefore scrollbar configuration)
2611 g_signal_connect (m_hAdjust
, "value_changed",
2612 G_CALLBACK (gtk_window_hscroll_callback
), this);
2613 g_signal_connect (m_vAdjust
, "value_changed",
2614 G_CALLBACK (gtk_window_vscroll_callback
), this);
2616 gtk_widget_show( m_wxwindow
);
2619 m_parent
->DoAddChild( this );
2621 m_focusWidget
= m_wxwindow
;
2628 wxWindowGTK::~wxWindowGTK()
2632 if (g_focusWindow
== this)
2633 g_focusWindow
= NULL
;
2635 if ( g_delayedFocus
== this )
2636 g_delayedFocus
= NULL
;
2638 m_isBeingDeleted
= true;
2641 // destroy children before destroying this window itself
2644 // unhook focus handlers to prevent stray events being
2645 // propagated to this (soon to be) dead object
2646 if (m_focusWidget
!= NULL
)
2648 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2649 (gpointer
) gtk_window_focus_in_callback
,
2651 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2652 (gpointer
) gtk_window_focus_out_callback
,
2661 gdk_ic_destroy (m_ic
);
2663 gdk_ic_attr_destroy (m_icattr
);
2666 // delete before the widgets to avoid a crash on solaris
2671 gtk_widget_destroy( m_wxwindow
);
2672 m_wxwindow
= (GtkWidget
*) NULL
;
2677 gtk_widget_destroy( m_widget
);
2678 m_widget
= (GtkWidget
*) NULL
;
2682 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2684 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2686 // Use either the given size, or the default if -1 is given.
2687 // See wxWindowBase for these functions.
2688 m_width
= WidthDefault(size
.x
) ;
2689 m_height
= HeightDefault(size
.y
);
2697 void wxWindowGTK::PostCreation()
2699 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2705 // these get reported to wxWidgets -> wxPaintEvent
2707 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2709 g_signal_connect (m_wxwindow
, "expose_event",
2710 G_CALLBACK (gtk_window_expose_callback
), this);
2712 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2715 // Create input method handler
2716 m_imData
= new wxGtkIMData
;
2718 // Cannot handle drawing preedited text yet
2719 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2721 g_signal_connect (m_imData
->context
, "commit",
2722 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2724 // these are called when the "sunken" or "raised" borders are drawn
2725 g_signal_connect (m_widget
, "expose_event",
2726 G_CALLBACK (gtk_window_own_expose_callback
), this);
2731 if (!GTK_IS_WINDOW(m_widget
))
2733 if (m_focusWidget
== NULL
)
2734 m_focusWidget
= m_widget
;
2736 g_signal_connect (m_focusWidget
, "focus_in_event",
2737 G_CALLBACK (gtk_window_focus_in_callback
), this);
2738 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2739 G_CALLBACK (gtk_window_focus_out_callback
), this);
2742 // connect to the various key and mouse handlers
2744 GtkWidget
*connect_widget
= GetConnectWidget();
2746 ConnectWidget( connect_widget
);
2748 /* We cannot set colours, fonts and cursors before the widget has
2749 been realized, so we do this directly after realization */
2750 g_signal_connect (connect_widget
, "realize",
2751 G_CALLBACK (gtk_window_realized_callback
), this);
2755 // Catch native resize events
2756 g_signal_connect (m_wxwindow
, "size_allocate",
2757 G_CALLBACK (gtk_window_size_callback
), this);
2759 // Initialize XIM support
2760 g_signal_connect (m_wxwindow
, "realize",
2761 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2763 // And resize XIM window
2764 g_signal_connect (m_wxwindow
, "size_allocate",
2765 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2768 if (GTK_IS_COMBO(m_widget
))
2770 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2772 g_signal_connect (gcombo
->entry
, "size_request",
2773 G_CALLBACK (wxgtk_combo_size_request_callback
),
2778 // This is needed if we want to add our windows into native
2779 // GTK controls, such as the toolbar. With this callback, the
2780 // toolbar gets to know the correct size (the one set by the
2781 // programmer). Sadly, it misbehaves for wxComboBox.
2782 g_signal_connect (m_widget
, "size_request",
2783 G_CALLBACK (wxgtk_window_size_request_callback
),
2787 InheritAttributes();
2791 // unless the window was created initially hidden (i.e. Hide() had been
2792 // called before Create()), we should show it at GTK+ level as well
2794 gtk_widget_show( m_widget
);
2797 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2799 g_signal_connect (widget
, "key_press_event",
2800 G_CALLBACK (gtk_window_key_press_callback
), this);
2801 g_signal_connect (widget
, "key_release_event",
2802 G_CALLBACK (gtk_window_key_release_callback
), this);
2803 g_signal_connect (widget
, "button_press_event",
2804 G_CALLBACK (gtk_window_button_press_callback
), this);
2805 g_signal_connect (widget
, "button_release_event",
2806 G_CALLBACK (gtk_window_button_release_callback
), this);
2807 g_signal_connect (widget
, "motion_notify_event",
2808 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2809 g_signal_connect (widget
, "scroll_event",
2810 G_CALLBACK (gtk_window_wheel_callback
), this);
2811 g_signal_connect (widget
, "popup_menu",
2812 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2813 g_signal_connect (widget
, "enter_notify_event",
2814 G_CALLBACK (gtk_window_enter_callback
), this);
2815 g_signal_connect (widget
, "leave_notify_event",
2816 G_CALLBACK (gtk_window_leave_callback
), this);
2819 bool wxWindowGTK::Destroy()
2821 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2825 return wxWindowBase::Destroy();
2828 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2830 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2833 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2835 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2836 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2839 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2842 if (m_resizing
) return; /* I don't like recursions */
2845 int currentX
, currentY
;
2846 GetPosition(¤tX
, ¤tY
);
2847 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2849 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2851 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2853 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2855 /* don't set the size for children of wxNotebook, just take the values. */
2863 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2864 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2866 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2867 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2871 m_x
= x
+ pizza
->xoffset
;
2872 m_y
= y
+ pizza
->yoffset
;
2875 // calculate the best size if we should auto size the window
2876 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2877 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2879 const wxSize sizeBest
= GetBestSize();
2880 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2882 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2883 height
= sizeBest
.y
;
2891 int minWidth
= GetMinWidth(),
2892 minHeight
= GetMinHeight(),
2893 maxWidth
= GetMaxWidth(),
2894 maxHeight
= GetMaxHeight();
2896 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2897 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2898 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2899 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2901 int left_border
= 0;
2902 int right_border
= 0;
2904 int bottom_border
= 0;
2906 /* the default button has a border around it */
2907 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2909 GtkBorder
*default_border
= NULL
;
2910 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2913 left_border
+= default_border
->left
;
2914 right_border
+= default_border
->right
;
2915 top_border
+= default_border
->top
;
2916 bottom_border
+= default_border
->bottom
;
2917 g_free( default_border
);
2921 DoMoveWindow( m_x
-top_border
,
2923 m_width
+left_border
+right_border
,
2924 m_height
+top_border
+bottom_border
);
2929 /* Sometimes the client area changes size without the
2930 whole windows's size changing, but if the whole
2931 windows's size doesn't change, no wxSizeEvent will
2932 normally be sent. Here we add an extra test if
2933 the client test has been changed and this will
2935 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2939 wxPrintf( "OnSize sent from " );
2940 if (GetClassInfo() && GetClassInfo()->GetClassName())
2941 wxPrintf( GetClassInfo()->GetClassName() );
2942 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2945 if (!m_nativeSizeEvent
)
2947 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2948 event
.SetEventObject( this );
2949 GetEventHandler()->ProcessEvent( event
);
2955 void wxWindowGTK::OnInternalIdle()
2957 if ( m_dirtyTabOrder
)
2959 m_dirtyTabOrder
= false;
2963 // Update style if the window was not yet realized
2964 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2965 if (m_needsStyleChange
)
2967 SetBackgroundStyle(GetBackgroundStyle());
2968 m_needsStyleChange
= false;
2971 // Update invalidated regions.
2974 wxCursor cursor
= m_cursor
;
2975 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2979 /* I now set the cursor anew in every OnInternalIdle call
2980 as setting the cursor in a parent window also effects the
2981 windows above so that checking for the current cursor is
2986 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2988 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2990 if (!g_globalCursor
.Ok())
2991 cursor
= *wxSTANDARD_CURSOR
;
2993 window
= m_widget
->window
;
2994 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2995 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3001 GdkWindow
*window
= m_widget
->window
;
3002 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3003 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3008 if (wxUpdateUIEvent::CanUpdate(this))
3009 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3012 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3014 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3016 if (width
) (*width
) = m_width
;
3017 if (height
) (*height
) = m_height
;
3020 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3022 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3026 SetSize( width
, height
);
3033 #ifndef __WXUNIVERSAL__
3034 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3036 /* when using GTK 1.2 we set the shadow border size to 2 */
3040 if (HasFlag(wxSIMPLE_BORDER
))
3042 /* when using GTK 1.2 we set the simple border size to 1 */
3046 #endif // __WXUNIVERSAL__
3050 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3052 GtkRequisition vscroll_req
;
3053 vscroll_req
.width
= 2;
3054 vscroll_req
.height
= 2;
3055 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3056 (scroll_window
->vscrollbar
, &vscroll_req
);
3058 GtkRequisition hscroll_req
;
3059 hscroll_req
.width
= 2;
3060 hscroll_req
.height
= 2;
3061 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3062 (scroll_window
->hscrollbar
, &hscroll_req
);
3064 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3066 if (scroll_window
->vscrollbar_visible
)
3068 dw
+= vscroll_req
.width
;
3069 dw
+= scroll_class
->scrollbar_spacing
;
3072 if (scroll_window
->hscrollbar_visible
)
3074 dh
+= hscroll_req
.height
;
3075 dh
+= scroll_class
->scrollbar_spacing
;
3079 SetSize( width
+dw
, height
+dh
);
3083 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3085 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3089 if (width
) (*width
) = m_width
;
3090 if (height
) (*height
) = m_height
;
3097 #ifndef __WXUNIVERSAL__
3098 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3100 /* when using GTK 1.2 we set the shadow border size to 2 */
3104 if (HasFlag(wxSIMPLE_BORDER
))
3106 /* when using GTK 1.2 we set the simple border size to 1 */
3110 #endif // __WXUNIVERSAL__
3114 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3116 GtkRequisition vscroll_req
;
3117 vscroll_req
.width
= 2;
3118 vscroll_req
.height
= 2;
3119 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3120 (scroll_window
->vscrollbar
, &vscroll_req
);
3122 GtkRequisition hscroll_req
;
3123 hscroll_req
.width
= 2;
3124 hscroll_req
.height
= 2;
3125 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3126 (scroll_window
->hscrollbar
, &hscroll_req
);
3128 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3130 if (scroll_window
->vscrollbar_visible
)
3132 dw
+= vscroll_req
.width
;
3133 dw
+= scroll_class
->scrollbar_spacing
;
3136 if (scroll_window
->hscrollbar_visible
)
3138 dh
+= hscroll_req
.height
;
3139 dh
+= scroll_class
->scrollbar_spacing
;
3143 if (width
) (*width
) = m_width
- dw
;
3144 if (height
) (*height
) = m_height
- dh
;
3148 printf( "GetClientSize, name %s ", GetName().c_str() );
3149 if (width) printf( " width = %d", (*width) );
3150 if (height) printf( " height = %d", (*height) );
3155 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3157 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3161 if (m_parent
&& m_parent
->m_wxwindow
)
3163 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3164 dx
= pizza
->xoffset
;
3165 dy
= pizza
->yoffset
;
3168 if (x
) (*x
) = m_x
- dx
;
3169 if (y
) (*y
) = m_y
- dy
;
3172 void wxWindowGTK::DoClientToScreen( 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 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3203 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3205 if (!m_widget
->window
) return;
3207 GdkWindow
*source
= (GdkWindow
*) NULL
;
3209 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3211 source
= m_widget
->window
;
3215 gdk_window_get_origin( source
, &org_x
, &org_y
);
3219 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3221 org_x
+= m_widget
->allocation
.x
;
3222 org_y
+= m_widget
->allocation
.y
;
3230 bool wxWindowGTK::Show( bool show
)
3232 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3234 if (!wxWindowBase::Show(show
))
3241 gtk_widget_show( m_widget
);
3243 gtk_widget_hide( m_widget
);
3245 wxShowEvent
eventShow(GetId(), show
);
3246 eventShow
.SetEventObject(this);
3248 GetEventHandler()->ProcessEvent(eventShow
);
3253 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3255 win
->OnParentEnable(enable
);
3257 // Recurse, so that children have the opportunity to Do The Right Thing
3258 // and reset colours that have been messed up by a parent's (really ancestor's)
3260 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3262 node
= node
->GetNext() )
3264 wxWindow
*child
= node
->GetData();
3265 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3266 wxWindowNotifyEnable(child
, enable
);
3270 bool wxWindowGTK::Enable( bool enable
)
3272 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3274 if (!wxWindowBase::Enable(enable
))
3280 gtk_widget_set_sensitive( m_widget
, enable
);
3282 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3284 wxWindowNotifyEnable(this, enable
);
3289 int wxWindowGTK::GetCharHeight() const
3291 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3293 wxFont font
= GetFont();
3294 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3296 PangoContext
*context
= NULL
;
3298 context
= gtk_widget_get_pango_context( m_widget
);
3303 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3304 PangoLayout
*layout
= pango_layout_new(context
);
3305 pango_layout_set_font_description(layout
, desc
);
3306 pango_layout_set_text(layout
, "H", 1);
3307 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3309 PangoRectangle rect
;
3310 pango_layout_line_get_extents(line
, NULL
, &rect
);
3312 g_object_unref( G_OBJECT( layout
) );
3314 return (int) PANGO_PIXELS(rect
.height
);
3317 int wxWindowGTK::GetCharWidth() const
3319 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3321 wxFont font
= GetFont();
3322 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3324 PangoContext
*context
= NULL
;
3326 context
= gtk_widget_get_pango_context( m_widget
);
3331 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3332 PangoLayout
*layout
= pango_layout_new(context
);
3333 pango_layout_set_font_description(layout
, desc
);
3334 pango_layout_set_text(layout
, "g", 1);
3335 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3337 PangoRectangle rect
;
3338 pango_layout_line_get_extents(line
, NULL
, &rect
);
3340 g_object_unref( G_OBJECT( layout
) );
3342 return (int) PANGO_PIXELS(rect
.width
);
3345 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3349 int *externalLeading
,
3350 const wxFont
*theFont
) const
3352 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3354 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3363 PangoContext
*context
= NULL
;
3365 context
= gtk_widget_get_pango_context( m_widget
);
3374 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3375 PangoLayout
*layout
= pango_layout_new(context
);
3376 pango_layout_set_font_description(layout
, desc
);
3379 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3380 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3382 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3383 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3384 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3388 PangoRectangle rect
;
3389 pango_layout_get_extents(layout
, NULL
, &rect
);
3391 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3392 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3395 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3396 int baseline
= pango_layout_iter_get_baseline(iter
);
3397 pango_layout_iter_free(iter
);
3398 *descent
= *y
- PANGO_PIXELS(baseline
);
3400 if (externalLeading
) (*externalLeading
) = 0; // ??
3402 g_object_unref( G_OBJECT( layout
) );
3405 void wxWindowGTK::SetFocus()
3407 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3410 // don't do anything if we already have focus
3416 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3418 gtk_widget_grab_focus (m_wxwindow
);
3423 if (GTK_IS_CONTAINER(m_widget
))
3425 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3428 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3431 if (!GTK_WIDGET_REALIZED(m_widget
))
3433 // we can't set the focus to the widget now so we remember that
3434 // it should be focused and will do it later, during the idle
3435 // time, as soon as we can
3436 wxLogTrace(TRACE_FOCUS
,
3437 _T("Delaying setting focus to %s(%s)"),
3438 GetClassInfo()->GetClassName(), GetLabel().c_str());
3440 g_delayedFocus
= this;
3444 wxLogTrace(TRACE_FOCUS
,
3445 _T("Setting focus to %s(%s)"),
3446 GetClassInfo()->GetClassName(), GetLabel().c_str());
3448 gtk_widget_grab_focus (m_widget
);
3453 wxLogTrace(TRACE_FOCUS
,
3454 _T("Can't set focus to %s(%s)"),
3455 GetClassInfo()->GetClassName(), GetLabel().c_str());
3460 bool wxWindowGTK::AcceptsFocus() const
3462 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3465 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3467 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3469 wxWindowGTK
*oldParent
= m_parent
,
3470 *newParent
= (wxWindowGTK
*)newParentBase
;
3472 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3474 if ( !wxWindowBase::Reparent(newParent
) )
3477 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3479 /* prevent GTK from deleting the widget arbitrarily */
3480 gtk_widget_ref( m_widget
);
3484 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3487 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3491 /* insert GTK representation */
3492 (*(newParent
->m_insertCallback
))(newParent
, this);
3495 /* reverse: prevent GTK from deleting the widget arbitrarily */
3496 gtk_widget_unref( m_widget
);
3501 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3503 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3505 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3507 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3512 /* insert GTK representation */
3513 (*m_insertCallback
)(this, child
);
3516 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3518 wxWindowBase::AddChild(child
);
3519 m_dirtyTabOrder
= true;
3521 wxapp_install_idle_handler();
3524 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3526 wxWindowBase::RemoveChild(child
);
3527 m_dirtyTabOrder
= true;
3529 wxapp_install_idle_handler();
3532 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3534 wxWindowBase::DoMoveInTabOrder(win
, move
);
3535 m_dirtyTabOrder
= true;
3537 wxapp_install_idle_handler();
3540 void wxWindowGTK::RealizeTabOrder()
3544 if ( !m_children
.empty() )
3547 // we don't only construct the correct focus chain but also use
3548 // this opportunity to update the mnemonic widgets for all labels
3550 // it would be nice to extract this code from here and put it in
3551 // stattext.cpp to reduce dependencies but there is no really easy
3552 // way to do it unfortunately
3553 wxStaticText
*lastLabel
= NULL
;
3554 #endif // wxUSE_STATTEXT
3556 GList
*chain
= NULL
;
3558 for ( wxWindowList::const_iterator i
= m_children
.begin();
3559 i
!= m_children
.end();
3562 wxWindowGTK
*win
= *i
;
3566 if ( win
->AcceptsFocusFromKeyboard() )
3568 GtkLabel
*l
= GTK_LABEL(lastLabel
->m_widget
);
3569 gtk_label_set_mnemonic_widget(l
, win
->m_widget
);
3573 else // check if this one is a label
3575 lastLabel
= wxDynamicCast(win
, wxStaticText
);
3577 #endif // wxUSE_STATTEXT
3579 chain
= g_list_prepend(chain
, win
->m_widget
);
3582 chain
= g_list_reverse(chain
);
3584 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3589 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3594 void wxWindowGTK::Raise()
3596 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3598 if (m_wxwindow
&& m_wxwindow
->window
)
3600 gdk_window_raise( m_wxwindow
->window
);
3602 else if (m_widget
->window
)
3604 gdk_window_raise( m_widget
->window
);
3608 void wxWindowGTK::Lower()
3610 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3612 if (m_wxwindow
&& m_wxwindow
->window
)
3614 gdk_window_lower( m_wxwindow
->window
);
3616 else if (m_widget
->window
)
3618 gdk_window_lower( m_widget
->window
);
3622 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3624 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3626 if (cursor
== m_cursor
)
3630 wxapp_install_idle_handler();
3632 if (cursor
== wxNullCursor
)
3633 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3635 return wxWindowBase::SetCursor( cursor
);
3638 void wxWindowGTK::WarpPointer( int x
, int y
)
3640 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3642 // We provide this function ourselves as it is
3643 // missing in GDK (top of this file).
3645 GdkWindow
*window
= (GdkWindow
*) NULL
;
3647 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3649 window
= GetConnectWidget()->window
;
3652 gdk_window_warp_pointer( window
, x
, y
);
3655 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3657 double value_start
= adj
->value
;
3658 double value
= value_start
+ change
;
3659 double upper
= adj
->upper
- adj
->page_size
;
3664 // Lower bound will be checked by gtk_adjustment_set_value
3665 gtk_adjustment_set_value(adj
, value
);
3666 return adj
->value
!= value_start
;
3669 bool wxWindowGTK::ScrollLines(int lines
)
3672 m_vAdjust
!= NULL
&&
3673 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3676 bool wxWindowGTK::ScrollPages(int pages
)
3679 m_vAdjust
!= NULL
&&
3680 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3683 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3685 wxASSERT(m_vAdjust
== NULL
);
3689 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3693 if (!m_widget
->window
)
3698 GdkRectangle gdk_rect
,
3702 gdk_rect
.x
= rect
->x
;
3703 gdk_rect
.y
= rect
->y
;
3704 gdk_rect
.width
= rect
->width
;
3705 gdk_rect
.height
= rect
->height
;
3708 else // invalidate everything
3713 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3717 void wxWindowGTK::Update()
3721 // when we call Update() we really want to update the window immediately on
3722 // screen, even if it means flushing the entire queue and hence slowing down
3723 // everything -- but it should still be done, it's just that Update() should
3724 // be called very rarely
3728 void wxWindowGTK::GtkUpdate()
3730 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3731 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3733 // for consistency with other platforms (and also because it's convenient
3734 // to be able to update an entire TLW by calling Update() only once), we
3735 // should also update all our children here
3736 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3738 node
= node
->GetNext() )
3740 node
->GetData()->GtkUpdate();
3744 void wxWindowGTK::GtkSendPaintEvents()
3748 m_updateRegion
.Clear();
3752 // Clip to paint region in wxClientDC
3753 m_clipPaintRegion
= true;
3755 // widget to draw on
3756 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3758 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3760 // find ancestor from which to steal background
3761 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3763 parent
= (wxWindow
*)this;
3765 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3767 wxRegionIterator
upd( m_updateRegion
);
3771 rect
.x
= upd
.GetX();
3772 rect
.y
= upd
.GetY();
3773 rect
.width
= upd
.GetWidth();
3774 rect
.height
= upd
.GetHeight();
3776 gtk_paint_flat_box( parent
->m_widget
->style
,
3778 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3792 wxWindowDC
dc( (wxWindow
*)this );
3793 dc
.SetClippingRegion( m_updateRegion
);
3795 wxEraseEvent
erase_event( GetId(), &dc
);
3796 erase_event
.SetEventObject( this );
3798 GetEventHandler()->ProcessEvent(erase_event
);
3801 wxNcPaintEvent
nc_paint_event( GetId() );
3802 nc_paint_event
.SetEventObject( this );
3803 GetEventHandler()->ProcessEvent( nc_paint_event
);
3805 wxPaintEvent
paint_event( GetId() );
3806 paint_event
.SetEventObject( this );
3807 GetEventHandler()->ProcessEvent( paint_event
);
3809 m_clipPaintRegion
= false;
3811 m_updateRegion
.Clear();
3814 void wxWindowGTK::ClearBackground()
3816 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3820 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3822 wxWindowBase::DoSetToolTip(tip
);
3825 m_tooltip
->Apply( (wxWindow
*)this );
3828 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3830 wxString
tmp( tip
);
3831 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3833 #endif // wxUSE_TOOLTIPS
3835 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3837 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3839 if (!wxWindowBase::SetBackgroundColour(colour
))
3844 // We need the pixel value e.g. for background clearing.
3845 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3848 // apply style change (forceStyle=true so that new style is applied
3849 // even if the bg colour changed from valid to wxNullColour)
3850 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3851 ApplyWidgetStyle(true);
3856 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3858 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3860 if (!wxWindowBase::SetForegroundColour(colour
))
3867 // We need the pixel value e.g. for background clearing.
3868 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3871 // apply style change (forceStyle=true so that new style is applied
3872 // even if the bg colour changed from valid to wxNullColour):
3873 ApplyWidgetStyle(true);
3878 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3880 return gtk_widget_get_pango_context( m_widget
);
3883 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3885 // do we need to apply any changes at all?
3888 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3893 GtkRcStyle
*style
= gtk_rc_style_new();
3898 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3901 if ( m_foregroundColour
.Ok() )
3903 GdkColor
*fg
= m_foregroundColour
.GetColor();
3905 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3906 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3908 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3909 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3911 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3912 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3915 if ( m_backgroundColour
.Ok() )
3917 GdkColor
*bg
= m_backgroundColour
.GetColor();
3919 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3920 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3921 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3922 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3924 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3925 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3926 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3927 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3929 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3930 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3931 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3932 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3934 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3935 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3936 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3937 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3943 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3945 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3948 DoApplyWidgetStyle(style
);
3949 gtk_rc_style_unref(style
);
3952 // Style change may affect GTK+'s size calculation:
3953 InvalidateBestSize();
3956 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3959 gtk_widget_modify_style(m_wxwindow
, style
);
3961 gtk_widget_modify_style(m_widget
, style
);
3964 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3966 wxWindowBase::SetBackgroundStyle(style
);
3968 if (style
== wxBG_STYLE_CUSTOM
)
3970 GdkWindow
*window
= (GdkWindow
*) NULL
;
3972 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3974 window
= GetConnectWidget()->window
;
3978 // Make sure GDK/X11 doesn't refresh the window
3980 gdk_window_set_back_pixmap( window
, None
, False
);
3982 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3985 m_needsStyleChange
= false;
3988 // Do in OnIdle, because the window is not yet available
3989 m_needsStyleChange
= true;
3991 // Don't apply widget style, or we get a grey background
3995 // apply style change (forceStyle=true so that new style is applied
3996 // even if the bg colour changed from valid to wxNullColour):
3997 ApplyWidgetStyle(true);
4002 #if wxUSE_DRAG_AND_DROP
4004 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4006 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4008 GtkWidget
*dnd_widget
= GetConnectWidget();
4010 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4012 if (m_dropTarget
) delete m_dropTarget
;
4013 m_dropTarget
= dropTarget
;
4015 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4018 #endif // wxUSE_DRAG_AND_DROP
4020 GtkWidget
* wxWindowGTK::GetConnectWidget()
4022 GtkWidget
*connect_widget
= m_widget
;
4023 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4025 return connect_widget
;
4028 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4031 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4033 return (window
== m_widget
->window
);
4036 bool wxWindowGTK::SetFont( const wxFont
&font
)
4038 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4040 if (!wxWindowBase::SetFont(font
))
4043 // apply style change (forceStyle=true so that new style is applied
4044 // even if the font changed from valid to wxNullFont):
4045 ApplyWidgetStyle(true);
4050 void wxWindowGTK::DoCaptureMouse()
4052 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4054 GdkWindow
*window
= (GdkWindow
*) NULL
;
4056 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4058 window
= GetConnectWidget()->window
;
4060 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4062 wxCursor
* cursor
= & m_cursor
;
4064 cursor
= wxSTANDARD_CURSOR
;
4066 gdk_pointer_grab( window
, FALSE
,
4068 (GDK_BUTTON_PRESS_MASK
|
4069 GDK_BUTTON_RELEASE_MASK
|
4070 GDK_POINTER_MOTION_HINT_MASK
|
4071 GDK_POINTER_MOTION_MASK
),
4073 cursor
->GetCursor(),
4074 (guint32
)GDK_CURRENT_TIME
);
4075 g_captureWindow
= this;
4076 g_captureWindowHasMouse
= true;
4079 void wxWindowGTK::DoReleaseMouse()
4081 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4083 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4085 g_captureWindow
= (wxWindowGTK
*) NULL
;
4087 GdkWindow
*window
= (GdkWindow
*) NULL
;
4089 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4091 window
= GetConnectWidget()->window
;
4096 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4100 wxWindow
*wxWindowBase::GetCapture()
4102 return (wxWindow
*)g_captureWindow
;
4105 bool wxWindowGTK::IsRetained() const
4110 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4111 int range
, bool refresh
)
4113 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4115 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4117 m_hasScrolling
= true;
4119 if (orient
== wxHORIZONTAL
)
4121 float fpos
= (float)pos
;
4122 float frange
= (float)range
;
4123 float fthumb
= (float)thumbVisible
;
4124 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4125 if (fpos
< 0.0) fpos
= 0.0;
4127 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4128 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4130 SetScrollPos( orient
, pos
, refresh
);
4134 m_oldHorizontalPos
= fpos
;
4136 m_hAdjust
->lower
= 0.0;
4137 m_hAdjust
->upper
= frange
;
4138 m_hAdjust
->value
= fpos
;
4139 m_hAdjust
->step_increment
= 1.0;
4140 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4141 m_hAdjust
->page_size
= fthumb
;
4145 float fpos
= (float)pos
;
4146 float frange
= (float)range
;
4147 float fthumb
= (float)thumbVisible
;
4148 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4149 if (fpos
< 0.0) fpos
= 0.0;
4151 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4152 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4154 SetScrollPos( orient
, pos
, refresh
);
4158 m_oldVerticalPos
= fpos
;
4160 m_vAdjust
->lower
= 0.0;
4161 m_vAdjust
->upper
= frange
;
4162 m_vAdjust
->value
= fpos
;
4163 m_vAdjust
->step_increment
= 1.0;
4164 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4165 m_vAdjust
->page_size
= fthumb
;
4168 if (orient
== wxHORIZONTAL
)
4169 g_signal_emit_by_name (m_hAdjust
, "changed");
4171 g_signal_emit_by_name (m_vAdjust
, "changed");
4174 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4176 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4177 gpointer fn
= orient
== wxHORIZONTAL
4178 ? (gpointer
) gtk_window_hscroll_callback
4179 : (gpointer
) gtk_window_vscroll_callback
;
4181 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4182 g_signal_emit_by_name (adj
, "value_changed");
4183 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4186 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4188 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4189 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4191 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4193 float fpos
= (float)pos
;
4194 if (fpos
> adj
->upper
- adj
->page_size
)
4195 fpos
= adj
->upper
- adj
->page_size
;
4198 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4200 if (fabs(fpos
-adj
->value
) < 0.2)
4204 if ( m_wxwindow
->window
)
4209 int wxWindowGTK::GetScrollThumb( int orient
) const
4211 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4213 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4215 if (orient
== wxHORIZONTAL
)
4216 return (int)(m_hAdjust
->page_size
+0.5);
4218 return (int)(m_vAdjust
->page_size
+0.5);
4221 int wxWindowGTK::GetScrollPos( int orient
) const
4223 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4225 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4227 if (orient
== wxHORIZONTAL
)
4228 return (int)(m_hAdjust
->value
+0.5);
4230 return (int)(m_vAdjust
->value
+0.5);
4233 int wxWindowGTK::GetScrollRange( int orient
) const
4235 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4237 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4239 if (orient
== wxHORIZONTAL
)
4240 return (int)(m_hAdjust
->upper
+0.5);
4242 return (int)(m_vAdjust
->upper
+0.5);
4245 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4247 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4249 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4251 // No scrolling requested.
4252 if ((dx
== 0) && (dy
== 0)) return;
4254 m_clipPaintRegion
= true;
4256 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4258 m_clipPaintRegion
= false;
4261 void wxWindowGTK::SetWindowStyleFlag( long style
)
4263 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4264 wxWindowBase::SetWindowStyleFlag(style
);
4267 // Find the wxWindow at the current mouse position, also returning the mouse
4269 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4271 pt
= wxGetMousePosition();
4272 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4276 // Get the current mouse position.
4277 wxPoint
wxGetMousePosition()
4279 /* This crashes when used within wxHelpContext,
4280 so we have to use the X-specific implementation below.
4282 GdkModifierType *mask;
4283 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4285 return wxPoint(x, y);
4289 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4291 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4292 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4293 Window rootReturn
, childReturn
;
4294 int rootX
, rootY
, winX
, winY
;
4295 unsigned int maskReturn
;
4297 XQueryPointer (display
,
4301 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4302 return wxPoint(rootX
, rootY
);
4306 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4307 void wxAddGrab(wxWindow
* window
)
4309 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4312 void wxRemoveGrab(wxWindow
* window
)
4314 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4317 // ----------------------------------------------------------------------------
4319 // ----------------------------------------------------------------------------
4321 class wxWinModule
: public wxModule
4328 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4331 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4333 bool wxWinModule::OnInit()
4335 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4336 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4341 void wxWinModule::OnExit()
4344 gdk_gc_unref( g_eraseGC
);