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 gboolean
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 gboolean ret
= FALSE
;
1872 // does the window itself think that it has the focus?
1873 if ( !win
->m_hasFocus
)
1875 // not yet, notify it
1876 win
->m_hasFocus
= true;
1878 (void)DoSendFocusEvents(win
);
1883 // Disable default focus handling for custom windows
1884 // since the default GTK+ handler issues a repaint
1885 if (win
->m_wxwindow
)
1886 g_signal_stop_emission_by_name (widget
, "focus_in_event");
1892 //-----------------------------------------------------------------------------
1893 // "focus_out_event"
1894 //-----------------------------------------------------------------------------
1897 static gboolean
gtk_window_focus_out_callback( GtkWidget
*widget
,
1898 GdkEventFocus
*gdk_event
,
1904 wxapp_install_idle_handler();
1907 gtk_im_context_focus_out(win
->m_imData
->context
);
1909 wxLogTrace( TRACE_FOCUS
,
1910 _T("%s: focus out"), win
->GetName().c_str() );
1913 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1917 g_focusWindow
= (wxWindowGTK
*)NULL
;
1925 // caret needs to be informed about focus change
1926 wxCaret
*caret
= win
->GetCaret();
1929 caret
->OnKillFocus();
1931 #endif // wxUSE_CARET
1933 gboolean ret
= FALSE
;
1935 // don't send the window a kill focus event if it thinks that it doesn't
1936 // have focus already
1937 if ( win
->m_hasFocus
)
1939 win
->m_hasFocus
= false;
1941 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1942 event
.SetEventObject( win
);
1944 (void)win
->GetEventHandler()->ProcessEvent( event
);
1949 // Disable default focus handling for custom windows
1950 // since the default GTK+ handler issues a repaint
1951 if (win
->m_wxwindow
)
1952 g_signal_stop_emission_by_name (widget
, "focus_out_event");
1958 //-----------------------------------------------------------------------------
1959 // "enter_notify_event"
1960 //-----------------------------------------------------------------------------
1964 gtk_window_enter_callback( GtkWidget
*widget
,
1965 GdkEventCrossing
*gdk_event
,
1971 wxapp_install_idle_handler();
1973 if (!win
->m_hasVMT
) return FALSE
;
1974 if (g_blockEventsOnDrag
) return FALSE
;
1976 // Event was emitted after a grab
1977 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1979 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1983 GdkModifierType state
= (GdkModifierType
)0;
1985 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1987 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1988 InitMouseEvent(win
, event
, gdk_event
);
1989 wxPoint pt
= win
->GetClientAreaOrigin();
1990 event
.m_x
= x
+ pt
.x
;
1991 event
.m_y
= y
+ pt
.y
;
1993 if (win
->GetEventHandler()->ProcessEvent( event
))
1995 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2003 //-----------------------------------------------------------------------------
2004 // "leave_notify_event"
2005 //-----------------------------------------------------------------------------
2009 gtk_window_leave_callback( GtkWidget
*widget
,
2010 GdkEventCrossing
*gdk_event
,
2016 wxapp_install_idle_handler();
2018 if (!win
->m_hasVMT
) return FALSE
;
2019 if (g_blockEventsOnDrag
) return FALSE
;
2021 // Event was emitted after an ungrab
2022 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2024 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2026 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2027 event
.SetTimestamp( gdk_event
->time
);
2028 event
.SetEventObject( win
);
2032 GdkModifierType state
= (GdkModifierType
)0;
2034 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2036 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2037 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2038 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2039 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2040 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2041 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2042 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2044 wxPoint pt
= win
->GetClientAreaOrigin();
2045 event
.m_x
= x
+ pt
.x
;
2046 event
.m_y
= y
+ pt
.y
;
2048 if (win
->GetEventHandler()->ProcessEvent( event
))
2050 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2058 //-----------------------------------------------------------------------------
2059 // "value_changed" from m_vAdjust
2060 //-----------------------------------------------------------------------------
2063 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2069 wxapp_install_idle_handler();
2071 if (g_blockEventsOnDrag
) return;
2073 if (!win
->m_hasVMT
) return;
2075 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2076 if (fabs(diff
) < 0.2) return;
2078 win
->m_oldVerticalPos
= adjust
->value
;
2080 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2082 int value
= (int)(adjust
->value
+0.5);
2084 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2085 event
.SetEventObject( win
);
2086 win
->GetEventHandler()->ProcessEvent( event
);
2090 //-----------------------------------------------------------------------------
2091 // "value_changed" from m_hAdjust
2092 //-----------------------------------------------------------------------------
2095 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2101 wxapp_install_idle_handler();
2103 if (g_blockEventsOnDrag
) return;
2104 if (!win
->m_hasVMT
) return;
2106 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2107 if (fabs(diff
) < 0.2) return;
2109 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2111 win
->m_oldHorizontalPos
= adjust
->value
;
2113 int value
= (int)(adjust
->value
+0.5);
2115 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2116 event
.SetEventObject( win
);
2117 win
->GetEventHandler()->ProcessEvent( event
);
2121 //-----------------------------------------------------------------------------
2122 // "button_press_event" from scrollbar
2123 //-----------------------------------------------------------------------------
2126 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2127 GdkEventButton
*gdk_event
,
2133 wxapp_install_idle_handler();
2136 g_blockEventsOnScroll
= true;
2138 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2140 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2147 //-----------------------------------------------------------------------------
2148 // "button_release_event" from scrollbar
2149 //-----------------------------------------------------------------------------
2152 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2153 GdkEventButton
*WXUNUSED(gdk_event
),
2158 // don't test here as we can release the mouse while being over
2159 // a different window than the slider
2161 // if (gdk_event->window != widget->slider) return FALSE;
2163 g_blockEventsOnScroll
= false;
2165 if (win
->m_isScrolling
)
2167 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2171 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2172 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2174 value
= (int)(win
->m_hAdjust
->value
+0.5);
2177 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2179 value
= (int)(win
->m_vAdjust
->value
+0.5);
2183 wxScrollWinEvent
event( command
, value
, dir
);
2184 event
.SetEventObject( win
);
2185 win
->GetEventHandler()->ProcessEvent( event
);
2188 win
->m_isScrolling
= false;
2194 // ----------------------------------------------------------------------------
2195 // this wxWindowBase function is implemented here (in platform-specific file)
2196 // because it is static and so couldn't be made virtual
2197 // ----------------------------------------------------------------------------
2199 wxWindow
*wxWindowBase::DoFindFocus()
2201 // the cast is necessary when we compile in wxUniversal mode
2202 return (wxWindow
*)g_focusWindow
;
2205 //-----------------------------------------------------------------------------
2206 // "realize" from m_widget
2207 //-----------------------------------------------------------------------------
2209 /* We cannot set colours and fonts before the widget has
2210 been realized, so we do this directly after realization. */
2214 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2219 wxapp_install_idle_handler();
2223 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2224 gtk_im_context_set_client_window( win
->m_imData
->context
,
2225 pizza
->bin_window
);
2228 wxWindowCreateEvent
event( win
);
2229 event
.SetEventObject( win
);
2230 win
->GetEventHandler()->ProcessEvent( event
);
2236 //-----------------------------------------------------------------------------
2238 //-----------------------------------------------------------------------------
2242 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2243 GtkAllocation
*WXUNUSED(alloc
),
2247 wxapp_install_idle_handler();
2249 if (!win
->m_hasScrolling
) return;
2251 int client_width
= 0;
2252 int client_height
= 0;
2253 win
->GetClientSize( &client_width
, &client_height
);
2254 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2257 win
->m_oldClientWidth
= client_width
;
2258 win
->m_oldClientHeight
= client_height
;
2260 if (!win
->m_nativeSizeEvent
)
2262 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2263 event
.SetEventObject( win
);
2264 win
->GetEventHandler()->ProcessEvent( event
);
2271 #define WXUNUSED_UNLESS_XIM(param) param
2273 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2276 /* Resize XIM window */
2280 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2281 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2282 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2285 wxapp_install_idle_handler();
2291 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2295 gdk_window_get_size (widget
->window
, &width
, &height
);
2296 win
->m_icattr
->preedit_area
.width
= width
;
2297 win
->m_icattr
->preedit_area
.height
= height
;
2298 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2304 //-----------------------------------------------------------------------------
2305 // "realize" from m_wxwindow
2306 //-----------------------------------------------------------------------------
2308 /* Initialize XIM support */
2312 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2313 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2316 wxapp_install_idle_handler();
2319 if (win
->m_ic
) return FALSE
;
2320 if (!widget
) return FALSE
;
2321 if (!gdk_im_ready()) return FALSE
;
2323 win
->m_icattr
= gdk_ic_attr_new();
2324 if (!win
->m_icattr
) return FALSE
;
2328 GdkColormap
*colormap
;
2329 GdkICAttr
*attr
= win
->m_icattr
;
2330 unsigned attrmask
= GDK_IC_ALL_REQ
;
2332 GdkIMStyle supported_style
= (GdkIMStyle
)
2333 (GDK_IM_PREEDIT_NONE
|
2334 GDK_IM_PREEDIT_NOTHING
|
2335 GDK_IM_PREEDIT_POSITION
|
2336 GDK_IM_STATUS_NONE
|
2337 GDK_IM_STATUS_NOTHING
);
2339 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2340 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2342 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2343 attr
->client_window
= widget
->window
;
2345 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2346 gtk_widget_get_default_colormap ())
2348 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2349 attr
->preedit_colormap
= colormap
;
2352 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2353 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2354 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2355 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2357 switch (style
& GDK_IM_PREEDIT_MASK
)
2359 case GDK_IM_PREEDIT_POSITION
:
2360 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2362 g_warning ("over-the-spot style requires fontset");
2366 gdk_window_get_size (widget
->window
, &width
, &height
);
2368 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2369 attr
->spot_location
.x
= 0;
2370 attr
->spot_location
.y
= height
;
2371 attr
->preedit_area
.x
= 0;
2372 attr
->preedit_area
.y
= 0;
2373 attr
->preedit_area
.width
= width
;
2374 attr
->preedit_area
.height
= height
;
2375 attr
->preedit_fontset
= widget
->style
->font
;
2380 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2382 if (win
->m_ic
== NULL
)
2383 g_warning ("Can't create input context.");
2386 mask
= gdk_window_get_events (widget
->window
);
2387 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2388 gdk_window_set_events (widget
->window
, mask
);
2390 if (GTK_WIDGET_HAS_FOCUS(widget
))
2391 gdk_im_begin (win
->m_ic
, widget
->window
);
2399 //-----------------------------------------------------------------------------
2400 // InsertChild for wxWindowGTK.
2401 //-----------------------------------------------------------------------------
2403 /* Callback for wxWindowGTK. This very strange beast has to be used because
2404 * C++ has no virtual methods in a constructor. We have to emulate a
2405 * virtual function here as wxNotebook requires a different way to insert
2406 * a child in it. I had opted for creating a wxNotebookPage window class
2407 * which would have made this superfluous (such in the MDI window system),
2408 * but no-one was listening to me... */
2410 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2412 /* the window might have been scrolled already, do we
2413 have to adapt the position */
2414 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2415 child
->m_x
+= pizza
->xoffset
;
2416 child
->m_y
+= pizza
->yoffset
;
2418 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2419 GTK_WIDGET(child
->m_widget
),
2426 //-----------------------------------------------------------------------------
2428 //-----------------------------------------------------------------------------
2430 wxWindow
*wxGetActiveWindow()
2432 return wxWindow::FindFocus();
2436 wxMouseState
wxGetMouseState()
2442 GdkModifierType mask
;
2444 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2448 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2449 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2450 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2452 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2453 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2454 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2455 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2460 //-----------------------------------------------------------------------------
2462 //-----------------------------------------------------------------------------
2464 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2466 #ifdef __WXUNIVERSAL__
2467 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2469 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2470 #endif // __WXUNIVERSAL__/__WXGTK__
2472 void wxWindowGTK::Init()
2475 m_widget
= (GtkWidget
*) NULL
;
2476 m_wxwindow
= (GtkWidget
*) NULL
;
2477 m_focusWidget
= (GtkWidget
*) NULL
;
2487 m_needParent
= true;
2488 m_isBeingDeleted
= false;
2491 m_nativeSizeEvent
= false;
2493 m_hasScrolling
= false;
2494 m_isScrolling
= false;
2496 m_hAdjust
= (GtkAdjustment
*) NULL
;
2497 m_vAdjust
= (GtkAdjustment
*) NULL
;
2498 m_oldHorizontalPos
=
2499 m_oldVerticalPos
= 0.0;
2501 m_oldClientHeight
= 0;
2505 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2507 m_acceptsFocus
= false;
2510 m_clipPaintRegion
= false;
2512 m_needsStyleChange
= false;
2514 m_cursor
= *wxSTANDARD_CURSOR
;
2517 m_dirtyTabOrder
= false;
2520 wxWindowGTK::wxWindowGTK()
2525 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2530 const wxString
&name
)
2534 Create( parent
, id
, pos
, size
, style
, name
);
2537 bool wxWindowGTK::Create( wxWindow
*parent
,
2542 const wxString
&name
)
2544 if (!PreCreation( parent
, pos
, size
) ||
2545 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2547 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2551 m_insertCallback
= wxInsertChildInWindow
;
2553 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2554 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2556 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2558 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2559 scroll_class
->scrollbar_spacing
= 0;
2561 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2563 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2564 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2566 m_wxwindow
= gtk_pizza_new();
2568 #ifndef __WXUNIVERSAL__
2569 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2571 if (HasFlag(wxRAISED_BORDER
))
2573 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2575 else if (HasFlag(wxSUNKEN_BORDER
))
2577 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2579 else if (HasFlag(wxSIMPLE_BORDER
))
2581 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2585 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2587 #endif // __WXUNIVERSAL__
2589 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2591 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2592 m_acceptsFocus
= true;
2594 // I _really_ don't want scrollbars in the beginning
2595 m_vAdjust
->lower
= 0.0;
2596 m_vAdjust
->upper
= 1.0;
2597 m_vAdjust
->value
= 0.0;
2598 m_vAdjust
->step_increment
= 1.0;
2599 m_vAdjust
->page_increment
= 1.0;
2600 m_vAdjust
->page_size
= 5.0;
2601 g_signal_emit_by_name (m_vAdjust
, "changed");
2602 m_hAdjust
->lower
= 0.0;
2603 m_hAdjust
->upper
= 1.0;
2604 m_hAdjust
->value
= 0.0;
2605 m_hAdjust
->step_increment
= 1.0;
2606 m_hAdjust
->page_increment
= 1.0;
2607 m_hAdjust
->page_size
= 5.0;
2608 g_signal_emit_by_name (m_hAdjust
, "changed");
2610 // these handlers block mouse events to any window during scrolling such as
2611 // motion events and prevent GTK and wxWidgets from fighting over where the
2613 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2614 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2615 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2616 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2617 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2618 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2619 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2620 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2622 // these handlers get notified when screen updates are required either when
2623 // scrolling or when the window size (and therefore scrollbar configuration)
2626 g_signal_connect (m_hAdjust
, "value_changed",
2627 G_CALLBACK (gtk_window_hscroll_callback
), this);
2628 g_signal_connect (m_vAdjust
, "value_changed",
2629 G_CALLBACK (gtk_window_vscroll_callback
), this);
2631 gtk_widget_show( m_wxwindow
);
2634 m_parent
->DoAddChild( this );
2636 m_focusWidget
= m_wxwindow
;
2643 wxWindowGTK::~wxWindowGTK()
2647 if (g_focusWindow
== this)
2648 g_focusWindow
= NULL
;
2650 if ( g_delayedFocus
== this )
2651 g_delayedFocus
= NULL
;
2653 m_isBeingDeleted
= true;
2656 // destroy children before destroying this window itself
2659 // unhook focus handlers to prevent stray events being
2660 // propagated to this (soon to be) dead object
2661 if (m_focusWidget
!= NULL
)
2663 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2664 (gpointer
) gtk_window_focus_in_callback
,
2666 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2667 (gpointer
) gtk_window_focus_out_callback
,
2676 gdk_ic_destroy (m_ic
);
2678 gdk_ic_attr_destroy (m_icattr
);
2681 // delete before the widgets to avoid a crash on solaris
2686 gtk_widget_destroy( m_wxwindow
);
2687 m_wxwindow
= (GtkWidget
*) NULL
;
2692 gtk_widget_destroy( m_widget
);
2693 m_widget
= (GtkWidget
*) NULL
;
2697 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2699 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2701 // Use either the given size, or the default if -1 is given.
2702 // See wxWindowBase for these functions.
2703 m_width
= WidthDefault(size
.x
) ;
2704 m_height
= HeightDefault(size
.y
);
2712 void wxWindowGTK::PostCreation()
2714 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2720 // these get reported to wxWidgets -> wxPaintEvent
2722 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2724 g_signal_connect (m_wxwindow
, "expose_event",
2725 G_CALLBACK (gtk_window_expose_callback
), this);
2727 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2730 // Create input method handler
2731 m_imData
= new wxGtkIMData
;
2733 // Cannot handle drawing preedited text yet
2734 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2736 g_signal_connect (m_imData
->context
, "commit",
2737 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2739 // these are called when the "sunken" or "raised" borders are drawn
2740 g_signal_connect (m_widget
, "expose_event",
2741 G_CALLBACK (gtk_window_own_expose_callback
), this);
2746 if (!GTK_IS_WINDOW(m_widget
))
2748 if (m_focusWidget
== NULL
)
2749 m_focusWidget
= m_widget
;
2751 g_signal_connect (m_focusWidget
, "focus_in_event",
2752 G_CALLBACK (gtk_window_focus_in_callback
), this);
2753 g_signal_connect (m_focusWidget
, "focus_out_event",
2754 G_CALLBACK (gtk_window_focus_out_callback
), this);
2757 // connect to the various key and mouse handlers
2759 GtkWidget
*connect_widget
= GetConnectWidget();
2761 ConnectWidget( connect_widget
);
2763 /* We cannot set colours, fonts and cursors before the widget has
2764 been realized, so we do this directly after realization */
2765 g_signal_connect (connect_widget
, "realize",
2766 G_CALLBACK (gtk_window_realized_callback
), this);
2770 // Catch native resize events
2771 g_signal_connect (m_wxwindow
, "size_allocate",
2772 G_CALLBACK (gtk_window_size_callback
), this);
2774 // Initialize XIM support
2775 g_signal_connect (m_wxwindow
, "realize",
2776 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2778 // And resize XIM window
2779 g_signal_connect (m_wxwindow
, "size_allocate",
2780 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2783 if (GTK_IS_COMBO(m_widget
))
2785 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2787 g_signal_connect (gcombo
->entry
, "size_request",
2788 G_CALLBACK (wxgtk_combo_size_request_callback
),
2793 // This is needed if we want to add our windows into native
2794 // GTK controls, such as the toolbar. With this callback, the
2795 // toolbar gets to know the correct size (the one set by the
2796 // programmer). Sadly, it misbehaves for wxComboBox.
2797 g_signal_connect (m_widget
, "size_request",
2798 G_CALLBACK (wxgtk_window_size_request_callback
),
2802 InheritAttributes();
2806 // unless the window was created initially hidden (i.e. Hide() had been
2807 // called before Create()), we should show it at GTK+ level as well
2809 gtk_widget_show( m_widget
);
2812 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2814 g_signal_connect (widget
, "key_press_event",
2815 G_CALLBACK (gtk_window_key_press_callback
), this);
2816 g_signal_connect (widget
, "key_release_event",
2817 G_CALLBACK (gtk_window_key_release_callback
), this);
2818 g_signal_connect (widget
, "button_press_event",
2819 G_CALLBACK (gtk_window_button_press_callback
), this);
2820 g_signal_connect (widget
, "button_release_event",
2821 G_CALLBACK (gtk_window_button_release_callback
), this);
2822 g_signal_connect (widget
, "motion_notify_event",
2823 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2824 g_signal_connect (widget
, "scroll_event",
2825 G_CALLBACK (gtk_window_wheel_callback
), this);
2826 g_signal_connect (widget
, "popup_menu",
2827 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2828 g_signal_connect (widget
, "enter_notify_event",
2829 G_CALLBACK (gtk_window_enter_callback
), this);
2830 g_signal_connect (widget
, "leave_notify_event",
2831 G_CALLBACK (gtk_window_leave_callback
), this);
2834 bool wxWindowGTK::Destroy()
2836 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2840 return wxWindowBase::Destroy();
2843 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2845 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2848 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2850 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2851 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2854 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2857 if (m_resizing
) return; /* I don't like recursions */
2860 int currentX
, currentY
;
2861 GetPosition(¤tX
, ¤tY
);
2862 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2864 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2866 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2868 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2870 /* don't set the size for children of wxNotebook, just take the values. */
2878 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2879 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2881 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2882 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2886 m_x
= x
+ pizza
->xoffset
;
2887 m_y
= y
+ pizza
->yoffset
;
2890 // calculate the best size if we should auto size the window
2891 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2892 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2894 const wxSize sizeBest
= GetBestSize();
2895 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2897 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2898 height
= sizeBest
.y
;
2906 int minWidth
= GetMinWidth(),
2907 minHeight
= GetMinHeight(),
2908 maxWidth
= GetMaxWidth(),
2909 maxHeight
= GetMaxHeight();
2911 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2912 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2913 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2914 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2916 int left_border
= 0;
2917 int right_border
= 0;
2919 int bottom_border
= 0;
2921 /* the default button has a border around it */
2922 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2924 GtkBorder
*default_border
= NULL
;
2925 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2928 left_border
+= default_border
->left
;
2929 right_border
+= default_border
->right
;
2930 top_border
+= default_border
->top
;
2931 bottom_border
+= default_border
->bottom
;
2932 g_free( default_border
);
2936 DoMoveWindow( m_x
-top_border
,
2938 m_width
+left_border
+right_border
,
2939 m_height
+top_border
+bottom_border
);
2944 /* Sometimes the client area changes size without the
2945 whole windows's size changing, but if the whole
2946 windows's size doesn't change, no wxSizeEvent will
2947 normally be sent. Here we add an extra test if
2948 the client test has been changed and this will
2950 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2954 wxPrintf( "OnSize sent from " );
2955 if (GetClassInfo() && GetClassInfo()->GetClassName())
2956 wxPrintf( GetClassInfo()->GetClassName() );
2957 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2960 if (!m_nativeSizeEvent
)
2962 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2963 event
.SetEventObject( this );
2964 GetEventHandler()->ProcessEvent( event
);
2970 void wxWindowGTK::OnInternalIdle()
2972 if ( m_dirtyTabOrder
)
2974 m_dirtyTabOrder
= false;
2978 // Update style if the window was not yet realized
2979 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2980 if (m_needsStyleChange
)
2982 SetBackgroundStyle(GetBackgroundStyle());
2983 m_needsStyleChange
= false;
2986 // Update invalidated regions.
2989 wxCursor cursor
= m_cursor
;
2990 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2994 /* I now set the cursor anew in every OnInternalIdle call
2995 as setting the cursor in a parent window also effects the
2996 windows above so that checking for the current cursor is
3001 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3003 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3005 if (!g_globalCursor
.Ok())
3006 cursor
= *wxSTANDARD_CURSOR
;
3008 window
= m_widget
->window
;
3009 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3010 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3016 GdkWindow
*window
= m_widget
->window
;
3017 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3018 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3023 if (wxUpdateUIEvent::CanUpdate(this))
3024 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3027 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3029 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3031 if (width
) (*width
) = m_width
;
3032 if (height
) (*height
) = m_height
;
3035 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3037 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3041 SetSize( width
, height
);
3048 #ifndef __WXUNIVERSAL__
3049 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3051 /* when using GTK 1.2 we set the shadow border size to 2 */
3055 if (HasFlag(wxSIMPLE_BORDER
))
3057 /* when using GTK 1.2 we set the simple border size to 1 */
3061 #endif // __WXUNIVERSAL__
3065 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3067 GtkRequisition vscroll_req
;
3068 vscroll_req
.width
= 2;
3069 vscroll_req
.height
= 2;
3070 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3071 (scroll_window
->vscrollbar
, &vscroll_req
);
3073 GtkRequisition hscroll_req
;
3074 hscroll_req
.width
= 2;
3075 hscroll_req
.height
= 2;
3076 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3077 (scroll_window
->hscrollbar
, &hscroll_req
);
3079 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3081 if (scroll_window
->vscrollbar_visible
)
3083 dw
+= vscroll_req
.width
;
3084 dw
+= scroll_class
->scrollbar_spacing
;
3087 if (scroll_window
->hscrollbar_visible
)
3089 dh
+= hscroll_req
.height
;
3090 dh
+= scroll_class
->scrollbar_spacing
;
3094 SetSize( width
+dw
, height
+dh
);
3098 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3100 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3104 if (width
) (*width
) = m_width
;
3105 if (height
) (*height
) = m_height
;
3112 #ifndef __WXUNIVERSAL__
3113 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3115 /* when using GTK 1.2 we set the shadow border size to 2 */
3119 if (HasFlag(wxSIMPLE_BORDER
))
3121 /* when using GTK 1.2 we set the simple border size to 1 */
3125 #endif // __WXUNIVERSAL__
3129 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3131 GtkRequisition vscroll_req
;
3132 vscroll_req
.width
= 2;
3133 vscroll_req
.height
= 2;
3134 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3135 (scroll_window
->vscrollbar
, &vscroll_req
);
3137 GtkRequisition hscroll_req
;
3138 hscroll_req
.width
= 2;
3139 hscroll_req
.height
= 2;
3140 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3141 (scroll_window
->hscrollbar
, &hscroll_req
);
3143 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3145 if (scroll_window
->vscrollbar_visible
)
3147 dw
+= vscroll_req
.width
;
3148 dw
+= scroll_class
->scrollbar_spacing
;
3151 if (scroll_window
->hscrollbar_visible
)
3153 dh
+= hscroll_req
.height
;
3154 dh
+= scroll_class
->scrollbar_spacing
;
3158 if (width
) (*width
) = m_width
- dw
;
3159 if (height
) (*height
) = m_height
- dh
;
3163 printf( "GetClientSize, name %s ", GetName().c_str() );
3164 if (width) printf( " width = %d", (*width) );
3165 if (height) printf( " height = %d", (*height) );
3170 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3172 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3176 if (m_parent
&& m_parent
->m_wxwindow
)
3178 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3179 dx
= pizza
->xoffset
;
3180 dy
= pizza
->yoffset
;
3183 if (x
) (*x
) = m_x
- dx
;
3184 if (y
) (*y
) = m_y
- dy
;
3187 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3189 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3191 if (!m_widget
->window
) return;
3193 GdkWindow
*source
= (GdkWindow
*) NULL
;
3195 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3197 source
= m_widget
->window
;
3201 gdk_window_get_origin( source
, &org_x
, &org_y
);
3205 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3207 org_x
+= m_widget
->allocation
.x
;
3208 org_y
+= m_widget
->allocation
.y
;
3216 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3218 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3220 if (!m_widget
->window
) return;
3222 GdkWindow
*source
= (GdkWindow
*) NULL
;
3224 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3226 source
= m_widget
->window
;
3230 gdk_window_get_origin( source
, &org_x
, &org_y
);
3234 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3236 org_x
+= m_widget
->allocation
.x
;
3237 org_y
+= m_widget
->allocation
.y
;
3245 bool wxWindowGTK::Show( bool show
)
3247 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3249 if (!wxWindowBase::Show(show
))
3256 gtk_widget_show( m_widget
);
3258 gtk_widget_hide( m_widget
);
3260 wxShowEvent
eventShow(GetId(), show
);
3261 eventShow
.SetEventObject(this);
3263 GetEventHandler()->ProcessEvent(eventShow
);
3268 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3270 win
->OnParentEnable(enable
);
3272 // Recurse, so that children have the opportunity to Do The Right Thing
3273 // and reset colours that have been messed up by a parent's (really ancestor's)
3275 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3277 node
= node
->GetNext() )
3279 wxWindow
*child
= node
->GetData();
3280 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3281 wxWindowNotifyEnable(child
, enable
);
3285 bool wxWindowGTK::Enable( bool enable
)
3287 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3289 if (!wxWindowBase::Enable(enable
))
3295 gtk_widget_set_sensitive( m_widget
, enable
);
3297 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3299 wxWindowNotifyEnable(this, enable
);
3304 int wxWindowGTK::GetCharHeight() const
3306 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3308 wxFont font
= GetFont();
3309 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3311 PangoContext
*context
= NULL
;
3313 context
= gtk_widget_get_pango_context( m_widget
);
3318 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3319 PangoLayout
*layout
= pango_layout_new(context
);
3320 pango_layout_set_font_description(layout
, desc
);
3321 pango_layout_set_text(layout
, "H", 1);
3322 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3324 PangoRectangle rect
;
3325 pango_layout_line_get_extents(line
, NULL
, &rect
);
3327 g_object_unref( G_OBJECT( layout
) );
3329 return (int) PANGO_PIXELS(rect
.height
);
3332 int wxWindowGTK::GetCharWidth() const
3334 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3336 wxFont font
= GetFont();
3337 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3339 PangoContext
*context
= NULL
;
3341 context
= gtk_widget_get_pango_context( m_widget
);
3346 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3347 PangoLayout
*layout
= pango_layout_new(context
);
3348 pango_layout_set_font_description(layout
, desc
);
3349 pango_layout_set_text(layout
, "g", 1);
3350 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3352 PangoRectangle rect
;
3353 pango_layout_line_get_extents(line
, NULL
, &rect
);
3355 g_object_unref( G_OBJECT( layout
) );
3357 return (int) PANGO_PIXELS(rect
.width
);
3360 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3364 int *externalLeading
,
3365 const wxFont
*theFont
) const
3367 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3369 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3378 PangoContext
*context
= NULL
;
3380 context
= gtk_widget_get_pango_context( m_widget
);
3389 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3390 PangoLayout
*layout
= pango_layout_new(context
);
3391 pango_layout_set_font_description(layout
, desc
);
3394 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3395 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3397 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3398 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3399 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3403 PangoRectangle rect
;
3404 pango_layout_get_extents(layout
, NULL
, &rect
);
3406 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3407 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3410 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3411 int baseline
= pango_layout_iter_get_baseline(iter
);
3412 pango_layout_iter_free(iter
);
3413 *descent
= *y
- PANGO_PIXELS(baseline
);
3415 if (externalLeading
) (*externalLeading
) = 0; // ??
3417 g_object_unref( G_OBJECT( layout
) );
3420 void wxWindowGTK::SetFocus()
3422 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3425 // don't do anything if we already have focus
3431 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3433 gtk_widget_grab_focus (m_wxwindow
);
3438 if (GTK_IS_CONTAINER(m_widget
))
3440 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3443 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3446 if (!GTK_WIDGET_REALIZED(m_widget
))
3448 // we can't set the focus to the widget now so we remember that
3449 // it should be focused and will do it later, during the idle
3450 // time, as soon as we can
3451 wxLogTrace(TRACE_FOCUS
,
3452 _T("Delaying setting focus to %s(%s)"),
3453 GetClassInfo()->GetClassName(), GetLabel().c_str());
3455 g_delayedFocus
= this;
3459 wxLogTrace(TRACE_FOCUS
,
3460 _T("Setting focus to %s(%s)"),
3461 GetClassInfo()->GetClassName(), GetLabel().c_str());
3463 gtk_widget_grab_focus (m_widget
);
3468 wxLogTrace(TRACE_FOCUS
,
3469 _T("Can't set focus to %s(%s)"),
3470 GetClassInfo()->GetClassName(), GetLabel().c_str());
3475 bool wxWindowGTK::AcceptsFocus() const
3477 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3480 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3482 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3484 wxWindowGTK
*oldParent
= m_parent
,
3485 *newParent
= (wxWindowGTK
*)newParentBase
;
3487 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3489 if ( !wxWindowBase::Reparent(newParent
) )
3492 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3494 /* prevent GTK from deleting the widget arbitrarily */
3495 gtk_widget_ref( m_widget
);
3499 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3502 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3506 /* insert GTK representation */
3507 (*(newParent
->m_insertCallback
))(newParent
, this);
3510 /* reverse: prevent GTK from deleting the widget arbitrarily */
3511 gtk_widget_unref( m_widget
);
3516 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3518 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3520 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3522 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3527 /* insert GTK representation */
3528 (*m_insertCallback
)(this, child
);
3531 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3533 wxWindowBase::AddChild(child
);
3534 m_dirtyTabOrder
= true;
3536 wxapp_install_idle_handler();
3539 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3541 wxWindowBase::RemoveChild(child
);
3542 m_dirtyTabOrder
= true;
3544 wxapp_install_idle_handler();
3547 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3549 wxWindowBase::DoMoveInTabOrder(win
, move
);
3550 m_dirtyTabOrder
= true;
3552 wxapp_install_idle_handler();
3555 void wxWindowGTK::RealizeTabOrder()
3559 if ( !m_children
.empty() )
3562 // we don't only construct the correct focus chain but also use
3563 // this opportunity to update the mnemonic widgets for all labels
3565 // it would be nice to extract this code from here and put it in
3566 // stattext.cpp to reduce dependencies but there is no really easy
3567 // way to do it unfortunately
3568 wxStaticText
*lastLabel
= NULL
;
3569 #endif // wxUSE_STATTEXT
3571 GList
*chain
= NULL
;
3573 for ( wxWindowList::const_iterator i
= m_children
.begin();
3574 i
!= m_children
.end();
3577 wxWindowGTK
*win
= *i
;
3581 if ( win
->AcceptsFocusFromKeyboard() )
3583 GtkLabel
*l
= GTK_LABEL(lastLabel
->m_widget
);
3584 gtk_label_set_mnemonic_widget(l
, win
->m_widget
);
3588 else // check if this one is a label
3590 lastLabel
= wxDynamicCast(win
, wxStaticText
);
3592 #endif // wxUSE_STATTEXT
3594 chain
= g_list_prepend(chain
, win
->m_widget
);
3597 chain
= g_list_reverse(chain
);
3599 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3604 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3609 void wxWindowGTK::Raise()
3611 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3613 if (m_wxwindow
&& m_wxwindow
->window
)
3615 gdk_window_raise( m_wxwindow
->window
);
3617 else if (m_widget
->window
)
3619 gdk_window_raise( m_widget
->window
);
3623 void wxWindowGTK::Lower()
3625 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3627 if (m_wxwindow
&& m_wxwindow
->window
)
3629 gdk_window_lower( m_wxwindow
->window
);
3631 else if (m_widget
->window
)
3633 gdk_window_lower( m_widget
->window
);
3637 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3639 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3641 if (cursor
== m_cursor
)
3645 wxapp_install_idle_handler();
3647 if (cursor
== wxNullCursor
)
3648 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3650 return wxWindowBase::SetCursor( cursor
);
3653 void wxWindowGTK::WarpPointer( int x
, int y
)
3655 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3657 // We provide this function ourselves as it is
3658 // missing in GDK (top of this file).
3660 GdkWindow
*window
= (GdkWindow
*) NULL
;
3662 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3664 window
= GetConnectWidget()->window
;
3667 gdk_window_warp_pointer( window
, x
, y
);
3670 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3672 double value_start
= adj
->value
;
3673 double value
= value_start
+ change
;
3674 double upper
= adj
->upper
- adj
->page_size
;
3679 // Lower bound will be checked by gtk_adjustment_set_value
3680 gtk_adjustment_set_value(adj
, value
);
3681 return adj
->value
!= value_start
;
3684 bool wxWindowGTK::ScrollLines(int lines
)
3687 m_vAdjust
!= NULL
&&
3688 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3691 bool wxWindowGTK::ScrollPages(int pages
)
3694 m_vAdjust
!= NULL
&&
3695 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3698 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3700 wxASSERT(m_vAdjust
== NULL
);
3704 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3708 if (!m_widget
->window
)
3713 GdkRectangle gdk_rect
,
3717 gdk_rect
.x
= rect
->x
;
3718 gdk_rect
.y
= rect
->y
;
3719 gdk_rect
.width
= rect
->width
;
3720 gdk_rect
.height
= rect
->height
;
3723 else // invalidate everything
3728 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3732 void wxWindowGTK::Update()
3736 // when we call Update() we really want to update the window immediately on
3737 // screen, even if it means flushing the entire queue and hence slowing down
3738 // everything -- but it should still be done, it's just that Update() should
3739 // be called very rarely
3743 void wxWindowGTK::GtkUpdate()
3745 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3746 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3748 // for consistency with other platforms (and also because it's convenient
3749 // to be able to update an entire TLW by calling Update() only once), we
3750 // should also update all our children here
3751 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3753 node
= node
->GetNext() )
3755 node
->GetData()->GtkUpdate();
3759 void wxWindowGTK::GtkSendPaintEvents()
3763 m_updateRegion
.Clear();
3767 // Clip to paint region in wxClientDC
3768 m_clipPaintRegion
= true;
3770 // widget to draw on
3771 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3773 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3775 // find ancestor from which to steal background
3776 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3778 parent
= (wxWindow
*)this;
3780 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3782 wxRegionIterator
upd( m_updateRegion
);
3786 rect
.x
= upd
.GetX();
3787 rect
.y
= upd
.GetY();
3788 rect
.width
= upd
.GetWidth();
3789 rect
.height
= upd
.GetHeight();
3791 gtk_paint_flat_box( parent
->m_widget
->style
,
3793 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3807 wxWindowDC
dc( (wxWindow
*)this );
3808 dc
.SetClippingRegion( m_updateRegion
);
3810 wxEraseEvent
erase_event( GetId(), &dc
);
3811 erase_event
.SetEventObject( this );
3813 GetEventHandler()->ProcessEvent(erase_event
);
3816 wxNcPaintEvent
nc_paint_event( GetId() );
3817 nc_paint_event
.SetEventObject( this );
3818 GetEventHandler()->ProcessEvent( nc_paint_event
);
3820 wxPaintEvent
paint_event( GetId() );
3821 paint_event
.SetEventObject( this );
3822 GetEventHandler()->ProcessEvent( paint_event
);
3824 m_clipPaintRegion
= false;
3826 m_updateRegion
.Clear();
3829 void wxWindowGTK::ClearBackground()
3831 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3835 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3837 wxWindowBase::DoSetToolTip(tip
);
3840 m_tooltip
->Apply( (wxWindow
*)this );
3843 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3845 wxString
tmp( tip
);
3846 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3848 #endif // wxUSE_TOOLTIPS
3850 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3852 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3854 if (!wxWindowBase::SetBackgroundColour(colour
))
3859 // We need the pixel value e.g. for background clearing.
3860 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3863 // apply style change (forceStyle=true so that new style is applied
3864 // even if the bg colour changed from valid to wxNullColour)
3865 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3866 ApplyWidgetStyle(true);
3871 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3873 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3875 if (!wxWindowBase::SetForegroundColour(colour
))
3882 // We need the pixel value e.g. for background clearing.
3883 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3886 // apply style change (forceStyle=true so that new style is applied
3887 // even if the bg colour changed from valid to wxNullColour):
3888 ApplyWidgetStyle(true);
3893 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3895 return gtk_widget_get_pango_context( m_widget
);
3898 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3900 // do we need to apply any changes at all?
3903 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3908 GtkRcStyle
*style
= gtk_rc_style_new();
3913 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3916 if ( m_foregroundColour
.Ok() )
3918 GdkColor
*fg
= m_foregroundColour
.GetColor();
3920 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3921 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3923 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3924 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3926 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3927 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3930 if ( m_backgroundColour
.Ok() )
3932 GdkColor
*bg
= m_backgroundColour
.GetColor();
3934 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3935 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3936 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3937 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3939 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3940 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3941 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3942 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3944 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3945 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3946 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3947 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3949 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3950 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3951 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3952 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3958 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3960 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3963 DoApplyWidgetStyle(style
);
3964 gtk_rc_style_unref(style
);
3967 // Style change may affect GTK+'s size calculation:
3968 InvalidateBestSize();
3971 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3974 gtk_widget_modify_style(m_wxwindow
, style
);
3976 gtk_widget_modify_style(m_widget
, style
);
3979 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3981 wxWindowBase::SetBackgroundStyle(style
);
3983 if (style
== wxBG_STYLE_CUSTOM
)
3985 GdkWindow
*window
= (GdkWindow
*) NULL
;
3987 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3989 window
= GetConnectWidget()->window
;
3993 // Make sure GDK/X11 doesn't refresh the window
3995 gdk_window_set_back_pixmap( window
, None
, False
);
3997 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4000 m_needsStyleChange
= false;
4003 // Do in OnIdle, because the window is not yet available
4004 m_needsStyleChange
= true;
4006 // Don't apply widget style, or we get a grey background
4010 // apply style change (forceStyle=true so that new style is applied
4011 // even if the bg colour changed from valid to wxNullColour):
4012 ApplyWidgetStyle(true);
4017 #if wxUSE_DRAG_AND_DROP
4019 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4021 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4023 GtkWidget
*dnd_widget
= GetConnectWidget();
4025 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4027 if (m_dropTarget
) delete m_dropTarget
;
4028 m_dropTarget
= dropTarget
;
4030 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4033 #endif // wxUSE_DRAG_AND_DROP
4035 GtkWidget
* wxWindowGTK::GetConnectWidget()
4037 GtkWidget
*connect_widget
= m_widget
;
4038 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4040 return connect_widget
;
4043 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4046 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4048 return (window
== m_widget
->window
);
4051 bool wxWindowGTK::SetFont( const wxFont
&font
)
4053 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4055 if (!wxWindowBase::SetFont(font
))
4058 // apply style change (forceStyle=true so that new style is applied
4059 // even if the font changed from valid to wxNullFont):
4060 ApplyWidgetStyle(true);
4065 void wxWindowGTK::DoCaptureMouse()
4067 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4069 GdkWindow
*window
= (GdkWindow
*) NULL
;
4071 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4073 window
= GetConnectWidget()->window
;
4075 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4077 wxCursor
* cursor
= & m_cursor
;
4079 cursor
= wxSTANDARD_CURSOR
;
4081 gdk_pointer_grab( window
, FALSE
,
4083 (GDK_BUTTON_PRESS_MASK
|
4084 GDK_BUTTON_RELEASE_MASK
|
4085 GDK_POINTER_MOTION_HINT_MASK
|
4086 GDK_POINTER_MOTION_MASK
),
4088 cursor
->GetCursor(),
4089 (guint32
)GDK_CURRENT_TIME
);
4090 g_captureWindow
= this;
4091 g_captureWindowHasMouse
= true;
4094 void wxWindowGTK::DoReleaseMouse()
4096 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4098 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4100 g_captureWindow
= (wxWindowGTK
*) NULL
;
4102 GdkWindow
*window
= (GdkWindow
*) NULL
;
4104 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4106 window
= GetConnectWidget()->window
;
4111 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4115 wxWindow
*wxWindowBase::GetCapture()
4117 return (wxWindow
*)g_captureWindow
;
4120 bool wxWindowGTK::IsRetained() const
4125 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4126 int range
, bool refresh
)
4128 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4130 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4132 m_hasScrolling
= true;
4134 if (orient
== wxHORIZONTAL
)
4136 float fpos
= (float)pos
;
4137 float frange
= (float)range
;
4138 float fthumb
= (float)thumbVisible
;
4139 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4140 if (fpos
< 0.0) fpos
= 0.0;
4142 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4143 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4145 SetScrollPos( orient
, pos
, refresh
);
4149 m_oldHorizontalPos
= fpos
;
4151 m_hAdjust
->lower
= 0.0;
4152 m_hAdjust
->upper
= frange
;
4153 m_hAdjust
->value
= fpos
;
4154 m_hAdjust
->step_increment
= 1.0;
4155 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4156 m_hAdjust
->page_size
= fthumb
;
4160 float fpos
= (float)pos
;
4161 float frange
= (float)range
;
4162 float fthumb
= (float)thumbVisible
;
4163 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4164 if (fpos
< 0.0) fpos
= 0.0;
4166 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4167 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4169 SetScrollPos( orient
, pos
, refresh
);
4173 m_oldVerticalPos
= fpos
;
4175 m_vAdjust
->lower
= 0.0;
4176 m_vAdjust
->upper
= frange
;
4177 m_vAdjust
->value
= fpos
;
4178 m_vAdjust
->step_increment
= 1.0;
4179 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4180 m_vAdjust
->page_size
= fthumb
;
4183 if (orient
== wxHORIZONTAL
)
4184 g_signal_emit_by_name (m_hAdjust
, "changed");
4186 g_signal_emit_by_name (m_vAdjust
, "changed");
4189 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4191 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4192 gpointer fn
= orient
== wxHORIZONTAL
4193 ? (gpointer
) gtk_window_hscroll_callback
4194 : (gpointer
) gtk_window_vscroll_callback
;
4196 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4197 g_signal_emit_by_name (adj
, "value_changed");
4198 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4201 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4203 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4204 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4206 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4208 float fpos
= (float)pos
;
4209 if (fpos
> adj
->upper
- adj
->page_size
)
4210 fpos
= adj
->upper
- adj
->page_size
;
4213 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4215 if (fabs(fpos
-adj
->value
) < 0.2)
4219 if ( m_wxwindow
->window
)
4224 int wxWindowGTK::GetScrollThumb( int orient
) const
4226 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4228 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4230 if (orient
== wxHORIZONTAL
)
4231 return (int)(m_hAdjust
->page_size
+0.5);
4233 return (int)(m_vAdjust
->page_size
+0.5);
4236 int wxWindowGTK::GetScrollPos( int orient
) const
4238 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4240 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4242 if (orient
== wxHORIZONTAL
)
4243 return (int)(m_hAdjust
->value
+0.5);
4245 return (int)(m_vAdjust
->value
+0.5);
4248 int wxWindowGTK::GetScrollRange( int orient
) const
4250 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4252 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4254 if (orient
== wxHORIZONTAL
)
4255 return (int)(m_hAdjust
->upper
+0.5);
4257 return (int)(m_vAdjust
->upper
+0.5);
4260 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4262 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4264 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4266 // No scrolling requested.
4267 if ((dx
== 0) && (dy
== 0)) return;
4269 m_clipPaintRegion
= true;
4271 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4273 m_clipPaintRegion
= false;
4276 void wxWindowGTK::SetWindowStyleFlag( long style
)
4278 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4279 wxWindowBase::SetWindowStyleFlag(style
);
4282 // Find the wxWindow at the current mouse position, also returning the mouse
4284 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4286 pt
= wxGetMousePosition();
4287 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4291 // Get the current mouse position.
4292 wxPoint
wxGetMousePosition()
4294 /* This crashes when used within wxHelpContext,
4295 so we have to use the X-specific implementation below.
4297 GdkModifierType *mask;
4298 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4300 return wxPoint(x, y);
4304 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4306 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4307 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4308 Window rootReturn
, childReturn
;
4309 int rootX
, rootY
, winX
, winY
;
4310 unsigned int maskReturn
;
4312 XQueryPointer (display
,
4316 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4317 return wxPoint(rootX
, rootY
);
4321 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4322 void wxAddGrab(wxWindow
* window
)
4324 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4327 void wxRemoveGrab(wxWindow
* window
)
4329 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4332 // ----------------------------------------------------------------------------
4334 // ----------------------------------------------------------------------------
4336 class wxWinModule
: public wxModule
4343 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4346 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4348 bool wxWinModule::OnInit()
4350 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4351 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4356 void wxWinModule::OnExit()
4359 gdk_gc_unref( g_eraseGC
);