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
)
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
)
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
;
2753 g_signal_connect (m_focusWidget
, "focus_in_event",
2754 G_CALLBACK (gtk_window_focus_in_callback
), this);
2755 g_signal_connect (m_focusWidget
, "focus_out_event",
2756 G_CALLBACK (gtk_window_focus_out_callback
), this);
2760 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2761 G_CALLBACK (gtk_window_focus_in_callback
), this);
2762 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2763 G_CALLBACK (gtk_window_focus_out_callback
), this);
2767 // connect to the various key and mouse handlers
2769 GtkWidget
*connect_widget
= GetConnectWidget();
2771 ConnectWidget( connect_widget
);
2773 /* We cannot set colours, fonts and cursors before the widget has
2774 been realized, so we do this directly after realization */
2775 g_signal_connect (connect_widget
, "realize",
2776 G_CALLBACK (gtk_window_realized_callback
), this);
2780 // Catch native resize events
2781 g_signal_connect (m_wxwindow
, "size_allocate",
2782 G_CALLBACK (gtk_window_size_callback
), this);
2784 // Initialize XIM support
2785 g_signal_connect (m_wxwindow
, "realize",
2786 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2788 // And resize XIM window
2789 g_signal_connect (m_wxwindow
, "size_allocate",
2790 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2793 if (GTK_IS_COMBO(m_widget
))
2795 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2797 g_signal_connect (gcombo
->entry
, "size_request",
2798 G_CALLBACK (wxgtk_combo_size_request_callback
),
2803 // This is needed if we want to add our windows into native
2804 // GTK controls, such as the toolbar. With this callback, the
2805 // toolbar gets to know the correct size (the one set by the
2806 // programmer). Sadly, it misbehaves for wxComboBox.
2807 g_signal_connect (m_widget
, "size_request",
2808 G_CALLBACK (wxgtk_window_size_request_callback
),
2812 InheritAttributes();
2816 // unless the window was created initially hidden (i.e. Hide() had been
2817 // called before Create()), we should show it at GTK+ level as well
2819 gtk_widget_show( m_widget
);
2822 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2824 g_signal_connect (widget
, "key_press_event",
2825 G_CALLBACK (gtk_window_key_press_callback
), this);
2826 g_signal_connect (widget
, "key_release_event",
2827 G_CALLBACK (gtk_window_key_release_callback
), this);
2828 g_signal_connect (widget
, "button_press_event",
2829 G_CALLBACK (gtk_window_button_press_callback
), this);
2830 g_signal_connect (widget
, "button_release_event",
2831 G_CALLBACK (gtk_window_button_release_callback
), this);
2832 g_signal_connect (widget
, "motion_notify_event",
2833 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2834 g_signal_connect (widget
, "scroll_event",
2835 G_CALLBACK (gtk_window_wheel_callback
), this);
2836 g_signal_connect (widget
, "popup_menu",
2837 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2838 g_signal_connect (widget
, "enter_notify_event",
2839 G_CALLBACK (gtk_window_enter_callback
), this);
2840 g_signal_connect (widget
, "leave_notify_event",
2841 G_CALLBACK (gtk_window_leave_callback
), this);
2844 bool wxWindowGTK::Destroy()
2846 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2850 return wxWindowBase::Destroy();
2853 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2855 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2858 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2860 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2861 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2864 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2867 if (m_resizing
) return; /* I don't like recursions */
2870 int currentX
, currentY
;
2871 GetPosition(¤tX
, ¤tY
);
2872 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2874 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2876 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2878 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2880 /* don't set the size for children of wxNotebook, just take the values. */
2888 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2889 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2891 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2892 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2896 m_x
= x
+ pizza
->xoffset
;
2897 m_y
= y
+ pizza
->yoffset
;
2900 // calculate the best size if we should auto size the window
2901 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2902 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2904 const wxSize sizeBest
= GetBestSize();
2905 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2907 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2908 height
= sizeBest
.y
;
2916 int minWidth
= GetMinWidth(),
2917 minHeight
= GetMinHeight(),
2918 maxWidth
= GetMaxWidth(),
2919 maxHeight
= GetMaxHeight();
2921 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2922 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2923 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2924 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2926 int left_border
= 0;
2927 int right_border
= 0;
2929 int bottom_border
= 0;
2931 /* the default button has a border around it */
2932 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2934 GtkBorder
*default_border
= NULL
;
2935 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2938 left_border
+= default_border
->left
;
2939 right_border
+= default_border
->right
;
2940 top_border
+= default_border
->top
;
2941 bottom_border
+= default_border
->bottom
;
2942 g_free( default_border
);
2946 DoMoveWindow( m_x
-top_border
,
2948 m_width
+left_border
+right_border
,
2949 m_height
+top_border
+bottom_border
);
2954 /* Sometimes the client area changes size without the
2955 whole windows's size changing, but if the whole
2956 windows's size doesn't change, no wxSizeEvent will
2957 normally be sent. Here we add an extra test if
2958 the client test has been changed and this will
2960 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2964 wxPrintf( "OnSize sent from " );
2965 if (GetClassInfo() && GetClassInfo()->GetClassName())
2966 wxPrintf( GetClassInfo()->GetClassName() );
2967 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2970 if (!m_nativeSizeEvent
)
2972 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2973 event
.SetEventObject( this );
2974 GetEventHandler()->ProcessEvent( event
);
2980 void wxWindowGTK::OnInternalIdle()
2982 if ( m_dirtyTabOrder
)
2984 m_dirtyTabOrder
= false;
2988 // Update style if the window was not yet realized
2989 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2990 if (m_needsStyleChange
)
2992 SetBackgroundStyle(GetBackgroundStyle());
2993 m_needsStyleChange
= false;
2996 // Update invalidated regions.
2999 wxCursor cursor
= m_cursor
;
3000 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3004 /* I now set the cursor anew in every OnInternalIdle call
3005 as setting the cursor in a parent window also effects the
3006 windows above so that checking for the current cursor is
3011 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3013 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3015 if (!g_globalCursor
.Ok())
3016 cursor
= *wxSTANDARD_CURSOR
;
3018 window
= m_widget
->window
;
3019 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3020 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3026 GdkWindow
*window
= m_widget
->window
;
3027 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3028 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3033 if (wxUpdateUIEvent::CanUpdate(this))
3034 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3037 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3039 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3041 if (width
) (*width
) = m_width
;
3042 if (height
) (*height
) = m_height
;
3045 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3047 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3051 SetSize( width
, height
);
3058 #ifndef __WXUNIVERSAL__
3059 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3061 /* when using GTK 1.2 we set the shadow border size to 2 */
3065 if (HasFlag(wxSIMPLE_BORDER
))
3067 /* when using GTK 1.2 we set the simple border size to 1 */
3071 #endif // __WXUNIVERSAL__
3075 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3077 GtkRequisition vscroll_req
;
3078 vscroll_req
.width
= 2;
3079 vscroll_req
.height
= 2;
3080 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3081 (scroll_window
->vscrollbar
, &vscroll_req
);
3083 GtkRequisition hscroll_req
;
3084 hscroll_req
.width
= 2;
3085 hscroll_req
.height
= 2;
3086 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3087 (scroll_window
->hscrollbar
, &hscroll_req
);
3089 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3091 if (scroll_window
->vscrollbar_visible
)
3093 dw
+= vscroll_req
.width
;
3094 dw
+= scroll_class
->scrollbar_spacing
;
3097 if (scroll_window
->hscrollbar_visible
)
3099 dh
+= hscroll_req
.height
;
3100 dh
+= scroll_class
->scrollbar_spacing
;
3104 SetSize( width
+dw
, height
+dh
);
3108 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3110 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3114 if (width
) (*width
) = m_width
;
3115 if (height
) (*height
) = m_height
;
3122 #ifndef __WXUNIVERSAL__
3123 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3125 /* when using GTK 1.2 we set the shadow border size to 2 */
3129 if (HasFlag(wxSIMPLE_BORDER
))
3131 /* when using GTK 1.2 we set the simple border size to 1 */
3135 #endif // __WXUNIVERSAL__
3139 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3141 GtkRequisition vscroll_req
;
3142 vscroll_req
.width
= 2;
3143 vscroll_req
.height
= 2;
3144 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3145 (scroll_window
->vscrollbar
, &vscroll_req
);
3147 GtkRequisition hscroll_req
;
3148 hscroll_req
.width
= 2;
3149 hscroll_req
.height
= 2;
3150 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3151 (scroll_window
->hscrollbar
, &hscroll_req
);
3153 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3155 if (scroll_window
->vscrollbar_visible
)
3157 dw
+= vscroll_req
.width
;
3158 dw
+= scroll_class
->scrollbar_spacing
;
3161 if (scroll_window
->hscrollbar_visible
)
3163 dh
+= hscroll_req
.height
;
3164 dh
+= scroll_class
->scrollbar_spacing
;
3168 if (width
) (*width
) = m_width
- dw
;
3169 if (height
) (*height
) = m_height
- dh
;
3173 printf( "GetClientSize, name %s ", GetName().c_str() );
3174 if (width) printf( " width = %d", (*width) );
3175 if (height) printf( " height = %d", (*height) );
3180 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3182 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3186 if (m_parent
&& m_parent
->m_wxwindow
)
3188 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3189 dx
= pizza
->xoffset
;
3190 dy
= pizza
->yoffset
;
3193 if (x
) (*x
) = m_x
- dx
;
3194 if (y
) (*y
) = m_y
- dy
;
3197 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3199 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3201 if (!m_widget
->window
) return;
3203 GdkWindow
*source
= (GdkWindow
*) NULL
;
3205 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3207 source
= m_widget
->window
;
3211 gdk_window_get_origin( source
, &org_x
, &org_y
);
3215 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3217 org_x
+= m_widget
->allocation
.x
;
3218 org_y
+= m_widget
->allocation
.y
;
3226 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3228 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3230 if (!m_widget
->window
) return;
3232 GdkWindow
*source
= (GdkWindow
*) NULL
;
3234 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3236 source
= m_widget
->window
;
3240 gdk_window_get_origin( source
, &org_x
, &org_y
);
3244 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3246 org_x
+= m_widget
->allocation
.x
;
3247 org_y
+= m_widget
->allocation
.y
;
3255 bool wxWindowGTK::Show( bool show
)
3257 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3259 if (!wxWindowBase::Show(show
))
3266 gtk_widget_show( m_widget
);
3268 gtk_widget_hide( m_widget
);
3270 wxShowEvent
eventShow(GetId(), show
);
3271 eventShow
.SetEventObject(this);
3273 GetEventHandler()->ProcessEvent(eventShow
);
3278 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3280 win
->OnParentEnable(enable
);
3282 // Recurse, so that children have the opportunity to Do The Right Thing
3283 // and reset colours that have been messed up by a parent's (really ancestor's)
3285 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3287 node
= node
->GetNext() )
3289 wxWindow
*child
= node
->GetData();
3290 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3291 wxWindowNotifyEnable(child
, enable
);
3295 bool wxWindowGTK::Enable( bool enable
)
3297 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3299 if (!wxWindowBase::Enable(enable
))
3305 gtk_widget_set_sensitive( m_widget
, enable
);
3307 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3309 wxWindowNotifyEnable(this, enable
);
3314 int wxWindowGTK::GetCharHeight() const
3316 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3318 wxFont font
= GetFont();
3319 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3321 PangoContext
*context
= NULL
;
3323 context
= gtk_widget_get_pango_context( m_widget
);
3328 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3329 PangoLayout
*layout
= pango_layout_new(context
);
3330 pango_layout_set_font_description(layout
, desc
);
3331 pango_layout_set_text(layout
, "H", 1);
3332 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3334 PangoRectangle rect
;
3335 pango_layout_line_get_extents(line
, NULL
, &rect
);
3337 g_object_unref( G_OBJECT( layout
) );
3339 return (int) PANGO_PIXELS(rect
.height
);
3342 int wxWindowGTK::GetCharWidth() const
3344 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3346 wxFont font
= GetFont();
3347 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3349 PangoContext
*context
= NULL
;
3351 context
= gtk_widget_get_pango_context( m_widget
);
3356 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3357 PangoLayout
*layout
= pango_layout_new(context
);
3358 pango_layout_set_font_description(layout
, desc
);
3359 pango_layout_set_text(layout
, "g", 1);
3360 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3362 PangoRectangle rect
;
3363 pango_layout_line_get_extents(line
, NULL
, &rect
);
3365 g_object_unref( G_OBJECT( layout
) );
3367 return (int) PANGO_PIXELS(rect
.width
);
3370 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3374 int *externalLeading
,
3375 const wxFont
*theFont
) const
3377 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3379 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3388 PangoContext
*context
= NULL
;
3390 context
= gtk_widget_get_pango_context( m_widget
);
3399 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3400 PangoLayout
*layout
= pango_layout_new(context
);
3401 pango_layout_set_font_description(layout
, desc
);
3404 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3405 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3407 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3408 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3409 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3413 PangoRectangle rect
;
3414 pango_layout_get_extents(layout
, NULL
, &rect
);
3416 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3417 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3420 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3421 int baseline
= pango_layout_iter_get_baseline(iter
);
3422 pango_layout_iter_free(iter
);
3423 *descent
= *y
- PANGO_PIXELS(baseline
);
3425 if (externalLeading
) (*externalLeading
) = 0; // ??
3427 g_object_unref( G_OBJECT( layout
) );
3430 void wxWindowGTK::SetFocus()
3432 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3435 // don't do anything if we already have focus
3441 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3443 gtk_widget_grab_focus (m_wxwindow
);
3448 if (GTK_IS_CONTAINER(m_widget
))
3450 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3453 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3456 if (!GTK_WIDGET_REALIZED(m_widget
))
3458 // we can't set the focus to the widget now so we remember that
3459 // it should be focused and will do it later, during the idle
3460 // time, as soon as we can
3461 wxLogTrace(TRACE_FOCUS
,
3462 _T("Delaying setting focus to %s(%s)"),
3463 GetClassInfo()->GetClassName(), GetLabel().c_str());
3465 g_delayedFocus
= this;
3469 wxLogTrace(TRACE_FOCUS
,
3470 _T("Setting focus to %s(%s)"),
3471 GetClassInfo()->GetClassName(), GetLabel().c_str());
3473 gtk_widget_grab_focus (m_widget
);
3478 wxLogTrace(TRACE_FOCUS
,
3479 _T("Can't set focus to %s(%s)"),
3480 GetClassInfo()->GetClassName(), GetLabel().c_str());
3485 bool wxWindowGTK::AcceptsFocus() const
3487 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3490 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3492 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3494 wxWindowGTK
*oldParent
= m_parent
,
3495 *newParent
= (wxWindowGTK
*)newParentBase
;
3497 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3499 if ( !wxWindowBase::Reparent(newParent
) )
3502 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3504 /* prevent GTK from deleting the widget arbitrarily */
3505 gtk_widget_ref( m_widget
);
3509 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3512 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3516 /* insert GTK representation */
3517 (*(newParent
->m_insertCallback
))(newParent
, this);
3520 /* reverse: prevent GTK from deleting the widget arbitrarily */
3521 gtk_widget_unref( m_widget
);
3526 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3528 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3530 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3532 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3537 /* insert GTK representation */
3538 (*m_insertCallback
)(this, child
);
3541 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3543 wxWindowBase::AddChild(child
);
3544 m_dirtyTabOrder
= true;
3546 wxapp_install_idle_handler();
3549 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3551 wxWindowBase::RemoveChild(child
);
3552 m_dirtyTabOrder
= true;
3554 wxapp_install_idle_handler();
3557 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3559 wxWindowBase::DoMoveInTabOrder(win
, move
);
3560 m_dirtyTabOrder
= true;
3562 wxapp_install_idle_handler();
3565 void wxWindowGTK::RealizeTabOrder()
3569 if ( !m_children
.empty() )
3572 // we don't only construct the correct focus chain but also use
3573 // this opportunity to update the mnemonic widgets for all labels
3575 // it would be nice to extract this code from here and put it in
3576 // stattext.cpp to reduce dependencies but there is no really easy
3577 // way to do it unfortunately
3578 wxStaticText
*lastLabel
= NULL
;
3579 #endif // wxUSE_STATTEXT
3581 GList
*chain
= NULL
;
3583 for ( wxWindowList::const_iterator i
= m_children
.begin();
3584 i
!= m_children
.end();
3587 wxWindowGTK
*win
= *i
;
3591 if ( win
->AcceptsFocusFromKeyboard() )
3593 GtkLabel
*l
= GTK_LABEL(lastLabel
->m_widget
);
3594 gtk_label_set_mnemonic_widget(l
, win
->m_widget
);
3598 else // check if this one is a label
3600 lastLabel
= wxDynamicCast(win
, wxStaticText
);
3602 #endif // wxUSE_STATTEXT
3604 chain
= g_list_prepend(chain
, win
->m_widget
);
3607 chain
= g_list_reverse(chain
);
3609 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3614 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3619 void wxWindowGTK::Raise()
3621 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3623 if (m_wxwindow
&& m_wxwindow
->window
)
3625 gdk_window_raise( m_wxwindow
->window
);
3627 else if (m_widget
->window
)
3629 gdk_window_raise( m_widget
->window
);
3633 void wxWindowGTK::Lower()
3635 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3637 if (m_wxwindow
&& m_wxwindow
->window
)
3639 gdk_window_lower( m_wxwindow
->window
);
3641 else if (m_widget
->window
)
3643 gdk_window_lower( m_widget
->window
);
3647 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3649 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3651 if (cursor
== m_cursor
)
3655 wxapp_install_idle_handler();
3657 if (cursor
== wxNullCursor
)
3658 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3660 return wxWindowBase::SetCursor( cursor
);
3663 void wxWindowGTK::WarpPointer( int x
, int y
)
3665 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3667 // We provide this function ourselves as it is
3668 // missing in GDK (top of this file).
3670 GdkWindow
*window
= (GdkWindow
*) NULL
;
3672 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3674 window
= GetConnectWidget()->window
;
3677 gdk_window_warp_pointer( window
, x
, y
);
3680 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3682 double value_start
= adj
->value
;
3683 double value
= value_start
+ change
;
3684 double upper
= adj
->upper
- adj
->page_size
;
3689 // Lower bound will be checked by gtk_adjustment_set_value
3690 gtk_adjustment_set_value(adj
, value
);
3691 return adj
->value
!= value_start
;
3694 bool wxWindowGTK::ScrollLines(int lines
)
3697 m_vAdjust
!= NULL
&&
3698 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3701 bool wxWindowGTK::ScrollPages(int pages
)
3704 m_vAdjust
!= NULL
&&
3705 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3708 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3710 wxASSERT(m_vAdjust
== NULL
);
3714 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3718 if (!m_widget
->window
)
3723 GdkRectangle gdk_rect
,
3727 gdk_rect
.x
= rect
->x
;
3728 gdk_rect
.y
= rect
->y
;
3729 gdk_rect
.width
= rect
->width
;
3730 gdk_rect
.height
= rect
->height
;
3733 else // invalidate everything
3738 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3742 void wxWindowGTK::Update()
3746 // when we call Update() we really want to update the window immediately on
3747 // screen, even if it means flushing the entire queue and hence slowing down
3748 // everything -- but it should still be done, it's just that Update() should
3749 // be called very rarely
3753 void wxWindowGTK::GtkUpdate()
3755 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3756 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3758 // for consistency with other platforms (and also because it's convenient
3759 // to be able to update an entire TLW by calling Update() only once), we
3760 // should also update all our children here
3761 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3763 node
= node
->GetNext() )
3765 node
->GetData()->GtkUpdate();
3769 void wxWindowGTK::GtkSendPaintEvents()
3773 m_updateRegion
.Clear();
3777 // Clip to paint region in wxClientDC
3778 m_clipPaintRegion
= true;
3780 // widget to draw on
3781 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3783 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3785 // find ancestor from which to steal background
3786 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3788 parent
= (wxWindow
*)this;
3790 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3792 wxRegionIterator
upd( m_updateRegion
);
3796 rect
.x
= upd
.GetX();
3797 rect
.y
= upd
.GetY();
3798 rect
.width
= upd
.GetWidth();
3799 rect
.height
= upd
.GetHeight();
3801 gtk_paint_flat_box( parent
->m_widget
->style
,
3803 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3817 wxWindowDC
dc( (wxWindow
*)this );
3818 dc
.SetClippingRegion( m_updateRegion
);
3820 wxEraseEvent
erase_event( GetId(), &dc
);
3821 erase_event
.SetEventObject( this );
3823 GetEventHandler()->ProcessEvent(erase_event
);
3826 wxNcPaintEvent
nc_paint_event( GetId() );
3827 nc_paint_event
.SetEventObject( this );
3828 GetEventHandler()->ProcessEvent( nc_paint_event
);
3830 wxPaintEvent
paint_event( GetId() );
3831 paint_event
.SetEventObject( this );
3832 GetEventHandler()->ProcessEvent( paint_event
);
3834 m_clipPaintRegion
= false;
3836 m_updateRegion
.Clear();
3839 void wxWindowGTK::ClearBackground()
3841 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3845 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3847 wxWindowBase::DoSetToolTip(tip
);
3850 m_tooltip
->Apply( (wxWindow
*)this );
3853 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3855 wxString
tmp( tip
);
3856 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3858 #endif // wxUSE_TOOLTIPS
3860 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3862 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3864 if (!wxWindowBase::SetBackgroundColour(colour
))
3869 // We need the pixel value e.g. for background clearing.
3870 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3873 // apply style change (forceStyle=true so that new style is applied
3874 // even if the bg colour changed from valid to wxNullColour)
3875 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3876 ApplyWidgetStyle(true);
3881 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3883 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3885 if (!wxWindowBase::SetForegroundColour(colour
))
3892 // We need the pixel value e.g. for background clearing.
3893 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3896 // apply style change (forceStyle=true so that new style is applied
3897 // even if the bg colour changed from valid to wxNullColour):
3898 ApplyWidgetStyle(true);
3903 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3905 return gtk_widget_get_pango_context( m_widget
);
3908 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3910 // do we need to apply any changes at all?
3913 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3918 GtkRcStyle
*style
= gtk_rc_style_new();
3923 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3926 if ( m_foregroundColour
.Ok() )
3928 GdkColor
*fg
= m_foregroundColour
.GetColor();
3930 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3931 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3933 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3934 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3936 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3937 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3940 if ( m_backgroundColour
.Ok() )
3942 GdkColor
*bg
= m_backgroundColour
.GetColor();
3944 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3945 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3946 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3947 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3949 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3950 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3951 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3952 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3954 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3955 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3956 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3957 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3959 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3960 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3961 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3962 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3968 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3970 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3973 DoApplyWidgetStyle(style
);
3974 gtk_rc_style_unref(style
);
3977 // Style change may affect GTK+'s size calculation:
3978 InvalidateBestSize();
3981 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3984 gtk_widget_modify_style(m_wxwindow
, style
);
3986 gtk_widget_modify_style(m_widget
, style
);
3989 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3991 wxWindowBase::SetBackgroundStyle(style
);
3993 if (style
== wxBG_STYLE_CUSTOM
)
3995 GdkWindow
*window
= (GdkWindow
*) NULL
;
3997 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3999 window
= GetConnectWidget()->window
;
4003 // Make sure GDK/X11 doesn't refresh the window
4005 gdk_window_set_back_pixmap( window
, None
, False
);
4007 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4010 m_needsStyleChange
= false;
4013 // Do in OnIdle, because the window is not yet available
4014 m_needsStyleChange
= true;
4016 // Don't apply widget style, or we get a grey background
4020 // apply style change (forceStyle=true so that new style is applied
4021 // even if the bg colour changed from valid to wxNullColour):
4022 ApplyWidgetStyle(true);
4027 #if wxUSE_DRAG_AND_DROP
4029 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4031 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4033 GtkWidget
*dnd_widget
= GetConnectWidget();
4035 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4037 if (m_dropTarget
) delete m_dropTarget
;
4038 m_dropTarget
= dropTarget
;
4040 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4043 #endif // wxUSE_DRAG_AND_DROP
4045 GtkWidget
* wxWindowGTK::GetConnectWidget()
4047 GtkWidget
*connect_widget
= m_widget
;
4048 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4050 return connect_widget
;
4053 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4056 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4058 return (window
== m_widget
->window
);
4061 bool wxWindowGTK::SetFont( const wxFont
&font
)
4063 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4065 if (!wxWindowBase::SetFont(font
))
4068 // apply style change (forceStyle=true so that new style is applied
4069 // even if the font changed from valid to wxNullFont):
4070 ApplyWidgetStyle(true);
4075 void wxWindowGTK::DoCaptureMouse()
4077 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4079 GdkWindow
*window
= (GdkWindow
*) NULL
;
4081 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4083 window
= GetConnectWidget()->window
;
4085 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4087 wxCursor
* cursor
= & m_cursor
;
4089 cursor
= wxSTANDARD_CURSOR
;
4091 gdk_pointer_grab( window
, FALSE
,
4093 (GDK_BUTTON_PRESS_MASK
|
4094 GDK_BUTTON_RELEASE_MASK
|
4095 GDK_POINTER_MOTION_HINT_MASK
|
4096 GDK_POINTER_MOTION_MASK
),
4098 cursor
->GetCursor(),
4099 (guint32
)GDK_CURRENT_TIME
);
4100 g_captureWindow
= this;
4101 g_captureWindowHasMouse
= true;
4104 void wxWindowGTK::DoReleaseMouse()
4106 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4108 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4110 g_captureWindow
= (wxWindowGTK
*) NULL
;
4112 GdkWindow
*window
= (GdkWindow
*) NULL
;
4114 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4116 window
= GetConnectWidget()->window
;
4121 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4125 wxWindow
*wxWindowBase::GetCapture()
4127 return (wxWindow
*)g_captureWindow
;
4130 bool wxWindowGTK::IsRetained() const
4135 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4136 int range
, bool refresh
)
4138 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4140 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4142 m_hasScrolling
= true;
4144 if (orient
== wxHORIZONTAL
)
4146 float fpos
= (float)pos
;
4147 float frange
= (float)range
;
4148 float fthumb
= (float)thumbVisible
;
4149 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4150 if (fpos
< 0.0) fpos
= 0.0;
4152 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4153 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4155 SetScrollPos( orient
, pos
, refresh
);
4159 m_oldHorizontalPos
= fpos
;
4161 m_hAdjust
->lower
= 0.0;
4162 m_hAdjust
->upper
= frange
;
4163 m_hAdjust
->value
= fpos
;
4164 m_hAdjust
->step_increment
= 1.0;
4165 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4166 m_hAdjust
->page_size
= fthumb
;
4170 float fpos
= (float)pos
;
4171 float frange
= (float)range
;
4172 float fthumb
= (float)thumbVisible
;
4173 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4174 if (fpos
< 0.0) fpos
= 0.0;
4176 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4177 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4179 SetScrollPos( orient
, pos
, refresh
);
4183 m_oldVerticalPos
= fpos
;
4185 m_vAdjust
->lower
= 0.0;
4186 m_vAdjust
->upper
= frange
;
4187 m_vAdjust
->value
= fpos
;
4188 m_vAdjust
->step_increment
= 1.0;
4189 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4190 m_vAdjust
->page_size
= fthumb
;
4193 if (orient
== wxHORIZONTAL
)
4194 g_signal_emit_by_name (m_hAdjust
, "changed");
4196 g_signal_emit_by_name (m_vAdjust
, "changed");
4199 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4201 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4202 gpointer fn
= orient
== wxHORIZONTAL
4203 ? (gpointer
) gtk_window_hscroll_callback
4204 : (gpointer
) gtk_window_vscroll_callback
;
4206 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4207 g_signal_emit_by_name (adj
, "value_changed");
4208 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4211 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4213 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4214 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4216 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4218 float fpos
= (float)pos
;
4219 if (fpos
> adj
->upper
- adj
->page_size
)
4220 fpos
= adj
->upper
- adj
->page_size
;
4223 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4225 if (fabs(fpos
-adj
->value
) < 0.2)
4229 if ( m_wxwindow
->window
)
4234 int wxWindowGTK::GetScrollThumb( int orient
) const
4236 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4238 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4240 if (orient
== wxHORIZONTAL
)
4241 return (int)(m_hAdjust
->page_size
+0.5);
4243 return (int)(m_vAdjust
->page_size
+0.5);
4246 int wxWindowGTK::GetScrollPos( int orient
) const
4248 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4250 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4252 if (orient
== wxHORIZONTAL
)
4253 return (int)(m_hAdjust
->value
+0.5);
4255 return (int)(m_vAdjust
->value
+0.5);
4258 int wxWindowGTK::GetScrollRange( int orient
) const
4260 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4262 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4264 if (orient
== wxHORIZONTAL
)
4265 return (int)(m_hAdjust
->upper
+0.5);
4267 return (int)(m_vAdjust
->upper
+0.5);
4270 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4272 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4274 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4276 // No scrolling requested.
4277 if ((dx
== 0) && (dy
== 0)) return;
4279 m_clipPaintRegion
= true;
4281 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4283 m_clipPaintRegion
= false;
4286 void wxWindowGTK::SetWindowStyleFlag( long style
)
4288 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4289 wxWindowBase::SetWindowStyleFlag(style
);
4292 // Find the wxWindow at the current mouse position, also returning the mouse
4294 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4296 pt
= wxGetMousePosition();
4297 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4301 // Get the current mouse position.
4302 wxPoint
wxGetMousePosition()
4304 /* This crashes when used within wxHelpContext,
4305 so we have to use the X-specific implementation below.
4307 GdkModifierType *mask;
4308 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4310 return wxPoint(x, y);
4314 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4316 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4317 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4318 Window rootReturn
, childReturn
;
4319 int rootX
, rootY
, winX
, winY
;
4320 unsigned int maskReturn
;
4322 XQueryPointer (display
,
4326 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4327 return wxPoint(rootX
, rootY
);
4331 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4332 void wxAddGrab(wxWindow
* window
)
4334 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4337 void wxRemoveGrab(wxWindow
* window
)
4339 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4342 // ----------------------------------------------------------------------------
4344 // ----------------------------------------------------------------------------
4346 class wxWinModule
: public wxModule
4353 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4356 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4358 bool wxWinModule::OnInit()
4360 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4361 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4366 void wxWinModule::OnExit()
4369 gdk_gc_unref( g_eraseGC
);