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 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
60 #include <gtk/gtkversion.h>
61 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
62 #undef GTK_DISABLE_DEPRECATED
65 #include "wx/gtk/private.h"
66 #include <gdk/gdkprivate.h>
67 #include <gdk/gdkkeysyms.h>
71 #include <gtk/gtkprivate.h>
73 #include "wx/gtk/win_gtk.h"
75 #include <pango/pangox.h>
81 extern GtkContainerClass
*pizza_parent_class
;
83 //-----------------------------------------------------------------------------
84 // documentation on internals
85 //-----------------------------------------------------------------------------
88 I have been asked several times about writing some documentation about
89 the GTK port of wxWidgets, especially its internal structures. Obviously,
90 you cannot understand wxGTK without knowing a little about the GTK, but
91 some more information about what the wxWindow, which is the base class
92 for all other window classes, does seems required as well.
96 What does wxWindow do? It contains the common interface for the following
97 jobs of its descendants:
99 1) Define the rudimentary behaviour common to all window classes, such as
100 resizing, intercepting user input (so as to make it possible to use these
101 events for special purposes in a derived class), window names etc.
103 2) Provide the possibility to contain and manage children, if the derived
104 class is allowed to contain children, which holds true for those window
105 classes which do not display a native GTK widget. To name them, these
106 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
107 work classes are a special case and are handled a bit differently from
108 the rest. The same holds true for the wxNotebook class.
110 3) Provide the possibility to draw into a client area of a window. This,
111 too, only holds true for classes that do not display a native GTK widget
114 4) Provide the entire mechanism for scrolling widgets. This actual inter-
115 face for this is usually in wxScrolledWindow, but the GTK implementation
118 5) A multitude of helper or extra methods for special purposes, such as
119 Drag'n'Drop, managing validators etc.
121 6) Display a border (sunken, raised, simple or none).
123 Normally one might expect, that one wxWidgets window would always correspond
124 to one GTK widget. Under GTK, there is no such allround widget that has all
125 the functionality. Moreover, the GTK defines a client area as a different
126 widget from the actual widget you are handling. Last but not least some
127 special classes (e.g. wxFrame) handle different categories of widgets and
128 still have the possibility to draw something in the client area.
129 It was therefore required to write a special purpose GTK widget, that would
130 represent a client area in the sense of wxWidgets capable to do the jobs
131 2), 3) and 4). I have written this class and it resides in win_gtk.c of
134 All windows must have a widget, with which they interact with other under-
135 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
136 the wxWindow class has a member variable called m_widget which holds a
137 pointer to this widget. When the window class represents a GTK native widget,
138 this is (in most cases) the only GTK widget the class manages. E.g. the
139 wxStaticText class handles only a GtkLabel widget a pointer to which you
140 can find in m_widget (defined in wxWindow)
142 When the class has a client area for drawing into and for containing children
143 it has to handle the client area widget (of the type GtkPizza, defined in
144 win_gtk.c), but there could be any number of widgets, handled by a class
145 The common rule for all windows is only, that the widget that interacts with
146 the rest of GTK must be referenced in m_widget and all other widgets must be
147 children of this widget on the GTK level. The top-most widget, which also
148 represents the client area, must be in the m_wxwindow field and must be of
151 As I said, the window classes that display a GTK native widget only have
152 one widget, so in the case of e.g. the wxButton class m_widget holds a
153 pointer to a GtkButton widget. But windows with client areas (for drawing
154 and children) have a m_widget field that is a pointer to a GtkScrolled-
155 Window and a m_wxwindow field that is pointer to a GtkPizza and this
156 one is (in the GTK sense) a child of the GtkScrolledWindow.
158 If the m_wxwindow field is set, then all input to this widget is inter-
159 cepted and sent to the wxWidgets class. If not, all input to the widget
160 that gets pointed to by m_widget gets intercepted and sent to the class.
164 The design of scrolling in wxWidgets is markedly different from that offered
165 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
166 clicking on a scrollbar belonging to scrolled window will inevitably move
167 the window. In wxWidgets, the scrollbar will only emit an event, send this
168 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
169 which actually moves the window and its subchildren. Note that GtkPizza
170 memorizes how much it has been scrolled but that wxWidgets forgets this
171 so that the two coordinates systems have to be kept in synch. This is done
172 in various places using the pizza->xoffset and pizza->yoffset values.
176 Singularily the most broken code in GTK is the code that is supposed to
177 inform subwindows (child windows) about new positions. Very often, duplicate
178 events are sent without changes in size or position, equally often no
179 events are sent at all (All this is due to a bug in the GtkContainer code
180 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
181 GTK's own system and it simply waits for size events for toplevel windows
182 and then iterates down the respective size events to all window. This has
183 the disadvantage that windows might get size events before the GTK widget
184 actually has the reported size. This doesn't normally pose any problem, but
185 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
186 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
187 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
188 window that is used for OpenGL output really has that size (as reported by
193 If someone at some point of time feels the immense desire to have a look at,
194 change or attempt to optimise the Refresh() logic, this person will need an
195 intimate understanding of what "draw" and "expose" events are and what
196 they are used for, in particular when used in connection with GTK's
197 own windowless widgets. Beware.
201 Cursors, too, have been a constant source of pleasure. The main difficulty
202 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
203 for the parent. To prevent this from doing too much harm, I use idle time
204 to set the cursor over and over again, starting from the toplevel windows
205 and ending with the youngest generation (speaking of parent and child windows).
206 Also don't forget that cursors (like much else) are connected to GdkWindows,
207 not GtkWidgets and that the "window" field of a GtkWidget might very well
208 point to the GdkWindow of the parent widget (-> "window-less widget") and
209 that the two obviously have very different meanings.
213 //-----------------------------------------------------------------------------
215 //-----------------------------------------------------------------------------
217 extern wxList wxPendingDelete
;
218 extern bool g_blockEventsOnDrag
;
219 extern bool g_blockEventsOnScroll
;
220 extern wxCursor g_globalCursor
;
222 static GdkGC
*g_eraseGC
= NULL
;
224 // mouse capture state: the window which has it and if the mouse is currently
226 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
227 static bool g_captureWindowHasMouse
= false;
229 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
231 // the last window which had the focus - this is normally never NULL (except
232 // if we never had focus at all) as even when g_focusWindow is NULL it still
233 // keeps its previous value
234 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
236 // If a window get the focus set but has not been realized
237 // yet, defer setting the focus to idle time.
238 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
240 extern bool g_mainThreadLocked
;
242 //-----------------------------------------------------------------------------
244 //-----------------------------------------------------------------------------
249 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
251 # define DEBUG_MAIN_THREAD
254 #define DEBUG_MAIN_THREAD
257 // the trace mask used for the focus debugging messages
258 #define TRACE_FOCUS _T("focus")
260 //-----------------------------------------------------------------------------
261 // missing gdk functions
262 //-----------------------------------------------------------------------------
265 gdk_window_warp_pointer (GdkWindow
*window
,
270 window
= GDK_ROOT_PARENT();
272 if (!GDK_WINDOW_DESTROYED(window
))
274 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
275 None
, /* not source window -> move from anywhere */
276 GDK_WINDOW_XID(window
), /* dest window */
277 0, 0, 0, 0, /* not source window -> move from anywhere */
282 //-----------------------------------------------------------------------------
284 //-----------------------------------------------------------------------------
286 extern void wxapp_install_idle_handler();
287 extern bool g_isIdle
;
289 //-----------------------------------------------------------------------------
290 // local code (see below)
291 //-----------------------------------------------------------------------------
293 // returns the child of win which currently has focus or NULL if not found
295 // Note: can't be static, needed by textctrl.cpp.
296 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
298 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
300 return (wxWindow
*)NULL
;
302 if ( winFocus
== win
)
303 return (wxWindow
*)win
;
305 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
307 node
= node
->GetNext() )
309 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
314 return (wxWindow
*)NULL
;
317 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
319 // wxUniversal widgets draw the borders and scrollbars themselves
320 #ifndef __WXUNIVERSAL__
327 if (win
->m_hasScrolling
)
329 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
331 GtkRequisition vscroll_req
;
332 vscroll_req
.width
= 2;
333 vscroll_req
.height
= 2;
334 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
335 (scroll_window
->vscrollbar
, &vscroll_req
);
337 GtkRequisition hscroll_req
;
338 hscroll_req
.width
= 2;
339 hscroll_req
.height
= 2;
340 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
341 (scroll_window
->hscrollbar
, &hscroll_req
);
343 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
345 if (scroll_window
->vscrollbar_visible
)
347 dw
+= vscroll_req
.width
;
348 dw
+= scroll_class
->scrollbar_spacing
;
351 if (scroll_window
->hscrollbar_visible
)
353 dh
+= hscroll_req
.height
;
354 dh
+= scroll_class
->scrollbar_spacing
;
360 if (GTK_WIDGET_NO_WINDOW (widget
))
362 dx
+= widget
->allocation
.x
;
363 dy
+= widget
->allocation
.y
;
366 if (win
->HasFlag(wxRAISED_BORDER
))
368 gtk_paint_shadow (widget
->style
,
372 NULL
, NULL
, NULL
, // FIXME: No clipping?
374 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
378 if (win
->HasFlag(wxSUNKEN_BORDER
))
380 gtk_paint_shadow (widget
->style
,
384 NULL
, NULL
, NULL
, // FIXME: No clipping?
386 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
390 if (win
->HasFlag(wxSIMPLE_BORDER
))
393 gc
= gdk_gc_new( widget
->window
);
394 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
395 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
397 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
401 #endif // __WXUNIVERSAL__
404 //-----------------------------------------------------------------------------
405 // "expose_event" of m_widget
406 //-----------------------------------------------------------------------------
409 static gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
411 if (gdk_event
->count
> 0) return FALSE
;
413 draw_frame( widget
, win
);
415 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
421 //-----------------------------------------------------------------------------
422 // "size_request" of m_widget
423 //-----------------------------------------------------------------------------
425 // make it extern because wxStaticText needs to disconnect this one
427 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
428 GtkRequisition
*requisition
,
432 win
->GetSize( &w
, &h
);
438 requisition
->height
= h
;
439 requisition
->width
= w
;
445 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
446 GtkRequisition
*requisition
,
449 // This callback is actually hooked into the text entry
450 // of the combo box, not the GtkHBox.
453 win
->GetSize( &w
, &h
);
459 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
461 GtkRequisition entry_req
;
463 entry_req
.height
= 2;
464 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
465 (gcombo
->button
, &entry_req
);
467 requisition
->width
= w
- entry_req
.width
;
468 requisition
->height
= entry_req
.height
;
472 //-----------------------------------------------------------------------------
473 // "expose_event" of m_wxwindow
474 //-----------------------------------------------------------------------------
477 static int gtk_window_expose_callback( GtkWidget
*widget
,
478 GdkEventExpose
*gdk_event
,
484 wxapp_install_idle_handler();
486 // This callback gets called in drawing-idle time under
487 // GTK 2.0, so we don't need to defer anything to idle
490 GtkPizza
*pizza
= GTK_PIZZA( widget
);
491 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
496 wxPrintf( wxT("OnExpose from ") );
497 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
498 wxPrintf( win
->GetClassInfo()->GetClassName() );
499 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
500 (int)gdk_event
->area
.y
,
501 (int)gdk_event
->area
.width
,
502 (int)gdk_event
->area
.height
);
507 win
->m_wxwindow
->style
,
511 (GdkRectangle
*) NULL
,
513 (char *)"button", // const_cast
518 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
520 win
->GtkSendPaintEvents();
523 // Let parent window draw window-less widgets
524 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
530 //-----------------------------------------------------------------------------
531 // "key_press_event" from any window
532 //-----------------------------------------------------------------------------
534 // set WXTRACE to this to see the key event codes on the console
535 #define TRACE_KEYS _T("keyevent")
537 // translates an X key symbol to WXK_XXX value
539 // if isChar is true it means that the value returned will be used for EVT_CHAR
540 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
541 // for example, while if it is false it means that the value is going to be
542 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
544 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
550 // Shift, Control and Alt don't generate the CHAR events at all
553 key_code
= isChar
? 0 : WXK_SHIFT
;
557 key_code
= isChar
? 0 : WXK_CONTROL
;
565 key_code
= isChar
? 0 : WXK_ALT
;
568 // neither do the toggle modifies
569 case GDK_Scroll_Lock
:
570 key_code
= isChar
? 0 : WXK_SCROLL
;
574 key_code
= isChar
? 0 : WXK_CAPITAL
;
578 key_code
= isChar
? 0 : WXK_NUMLOCK
;
582 // various other special keys
595 case GDK_ISO_Left_Tab
:
602 key_code
= WXK_RETURN
;
606 key_code
= WXK_CLEAR
;
610 key_code
= WXK_PAUSE
;
614 key_code
= WXK_SELECT
;
618 key_code
= WXK_PRINT
;
622 key_code
= WXK_EXECUTE
;
626 key_code
= WXK_ESCAPE
;
629 // cursor and other extended keyboard keys
631 key_code
= WXK_DELETE
;
647 key_code
= WXK_RIGHT
;
654 case GDK_Prior
: // == GDK_Page_Up
655 key_code
= WXK_PRIOR
;
658 case GDK_Next
: // == GDK_Page_Down
671 key_code
= WXK_INSERT
;
686 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
690 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
694 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
698 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
702 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
706 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
710 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
714 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
718 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
722 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
726 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
730 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
734 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
737 case GDK_KP_Prior
: // == GDK_KP_Page_Up
738 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
741 case GDK_KP_Next
: // == GDK_KP_Page_Down
742 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
746 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
750 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
754 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
758 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
762 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
765 case GDK_KP_Multiply
:
766 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
770 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
773 case GDK_KP_Separator
:
774 // FIXME: what is this?
775 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
778 case GDK_KP_Subtract
:
779 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
783 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
787 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
804 key_code
= WXK_F1
+ keysym
- GDK_F1
;
814 static inline bool wxIsAsciiKeysym(KeySym ks
)
819 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
821 GdkEventKey
*gdk_event
)
825 GdkModifierType state
;
826 if (gdk_event
->window
)
827 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
829 event
.SetTimestamp( gdk_event
->time
);
830 event
.SetId(win
->GetId());
831 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
832 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
833 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
834 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
835 event
.m_scanCode
= gdk_event
->keyval
;
836 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
837 event
.m_rawFlags
= 0;
839 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
840 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
842 event
.m_uniChar
= toupper(event
.m_uniChar
);
845 wxGetMousePosition( &x
, &y
);
846 win
->ScreenToClient( &x
, &y
);
849 event
.SetEventObject( win
);
854 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
856 GdkEventKey
*gdk_event
)
858 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
859 // but only event->keyval which is quite useless to us, so remember
860 // the last character from GDK_KEY_PRESS and reuse it as last resort
862 // NB: should be MT-safe as we're always called from the main thread only
867 } s_lastKeyPress
= { 0, 0 };
869 KeySym keysym
= gdk_event
->keyval
;
871 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
872 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
876 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
880 // do we have the translation or is it a plain ASCII character?
881 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
883 // we should use keysym if it is ASCII as X does some translations
884 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
885 // which we don't want here (but which we do use for OnChar())
886 if ( !wxIsAsciiKeysym(keysym
) )
888 keysym
= (KeySym
)gdk_event
->string
[0];
891 // we want to always get the same key code when the same key is
892 // pressed regardless of the state of the modifiers, i.e. on a
893 // standard US keyboard pressing '5' or '%' ('5' key with
894 // Shift) should result in the same key code in OnKeyDown():
895 // '5' (although OnChar() will get either '5' or '%').
897 // to do it we first translate keysym to keycode (== scan code)
898 // and then back but always using the lower register
899 Display
*dpy
= (Display
*)wxGetDisplay();
900 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
902 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
904 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
906 // use the normalized, i.e. lower register, keysym if we've
908 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
910 // as explained above, we want to have lower register key codes
911 // normally but for the letter keys we want to have the upper ones
913 // NB: don't use XConvertCase() here, we want to do it for letters
915 key_code
= toupper(key_code
);
917 else // non ASCII key, what to do?
919 // by default, ignore it
922 // but if we have cached information from the last KEY_PRESS
923 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
926 if ( keysym
== s_lastKeyPress
.keysym
)
928 key_code
= s_lastKeyPress
.keycode
;
933 if ( gdk_event
->type
== GDK_KEY_PRESS
)
935 // remember it to be reused for KEY_UP event later
936 s_lastKeyPress
.keysym
= keysym
;
937 s_lastKeyPress
.keycode
= key_code
;
941 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
943 // sending unknown key events doesn't really make sense
947 // now fill all the other fields
948 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
950 event
.m_keyCode
= key_code
;
958 GtkIMContext
*context
;
959 GdkEventKey
*lastKeyEvent
;
963 context
= gtk_im_multicontext_new();
968 g_object_unref(context
);
973 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
974 GdkEventKey
*gdk_event
,
980 wxapp_install_idle_handler();
984 if (g_blockEventsOnDrag
)
988 wxKeyEvent
event( wxEVT_KEY_DOWN
);
990 bool return_after_IM
= false;
992 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
994 // Emit KEY_DOWN event
995 ret
= win
->GetEventHandler()->ProcessEvent( event
);
999 // Return after IM processing as we cannot do
1000 // anything with it anyhow.
1001 return_after_IM
= true;
1004 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1005 // When we get a key_press event here, it could be originate
1006 // from the current widget or its child widgets. However, only the widget
1007 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1008 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1009 // originated from its child widgets and shouldn't be passed to IM context.
1010 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1011 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1012 // widgets has both IM context and input focus, the event should be filtered
1013 // by gtk_im_context_filter_keypress().
1014 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1015 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1017 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1018 // docs, if IM filter returns true, no further processing should be done.
1019 // we should send the key_down event anyway.
1020 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1021 win
->m_imData
->lastKeyEvent
= NULL
;
1022 if (intercepted_by_IM
)
1024 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1029 if (return_after_IM
)
1035 wxWindowGTK
*ancestor
= win
;
1038 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1041 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1042 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1045 if (ancestor
->IsTopLevel())
1047 ancestor
= ancestor
->GetParent();
1050 #endif // wxUSE_ACCEL
1052 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1053 // will only be sent if it is not in an accelerator table.
1057 KeySym keysym
= gdk_event
->keyval
;
1058 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1059 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1062 if ( wxIsAsciiKeysym(keysym
) )
1065 key_code
= (unsigned char)keysym
;
1067 // gdk_event->string is actually deprecated
1068 else if ( gdk_event
->length
== 1 )
1070 key_code
= (unsigned char)gdk_event
->string
[0];
1076 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1078 event
.m_keyCode
= key_code
;
1080 // To conform to the docs we need to translate Ctrl-alpha
1081 // characters to values in the range 1-26.
1082 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1084 event
.m_keyCode
= key_code
- 'a' + 1;
1086 event
.m_uniChar
= event
.m_keyCode
;
1090 // Implement OnCharHook by checking ancestor top level windows
1091 wxWindow
*parent
= win
;
1092 while (parent
&& !parent
->IsTopLevel())
1093 parent
= parent
->GetParent();
1096 event
.SetEventType( wxEVT_CHAR_HOOK
);
1097 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1102 event
.SetEventType(wxEVT_CHAR
);
1103 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1112 // win is a control: tab can be propagated up
1114 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1115 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1116 // have this style, yet choose not to process this particular TAB in which
1117 // case TAB must still work as a navigational character
1118 // JS: enabling again to make consistent with other platforms
1119 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1120 // navigation behaviour)
1122 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1124 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1126 wxNavigationKeyEvent new_event
;
1127 new_event
.SetEventObject( win
->GetParent() );
1128 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1129 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1130 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1131 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1132 new_event
.SetCurrentFocus( win
);
1133 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1136 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1138 (gdk_event
->keyval
== GDK_Escape
) )
1140 // however only do it if we have a Cancel button in the dialog,
1141 // otherwise the user code may get confused by the events from a
1142 // non-existing button and, worse, a wxButton might get button event
1143 // from another button which is not really expected
1144 wxWindow
*winForCancel
= win
,
1146 while ( winForCancel
)
1148 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1151 // found a cancel button
1155 if ( winForCancel
->IsTopLevel() )
1157 // no need to look further
1161 // maybe our parent has a cancel button?
1162 winForCancel
= winForCancel
->GetParent();
1167 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1168 eventClick
.SetEventObject(btnCancel
);
1169 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1175 g_signal_stop_emission_by_name (widget
, "key_press_event");
1184 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1188 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1190 // take modifiers, cursor position, timestamp etc. from the last
1191 // key_press_event that was fed into Input Method:
1192 if (window
->m_imData
->lastKeyEvent
)
1194 wxFillOtherKeyEventFields(event
,
1195 window
, window
->m_imData
->lastKeyEvent
);
1199 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1201 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1202 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1203 #endif // wxUSE_UNICODE
1204 if( !(const wxChar
*)data
)
1209 // Implement OnCharHook by checking ancestor top level windows
1210 wxWindow
*parent
= window
;
1211 while (parent
&& !parent
->IsTopLevel())
1212 parent
= parent
->GetParent();
1214 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1217 event
.m_uniChar
= *pstr
;
1218 // Backward compatible for ISO-8859-1
1219 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1220 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1222 event
.m_keyCode
= *pstr
;
1223 #endif // wxUSE_UNICODE
1225 // To conform to the docs we need to translate Ctrl-alpha
1226 // characters to values in the range 1-26.
1227 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1229 event
.m_keyCode
= *pstr
- 'a' + 1;
1231 event
.m_uniChar
= event
.m_keyCode
;
1237 event
.SetEventType( wxEVT_CHAR_HOOK
);
1238 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1243 event
.SetEventType(wxEVT_CHAR
);
1244 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1251 //-----------------------------------------------------------------------------
1252 // "key_release_event" from any window
1253 //-----------------------------------------------------------------------------
1256 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1257 GdkEventKey
*gdk_event
,
1263 wxapp_install_idle_handler();
1268 if (g_blockEventsOnDrag
)
1271 wxKeyEvent
event( wxEVT_KEY_UP
);
1272 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1274 // unknown key pressed, ignore (the event would be useless anyhow)
1278 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1281 g_signal_stop_emission_by_name (widget
, "key_release_event");
1286 // ============================================================================
1288 // ============================================================================
1290 // ----------------------------------------------------------------------------
1291 // mouse event processing helpers
1292 // ----------------------------------------------------------------------------
1294 // init wxMouseEvent with the info from GdkEventXXX struct
1295 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1296 wxMouseEvent
& event
,
1299 event
.SetTimestamp( gdk_event
->time
);
1300 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1301 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1302 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1303 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1304 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1305 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1306 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1307 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1309 event
.m_linesPerAction
= 3;
1310 event
.m_wheelDelta
= 120;
1311 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1312 event
.m_wheelRotation
= 120;
1313 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1314 event
.m_wheelRotation
= -120;
1317 wxPoint pt
= win
->GetClientAreaOrigin();
1318 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1319 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1321 event
.SetEventObject( win
);
1322 event
.SetId( win
->GetId() );
1323 event
.SetTimestamp( gdk_event
->time
);
1326 static void AdjustEventButtonState(wxMouseEvent
& event
)
1328 // GDK reports the old state of the button for a button press event, but
1329 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1330 // for a LEFT_DOWN event, not FALSE, so we will invert
1331 // left/right/middleDown for the corresponding click events
1333 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1334 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1335 (event
.GetEventType() == wxEVT_LEFT_UP
))
1337 event
.m_leftDown
= !event
.m_leftDown
;
1341 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1342 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1343 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1345 event
.m_middleDown
= !event
.m_middleDown
;
1349 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1350 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1351 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1353 event
.m_rightDown
= !event
.m_rightDown
;
1358 // find the window to send the mouse event too
1360 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1365 if (win
->m_wxwindow
)
1367 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1368 xx
+= pizza
->xoffset
;
1369 yy
+= pizza
->yoffset
;
1372 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1375 wxWindowGTK
*child
= node
->GetData();
1377 node
= node
->GetNext();
1378 if (!child
->IsShown())
1381 if (child
->IsTransparentForMouse())
1383 // wxStaticBox is transparent in the box itself
1384 int xx1
= child
->m_x
;
1385 int yy1
= child
->m_y
;
1386 int xx2
= child
->m_x
+ child
->m_width
;
1387 int yy2
= child
->m_y
+ child
->m_height
;
1390 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1392 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1394 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1396 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1407 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1408 (child
->m_x
<= xx
) &&
1409 (child
->m_y
<= yy
) &&
1410 (child
->m_x
+child
->m_width
>= xx
) &&
1411 (child
->m_y
+child
->m_height
>= yy
))
1424 //-----------------------------------------------------------------------------
1425 // "button_press_event"
1426 //-----------------------------------------------------------------------------
1429 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1430 GdkEventButton
*gdk_event
,
1436 wxapp_install_idle_handler();
1439 wxPrintf( wxT("1) OnButtonPress from ") );
1440 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1441 wxPrintf( win->GetClassInfo()->GetClassName() );
1442 wxPrintf( wxT(".\n") );
1444 if (!win
->m_hasVMT
) return FALSE
;
1445 if (g_blockEventsOnDrag
) return TRUE
;
1446 if (g_blockEventsOnScroll
) return TRUE
;
1448 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1450 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1452 gtk_widget_grab_focus( win
->m_wxwindow
);
1454 wxPrintf( wxT("GrabFocus from ") );
1455 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1456 wxPrintf( win->GetClassInfo()->GetClassName() );
1457 wxPrintf( wxT(".\n") );
1461 // GDK sends surplus button down events
1462 // before a double click event. We
1463 // need to filter these out.
1464 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1466 GdkEvent
*peek_event
= gdk_event_peek();
1469 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1470 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1472 gdk_event_free( peek_event
);
1477 gdk_event_free( peek_event
);
1482 wxEventType event_type
= wxEVT_NULL
;
1484 // GdkDisplay is a GTK+ 2.2.0 thing
1485 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1486 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1487 !gtk_check_version(2,2,0) &&
1488 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1490 // Reset GDK internal timestamp variables in order to disable GDK
1491 // triple click events. GDK will then next time believe no button has
1492 // been clicked just before, and send a normal button click event.
1493 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1494 display
->button_click_time
[1] = 0;
1495 display
->button_click_time
[0] = 0;
1499 if (gdk_event
->button
== 1)
1501 // note that GDK generates triple click events which are not supported
1502 // by wxWidgets but still have to be passed to the app as otherwise
1503 // clicks would simply go missing
1504 switch (gdk_event
->type
)
1506 // we shouldn't get triple clicks at all for GTK2 because we
1507 // suppress them artificially using the code above but we still
1508 // should map them to something for GTK1 and not just ignore them
1509 // as this would lose clicks
1510 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1511 case GDK_BUTTON_PRESS
:
1512 event_type
= wxEVT_LEFT_DOWN
;
1515 case GDK_2BUTTON_PRESS
:
1516 event_type
= wxEVT_LEFT_DCLICK
;
1520 // just to silence gcc warnings
1524 else if (gdk_event
->button
== 2)
1526 switch (gdk_event
->type
)
1528 case GDK_3BUTTON_PRESS
:
1529 case GDK_BUTTON_PRESS
:
1530 event_type
= wxEVT_MIDDLE_DOWN
;
1533 case GDK_2BUTTON_PRESS
:
1534 event_type
= wxEVT_MIDDLE_DCLICK
;
1541 else if (gdk_event
->button
== 3)
1543 switch (gdk_event
->type
)
1545 case GDK_3BUTTON_PRESS
:
1546 case GDK_BUTTON_PRESS
:
1547 event_type
= wxEVT_RIGHT_DOWN
;
1550 case GDK_2BUTTON_PRESS
:
1551 event_type
= wxEVT_RIGHT_DCLICK
;
1558 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1560 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1562 event_type
= wxEVT_MOUSEWHEEL
;
1566 if ( event_type
== wxEVT_NULL
)
1568 // unknown mouse button or click type
1572 wxMouseEvent
event( event_type
);
1573 InitMouseEvent( win
, event
, gdk_event
);
1575 AdjustEventButtonState(event
);
1577 // wxListBox actually gets mouse events from the item, so we need to give it
1578 // a chance to correct this
1579 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1581 // find the correct window to send the event to: it may be a different one
1582 // from the one which got it at GTK+ level because some controls don't have
1583 // their own X window and thus cannot get any events.
1584 if ( !g_captureWindow
)
1585 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1587 if (win
->GetEventHandler()->ProcessEvent( event
))
1589 g_signal_stop_emission_by_name (widget
, "button_press_event");
1593 if (event_type
== wxEVT_RIGHT_DOWN
)
1595 // generate a "context menu" event: this is similar to right mouse
1596 // click under many GUIs except that it is generated differently
1597 // (right up under MSW, ctrl-click under Mac, right down here) and
1599 // (a) it's a command event and so is propagated to the parent
1600 // (b) under some ports it can be generated from kbd too
1601 // (c) it uses screen coords (because of (a))
1602 wxContextMenuEvent
evtCtx(
1605 win
->ClientToScreen(event
.GetPosition()));
1606 evtCtx
.SetEventObject(win
);
1607 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1614 //-----------------------------------------------------------------------------
1615 // "button_release_event"
1616 //-----------------------------------------------------------------------------
1619 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1620 GdkEventButton
*gdk_event
,
1626 wxapp_install_idle_handler();
1628 if (!win
->m_hasVMT
) return FALSE
;
1629 if (g_blockEventsOnDrag
) return FALSE
;
1630 if (g_blockEventsOnScroll
) return FALSE
;
1632 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1634 wxEventType event_type
= wxEVT_NULL
;
1636 switch (gdk_event
->button
)
1639 event_type
= wxEVT_LEFT_UP
;
1643 event_type
= wxEVT_MIDDLE_UP
;
1647 event_type
= wxEVT_RIGHT_UP
;
1651 // unknwon button, don't process
1655 wxMouseEvent
event( event_type
);
1656 InitMouseEvent( win
, event
, gdk_event
);
1658 AdjustEventButtonState(event
);
1660 // same wxListBox hack as above
1661 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1663 if ( !g_captureWindow
)
1664 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1666 if (win
->GetEventHandler()->ProcessEvent( event
))
1668 g_signal_stop_emission_by_name (widget
, "button_release_event");
1676 //-----------------------------------------------------------------------------
1677 // "motion_notify_event"
1678 //-----------------------------------------------------------------------------
1681 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1682 GdkEventMotion
*gdk_event
,
1688 wxapp_install_idle_handler();
1690 if (!win
->m_hasVMT
) return FALSE
;
1691 if (g_blockEventsOnDrag
) return FALSE
;
1692 if (g_blockEventsOnScroll
) return FALSE
;
1694 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1696 if (gdk_event
->is_hint
)
1700 GdkModifierType state
;
1701 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1707 printf( "OnMotion from " );
1708 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1709 printf( win->GetClassInfo()->GetClassName() );
1713 wxMouseEvent
event( wxEVT_MOTION
);
1714 InitMouseEvent(win
, event
, gdk_event
);
1716 if ( g_captureWindow
)
1718 // synthetize a mouse enter or leave event if needed
1719 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1720 // This seems to be necessary and actually been added to
1721 // GDK itself in version 2.0.X
1724 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1725 if ( hasMouse
!= g_captureWindowHasMouse
)
1727 // the mouse changed window
1728 g_captureWindowHasMouse
= hasMouse
;
1730 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1731 : wxEVT_LEAVE_WINDOW
);
1732 InitMouseEvent(win
, eventM
, gdk_event
);
1733 eventM
.SetEventObject(win
);
1734 win
->GetEventHandler()->ProcessEvent(eventM
);
1739 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1742 if (win
->GetEventHandler()->ProcessEvent( event
))
1744 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1752 //-----------------------------------------------------------------------------
1753 // "mouse_wheel_event"
1754 //-----------------------------------------------------------------------------
1757 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1758 GdkEventScroll
* gdk_event
,
1764 wxapp_install_idle_handler();
1766 wxEventType event_type
= wxEVT_NULL
;
1767 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1768 event_type
= wxEVT_MOUSEWHEEL
;
1769 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1770 event_type
= wxEVT_MOUSEWHEEL
;
1774 wxMouseEvent
event( event_type
);
1775 // Can't use InitMouse macro because scroll events don't have button
1776 event
.SetTimestamp( gdk_event
->time
);
1777 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1778 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1779 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1780 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1781 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1782 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1783 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1784 event
.m_linesPerAction
= 3;
1785 event
.m_wheelDelta
= 120;
1786 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1787 event
.m_wheelRotation
= 120;
1789 event
.m_wheelRotation
= -120;
1791 wxPoint pt
= win
->GetClientAreaOrigin();
1792 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1793 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1795 event
.SetEventObject( win
);
1796 event
.SetId( win
->GetId() );
1797 event
.SetTimestamp( gdk_event
->time
);
1799 if (win
->GetEventHandler()->ProcessEvent( event
))
1801 g_signal_stop_emission_by_name (widget
, "scroll_event");
1809 //-----------------------------------------------------------------------------
1811 //-----------------------------------------------------------------------------
1813 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1815 wxContextMenuEvent
event(
1819 event
.SetEventObject(win
);
1820 return win
->GetEventHandler()->ProcessEvent(event
);
1824 //-----------------------------------------------------------------------------
1826 //-----------------------------------------------------------------------------
1828 // send the wxChildFocusEvent and wxFocusEvent, common code of
1829 // gtk_window_focus_in_callback() and SetFocus()
1830 static bool DoSendFocusEvents(wxWindow
*win
)
1832 // Notify the parent keeping track of focus for the kbd navigation
1833 // purposes that we got it.
1834 wxChildFocusEvent
eventChildFocus(win
);
1835 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1837 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1838 eventFocus
.SetEventObject(win
);
1840 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1844 static gboolean
gtk_window_focus_in_callback( GtkWidget
*widget
,
1845 GdkEvent
*WXUNUSED(event
),
1851 wxapp_install_idle_handler();
1854 gtk_im_context_focus_in(win
->m_imData
->context
);
1857 g_focusWindow
= win
;
1859 wxLogTrace(TRACE_FOCUS
,
1860 _T("%s: focus in"), win
->GetName().c_str());
1864 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1868 // caret needs to be informed about focus change
1869 wxCaret
*caret
= win
->GetCaret();
1872 caret
->OnSetFocus();
1874 #endif // wxUSE_CARET
1876 gboolean ret
= FALSE
;
1878 // does the window itself think that it has the focus?
1879 if ( !win
->m_hasFocus
)
1881 // not yet, notify it
1882 win
->m_hasFocus
= true;
1884 (void)DoSendFocusEvents(win
);
1889 // Disable default focus handling for custom windows
1890 // since the default GTK+ handler issues a repaint
1891 if (win
->m_wxwindow
)
1898 //-----------------------------------------------------------------------------
1899 // "focus_out_event"
1900 //-----------------------------------------------------------------------------
1903 static gboolean
gtk_window_focus_out_callback( GtkWidget
*widget
,
1904 GdkEventFocus
*gdk_event
,
1910 wxapp_install_idle_handler();
1913 gtk_im_context_focus_out(win
->m_imData
->context
);
1915 wxLogTrace( TRACE_FOCUS
,
1916 _T("%s: focus out"), win
->GetName().c_str() );
1919 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1923 g_focusWindow
= (wxWindowGTK
*)NULL
;
1931 // caret needs to be informed about focus change
1932 wxCaret
*caret
= win
->GetCaret();
1935 caret
->OnKillFocus();
1937 #endif // wxUSE_CARET
1939 gboolean ret
= FALSE
;
1941 // don't send the window a kill focus event if it thinks that it doesn't
1942 // have focus already
1943 if ( win
->m_hasFocus
)
1945 win
->m_hasFocus
= false;
1947 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1948 event
.SetEventObject( win
);
1950 (void)win
->GetEventHandler()->ProcessEvent( event
);
1955 // Disable default focus handling for custom windows
1956 // since the default GTK+ handler issues a repaint
1957 if (win
->m_wxwindow
)
1964 //-----------------------------------------------------------------------------
1965 // "enter_notify_event"
1966 //-----------------------------------------------------------------------------
1970 gtk_window_enter_callback( GtkWidget
*widget
,
1971 GdkEventCrossing
*gdk_event
,
1977 wxapp_install_idle_handler();
1979 if (!win
->m_hasVMT
) return FALSE
;
1980 if (g_blockEventsOnDrag
) return FALSE
;
1982 // Event was emitted after a grab
1983 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1985 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1989 GdkModifierType state
= (GdkModifierType
)0;
1991 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1993 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1994 InitMouseEvent(win
, event
, gdk_event
);
1995 wxPoint pt
= win
->GetClientAreaOrigin();
1996 event
.m_x
= x
+ pt
.x
;
1997 event
.m_y
= y
+ pt
.y
;
1999 if (win
->GetEventHandler()->ProcessEvent( event
))
2001 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2009 //-----------------------------------------------------------------------------
2010 // "leave_notify_event"
2011 //-----------------------------------------------------------------------------
2015 gtk_window_leave_callback( GtkWidget
*widget
,
2016 GdkEventCrossing
*gdk_event
,
2022 wxapp_install_idle_handler();
2024 if (!win
->m_hasVMT
) return FALSE
;
2025 if (g_blockEventsOnDrag
) return FALSE
;
2027 // Event was emitted after an ungrab
2028 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2030 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2032 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2033 event
.SetTimestamp( gdk_event
->time
);
2034 event
.SetEventObject( win
);
2038 GdkModifierType state
= (GdkModifierType
)0;
2040 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2042 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2043 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2044 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2045 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2046 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2047 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2048 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2050 wxPoint pt
= win
->GetClientAreaOrigin();
2051 event
.m_x
= x
+ pt
.x
;
2052 event
.m_y
= y
+ pt
.y
;
2054 if (win
->GetEventHandler()->ProcessEvent( event
))
2056 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2064 //-----------------------------------------------------------------------------
2065 // "value_changed" from m_vAdjust
2066 //-----------------------------------------------------------------------------
2069 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2075 wxapp_install_idle_handler();
2077 if (g_blockEventsOnDrag
) return;
2079 if (!win
->m_hasVMT
) return;
2081 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2082 if (fabs(diff
) < 0.2) return;
2084 win
->m_oldVerticalPos
= adjust
->value
;
2086 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2088 int value
= (int)(adjust
->value
+0.5);
2090 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2091 event
.SetEventObject( win
);
2092 win
->GetEventHandler()->ProcessEvent( event
);
2096 //-----------------------------------------------------------------------------
2097 // "value_changed" from m_hAdjust
2098 //-----------------------------------------------------------------------------
2101 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2107 wxapp_install_idle_handler();
2109 if (g_blockEventsOnDrag
) return;
2110 if (!win
->m_hasVMT
) return;
2112 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2113 if (fabs(diff
) < 0.2) return;
2115 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2117 win
->m_oldHorizontalPos
= adjust
->value
;
2119 int value
= (int)(adjust
->value
+0.5);
2121 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2122 event
.SetEventObject( win
);
2123 win
->GetEventHandler()->ProcessEvent( event
);
2127 //-----------------------------------------------------------------------------
2128 // "button_press_event" from scrollbar
2129 //-----------------------------------------------------------------------------
2132 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2133 GdkEventButton
*gdk_event
,
2139 wxapp_install_idle_handler();
2142 g_blockEventsOnScroll
= true;
2144 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2146 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2153 //-----------------------------------------------------------------------------
2154 // "button_release_event" from scrollbar
2155 //-----------------------------------------------------------------------------
2158 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2159 GdkEventButton
*WXUNUSED(gdk_event
),
2164 // don't test here as we can release the mouse while being over
2165 // a different window than the slider
2167 // if (gdk_event->window != widget->slider) return FALSE;
2169 g_blockEventsOnScroll
= false;
2171 if (win
->m_isScrolling
)
2173 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2177 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2178 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2180 value
= (int)(win
->m_hAdjust
->value
+0.5);
2183 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2185 value
= (int)(win
->m_vAdjust
->value
+0.5);
2189 wxScrollWinEvent
event( command
, value
, dir
);
2190 event
.SetEventObject( win
);
2191 win
->GetEventHandler()->ProcessEvent( event
);
2194 win
->m_isScrolling
= false;
2200 // ----------------------------------------------------------------------------
2201 // this wxWindowBase function is implemented here (in platform-specific file)
2202 // because it is static and so couldn't be made virtual
2203 // ----------------------------------------------------------------------------
2205 wxWindow
*wxWindowBase::DoFindFocus()
2207 // the cast is necessary when we compile in wxUniversal mode
2208 return (wxWindow
*)g_focusWindow
;
2211 //-----------------------------------------------------------------------------
2212 // "realize" from m_widget
2213 //-----------------------------------------------------------------------------
2215 /* We cannot set colours and fonts before the widget has
2216 been realized, so we do this directly after realization. */
2220 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2225 wxapp_install_idle_handler();
2229 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2230 gtk_im_context_set_client_window( win
->m_imData
->context
,
2231 pizza
->bin_window
);
2234 wxWindowCreateEvent
event( win
);
2235 event
.SetEventObject( win
);
2236 win
->GetEventHandler()->ProcessEvent( event
);
2242 //-----------------------------------------------------------------------------
2244 //-----------------------------------------------------------------------------
2248 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2249 GtkAllocation
*WXUNUSED(alloc
),
2253 wxapp_install_idle_handler();
2255 if (!win
->m_hasScrolling
) return;
2257 int client_width
= 0;
2258 int client_height
= 0;
2259 win
->GetClientSize( &client_width
, &client_height
);
2260 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2263 win
->m_oldClientWidth
= client_width
;
2264 win
->m_oldClientHeight
= client_height
;
2266 if (!win
->m_nativeSizeEvent
)
2268 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2269 event
.SetEventObject( win
);
2270 win
->GetEventHandler()->ProcessEvent( event
);
2277 #define WXUNUSED_UNLESS_XIM(param) param
2279 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2282 /* Resize XIM window */
2286 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2287 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2288 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2291 wxapp_install_idle_handler();
2297 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2301 gdk_window_get_size (widget
->window
, &width
, &height
);
2302 win
->m_icattr
->preedit_area
.width
= width
;
2303 win
->m_icattr
->preedit_area
.height
= height
;
2304 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2310 //-----------------------------------------------------------------------------
2311 // "realize" from m_wxwindow
2312 //-----------------------------------------------------------------------------
2314 /* Initialize XIM support */
2318 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2319 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2322 wxapp_install_idle_handler();
2325 if (win
->m_ic
) return FALSE
;
2326 if (!widget
) return FALSE
;
2327 if (!gdk_im_ready()) return FALSE
;
2329 win
->m_icattr
= gdk_ic_attr_new();
2330 if (!win
->m_icattr
) return FALSE
;
2334 GdkColormap
*colormap
;
2335 GdkICAttr
*attr
= win
->m_icattr
;
2336 unsigned attrmask
= GDK_IC_ALL_REQ
;
2338 GdkIMStyle supported_style
= (GdkIMStyle
)
2339 (GDK_IM_PREEDIT_NONE
|
2340 GDK_IM_PREEDIT_NOTHING
|
2341 GDK_IM_PREEDIT_POSITION
|
2342 GDK_IM_STATUS_NONE
|
2343 GDK_IM_STATUS_NOTHING
);
2345 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2346 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2348 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2349 attr
->client_window
= widget
->window
;
2351 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2352 gtk_widget_get_default_colormap ())
2354 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2355 attr
->preedit_colormap
= colormap
;
2358 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2359 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2360 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2361 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2363 switch (style
& GDK_IM_PREEDIT_MASK
)
2365 case GDK_IM_PREEDIT_POSITION
:
2366 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2368 g_warning ("over-the-spot style requires fontset");
2372 gdk_window_get_size (widget
->window
, &width
, &height
);
2374 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2375 attr
->spot_location
.x
= 0;
2376 attr
->spot_location
.y
= height
;
2377 attr
->preedit_area
.x
= 0;
2378 attr
->preedit_area
.y
= 0;
2379 attr
->preedit_area
.width
= width
;
2380 attr
->preedit_area
.height
= height
;
2381 attr
->preedit_fontset
= widget
->style
->font
;
2386 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2388 if (win
->m_ic
== NULL
)
2389 g_warning ("Can't create input context.");
2392 mask
= gdk_window_get_events (widget
->window
);
2393 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2394 gdk_window_set_events (widget
->window
, mask
);
2396 if (GTK_WIDGET_HAS_FOCUS(widget
))
2397 gdk_im_begin (win
->m_ic
, widget
->window
);
2405 //-----------------------------------------------------------------------------
2406 // InsertChild for wxWindowGTK.
2407 //-----------------------------------------------------------------------------
2409 /* Callback for wxWindowGTK. This very strange beast has to be used because
2410 * C++ has no virtual methods in a constructor. We have to emulate a
2411 * virtual function here as wxNotebook requires a different way to insert
2412 * a child in it. I had opted for creating a wxNotebookPage window class
2413 * which would have made this superfluous (such in the MDI window system),
2414 * but no-one was listening to me... */
2416 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2418 /* the window might have been scrolled already, do we
2419 have to adapt the position */
2420 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2421 child
->m_x
+= pizza
->xoffset
;
2422 child
->m_y
+= pizza
->yoffset
;
2424 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2425 GTK_WIDGET(child
->m_widget
),
2432 //-----------------------------------------------------------------------------
2434 //-----------------------------------------------------------------------------
2436 wxWindow
*wxGetActiveWindow()
2438 return wxWindow::FindFocus();
2442 wxMouseState
wxGetMouseState()
2448 GdkModifierType mask
;
2450 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2454 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2455 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2456 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2458 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2459 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2460 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2461 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2466 //-----------------------------------------------------------------------------
2468 //-----------------------------------------------------------------------------
2470 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2472 #ifdef __WXUNIVERSAL__
2473 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2475 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2476 #endif // __WXUNIVERSAL__/__WXGTK__
2478 void wxWindowGTK::Init()
2481 m_widget
= (GtkWidget
*) NULL
;
2482 m_wxwindow
= (GtkWidget
*) NULL
;
2483 m_focusWidget
= (GtkWidget
*) NULL
;
2493 m_needParent
= true;
2494 m_isBeingDeleted
= false;
2497 m_nativeSizeEvent
= false;
2499 m_hasScrolling
= false;
2500 m_isScrolling
= false;
2502 m_hAdjust
= (GtkAdjustment
*) NULL
;
2503 m_vAdjust
= (GtkAdjustment
*) NULL
;
2504 m_oldHorizontalPos
=
2505 m_oldVerticalPos
= 0.0;
2507 m_oldClientHeight
= 0;
2511 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2513 m_acceptsFocus
= false;
2516 m_clipPaintRegion
= false;
2518 m_needsStyleChange
= false;
2520 m_cursor
= *wxSTANDARD_CURSOR
;
2523 m_dirtyTabOrder
= false;
2526 wxWindowGTK::wxWindowGTK()
2531 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2536 const wxString
&name
)
2540 Create( parent
, id
, pos
, size
, style
, name
);
2543 bool wxWindowGTK::Create( wxWindow
*parent
,
2548 const wxString
&name
)
2550 if (!PreCreation( parent
, pos
, size
) ||
2551 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2553 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2557 m_insertCallback
= wxInsertChildInWindow
;
2559 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2560 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2562 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2564 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2565 scroll_class
->scrollbar_spacing
= 0;
2567 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2569 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2570 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2572 m_wxwindow
= gtk_pizza_new();
2574 #ifndef __WXUNIVERSAL__
2575 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2577 if (HasFlag(wxRAISED_BORDER
))
2579 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2581 else if (HasFlag(wxSUNKEN_BORDER
))
2583 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2585 else if (HasFlag(wxSIMPLE_BORDER
))
2587 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2591 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2593 #endif // __WXUNIVERSAL__
2595 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2597 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2598 m_acceptsFocus
= true;
2600 // I _really_ don't want scrollbars in the beginning
2601 m_vAdjust
->lower
= 0.0;
2602 m_vAdjust
->upper
= 1.0;
2603 m_vAdjust
->value
= 0.0;
2604 m_vAdjust
->step_increment
= 1.0;
2605 m_vAdjust
->page_increment
= 1.0;
2606 m_vAdjust
->page_size
= 5.0;
2607 g_signal_emit_by_name (m_vAdjust
, "changed");
2608 m_hAdjust
->lower
= 0.0;
2609 m_hAdjust
->upper
= 1.0;
2610 m_hAdjust
->value
= 0.0;
2611 m_hAdjust
->step_increment
= 1.0;
2612 m_hAdjust
->page_increment
= 1.0;
2613 m_hAdjust
->page_size
= 5.0;
2614 g_signal_emit_by_name (m_hAdjust
, "changed");
2616 // these handlers block mouse events to any window during scrolling such as
2617 // motion events and prevent GTK and wxWidgets from fighting over where the
2619 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2620 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2621 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2622 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2623 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2624 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2625 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2626 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2628 // these handlers get notified when screen updates are required either when
2629 // scrolling or when the window size (and therefore scrollbar configuration)
2632 g_signal_connect (m_hAdjust
, "value_changed",
2633 G_CALLBACK (gtk_window_hscroll_callback
), this);
2634 g_signal_connect (m_vAdjust
, "value_changed",
2635 G_CALLBACK (gtk_window_vscroll_callback
), this);
2637 gtk_widget_show( m_wxwindow
);
2640 m_parent
->DoAddChild( this );
2642 m_focusWidget
= m_wxwindow
;
2649 wxWindowGTK::~wxWindowGTK()
2653 if (g_focusWindow
== this)
2654 g_focusWindow
= NULL
;
2656 if ( g_delayedFocus
== this )
2657 g_delayedFocus
= NULL
;
2659 m_isBeingDeleted
= true;
2662 // destroy children before destroying this window itself
2665 // unhook focus handlers to prevent stray events being
2666 // propagated to this (soon to be) dead object
2667 if (m_focusWidget
!= NULL
)
2669 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2670 (gpointer
) gtk_window_focus_in_callback
,
2672 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2673 (gpointer
) gtk_window_focus_out_callback
,
2682 gdk_ic_destroy (m_ic
);
2684 gdk_ic_attr_destroy (m_icattr
);
2687 // delete before the widgets to avoid a crash on solaris
2692 gtk_widget_destroy( m_wxwindow
);
2693 m_wxwindow
= (GtkWidget
*) NULL
;
2698 gtk_widget_destroy( m_widget
);
2699 m_widget
= (GtkWidget
*) NULL
;
2703 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2705 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2707 // Use either the given size, or the default if -1 is given.
2708 // See wxWindowBase for these functions.
2709 m_width
= WidthDefault(size
.x
) ;
2710 m_height
= HeightDefault(size
.y
);
2718 void wxWindowGTK::PostCreation()
2720 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2726 // these get reported to wxWidgets -> wxPaintEvent
2728 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2730 g_signal_connect (m_wxwindow
, "expose_event",
2731 G_CALLBACK (gtk_window_expose_callback
), this);
2733 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2736 // Create input method handler
2737 m_imData
= new wxGtkIMData
;
2739 // Cannot handle drawing preedited text yet
2740 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2742 g_signal_connect (m_imData
->context
, "commit",
2743 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2745 // these are called when the "sunken" or "raised" borders are drawn
2746 g_signal_connect (m_widget
, "expose_event",
2747 G_CALLBACK (gtk_window_own_expose_callback
), this);
2752 if (!GTK_IS_WINDOW(m_widget
))
2754 if (m_focusWidget
== NULL
)
2755 m_focusWidget
= m_widget
;
2759 g_signal_connect (m_focusWidget
, "focus_in_event",
2760 G_CALLBACK (gtk_window_focus_in_callback
), this);
2761 g_signal_connect (m_focusWidget
, "focus_out_event",
2762 G_CALLBACK (gtk_window_focus_out_callback
), this);
2766 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2767 G_CALLBACK (gtk_window_focus_in_callback
), this);
2768 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2769 G_CALLBACK (gtk_window_focus_out_callback
), this);
2773 // connect to the various key and mouse handlers
2775 GtkWidget
*connect_widget
= GetConnectWidget();
2777 ConnectWidget( connect_widget
);
2779 /* We cannot set colours, fonts and cursors before the widget has
2780 been realized, so we do this directly after realization */
2781 g_signal_connect (connect_widget
, "realize",
2782 G_CALLBACK (gtk_window_realized_callback
), this);
2786 // Catch native resize events
2787 g_signal_connect (m_wxwindow
, "size_allocate",
2788 G_CALLBACK (gtk_window_size_callback
), this);
2790 // Initialize XIM support
2791 g_signal_connect (m_wxwindow
, "realize",
2792 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2794 // And resize XIM window
2795 g_signal_connect (m_wxwindow
, "size_allocate",
2796 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2799 if (GTK_IS_COMBO(m_widget
))
2801 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2803 g_signal_connect (gcombo
->entry
, "size_request",
2804 G_CALLBACK (wxgtk_combo_size_request_callback
),
2809 // This is needed if we want to add our windows into native
2810 // GTK controls, such as the toolbar. With this callback, the
2811 // toolbar gets to know the correct size (the one set by the
2812 // programmer). Sadly, it misbehaves for wxComboBox.
2813 g_signal_connect (m_widget
, "size_request",
2814 G_CALLBACK (wxgtk_window_size_request_callback
),
2818 InheritAttributes();
2822 // unless the window was created initially hidden (i.e. Hide() had been
2823 // called before Create()), we should show it at GTK+ level as well
2825 gtk_widget_show( m_widget
);
2828 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2830 g_signal_connect (widget
, "key_press_event",
2831 G_CALLBACK (gtk_window_key_press_callback
), this);
2832 g_signal_connect (widget
, "key_release_event",
2833 G_CALLBACK (gtk_window_key_release_callback
), this);
2834 g_signal_connect (widget
, "button_press_event",
2835 G_CALLBACK (gtk_window_button_press_callback
), this);
2836 g_signal_connect (widget
, "button_release_event",
2837 G_CALLBACK (gtk_window_button_release_callback
), this);
2838 g_signal_connect (widget
, "motion_notify_event",
2839 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2840 g_signal_connect (widget
, "scroll_event",
2841 G_CALLBACK (gtk_window_wheel_callback
), this);
2842 g_signal_connect (widget
, "popup_menu",
2843 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2844 g_signal_connect (widget
, "enter_notify_event",
2845 G_CALLBACK (gtk_window_enter_callback
), this);
2846 g_signal_connect (widget
, "leave_notify_event",
2847 G_CALLBACK (gtk_window_leave_callback
), this);
2850 bool wxWindowGTK::Destroy()
2852 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2856 return wxWindowBase::Destroy();
2859 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2861 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2864 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2866 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2867 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2870 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2873 if (m_resizing
) return; /* I don't like recursions */
2876 int currentX
, currentY
;
2877 GetPosition(¤tX
, ¤tY
);
2878 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2880 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2882 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2884 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2886 /* don't set the size for children of wxNotebook, just take the values. */
2894 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2895 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2897 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2898 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2902 m_x
= x
+ pizza
->xoffset
;
2903 m_y
= y
+ pizza
->yoffset
;
2906 // calculate the best size if we should auto size the window
2907 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2908 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2910 const wxSize sizeBest
= GetBestSize();
2911 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2913 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2914 height
= sizeBest
.y
;
2922 int minWidth
= GetMinWidth(),
2923 minHeight
= GetMinHeight(),
2924 maxWidth
= GetMaxWidth(),
2925 maxHeight
= GetMaxHeight();
2927 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2928 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2929 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2930 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2932 int left_border
= 0;
2933 int right_border
= 0;
2935 int bottom_border
= 0;
2937 /* the default button has a border around it */
2938 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2940 GtkBorder
*default_border
= NULL
;
2941 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2944 left_border
+= default_border
->left
;
2945 right_border
+= default_border
->right
;
2946 top_border
+= default_border
->top
;
2947 bottom_border
+= default_border
->bottom
;
2948 g_free( default_border
);
2952 DoMoveWindow( m_x
-top_border
,
2954 m_width
+left_border
+right_border
,
2955 m_height
+top_border
+bottom_border
);
2960 /* Sometimes the client area changes size without the
2961 whole windows's size changing, but if the whole
2962 windows's size doesn't change, no wxSizeEvent will
2963 normally be sent. Here we add an extra test if
2964 the client test has been changed and this will
2966 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2970 wxPrintf( "OnSize sent from " );
2971 if (GetClassInfo() && GetClassInfo()->GetClassName())
2972 wxPrintf( GetClassInfo()->GetClassName() );
2973 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2976 if (!m_nativeSizeEvent
)
2978 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2979 event
.SetEventObject( this );
2980 GetEventHandler()->ProcessEvent( event
);
2986 void wxWindowGTK::OnInternalIdle()
2988 if ( m_dirtyTabOrder
)
2990 m_dirtyTabOrder
= false;
2994 // Update style if the window was not yet realized
2995 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2996 if (m_needsStyleChange
)
2998 SetBackgroundStyle(GetBackgroundStyle());
2999 m_needsStyleChange
= false;
3002 // Update invalidated regions.
3005 wxCursor cursor
= m_cursor
;
3006 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3010 /* I now set the cursor anew in every OnInternalIdle call
3011 as setting the cursor in a parent window also effects the
3012 windows above so that checking for the current cursor is
3017 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3019 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3021 if (!g_globalCursor
.Ok())
3022 cursor
= *wxSTANDARD_CURSOR
;
3024 window
= m_widget
->window
;
3025 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3026 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3032 GdkWindow
*window
= m_widget
->window
;
3033 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3034 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3039 if (wxUpdateUIEvent::CanUpdate(this))
3040 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3043 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3045 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3047 if (width
) (*width
) = m_width
;
3048 if (height
) (*height
) = m_height
;
3051 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3053 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3057 SetSize( width
, height
);
3064 #ifndef __WXUNIVERSAL__
3065 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3067 /* when using GTK 1.2 we set the shadow border size to 2 */
3071 if (HasFlag(wxSIMPLE_BORDER
))
3073 /* when using GTK 1.2 we set the simple border size to 1 */
3077 #endif // __WXUNIVERSAL__
3081 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3083 GtkRequisition vscroll_req
;
3084 vscroll_req
.width
= 2;
3085 vscroll_req
.height
= 2;
3086 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3087 (scroll_window
->vscrollbar
, &vscroll_req
);
3089 GtkRequisition hscroll_req
;
3090 hscroll_req
.width
= 2;
3091 hscroll_req
.height
= 2;
3092 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3093 (scroll_window
->hscrollbar
, &hscroll_req
);
3095 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3097 if (scroll_window
->vscrollbar_visible
)
3099 dw
+= vscroll_req
.width
;
3100 dw
+= scroll_class
->scrollbar_spacing
;
3103 if (scroll_window
->hscrollbar_visible
)
3105 dh
+= hscroll_req
.height
;
3106 dh
+= scroll_class
->scrollbar_spacing
;
3110 SetSize( width
+dw
, height
+dh
);
3114 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3116 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3120 if (width
) (*width
) = m_width
;
3121 if (height
) (*height
) = m_height
;
3128 #ifndef __WXUNIVERSAL__
3129 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3131 /* when using GTK 1.2 we set the shadow border size to 2 */
3135 if (HasFlag(wxSIMPLE_BORDER
))
3137 /* when using GTK 1.2 we set the simple border size to 1 */
3141 #endif // __WXUNIVERSAL__
3145 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3147 GtkRequisition vscroll_req
;
3148 vscroll_req
.width
= 2;
3149 vscroll_req
.height
= 2;
3150 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3151 (scroll_window
->vscrollbar
, &vscroll_req
);
3153 GtkRequisition hscroll_req
;
3154 hscroll_req
.width
= 2;
3155 hscroll_req
.height
= 2;
3156 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3157 (scroll_window
->hscrollbar
, &hscroll_req
);
3159 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3161 if (scroll_window
->vscrollbar_visible
)
3163 dw
+= vscroll_req
.width
;
3164 dw
+= scroll_class
->scrollbar_spacing
;
3167 if (scroll_window
->hscrollbar_visible
)
3169 dh
+= hscroll_req
.height
;
3170 dh
+= scroll_class
->scrollbar_spacing
;
3174 if (width
) (*width
) = m_width
- dw
;
3175 if (height
) (*height
) = m_height
- dh
;
3179 printf( "GetClientSize, name %s ", GetName().c_str() );
3180 if (width) printf( " width = %d", (*width) );
3181 if (height) printf( " height = %d", (*height) );
3186 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3188 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3192 if (m_parent
&& m_parent
->m_wxwindow
)
3194 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3195 dx
= pizza
->xoffset
;
3196 dy
= pizza
->yoffset
;
3199 if (x
) (*x
) = m_x
- dx
;
3200 if (y
) (*y
) = m_y
- dy
;
3203 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3205 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3207 if (!m_widget
->window
) return;
3209 GdkWindow
*source
= (GdkWindow
*) NULL
;
3211 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3213 source
= m_widget
->window
;
3217 gdk_window_get_origin( source
, &org_x
, &org_y
);
3221 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3223 org_x
+= m_widget
->allocation
.x
;
3224 org_y
+= m_widget
->allocation
.y
;
3232 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3234 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3236 if (!m_widget
->window
) return;
3238 GdkWindow
*source
= (GdkWindow
*) NULL
;
3240 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3242 source
= m_widget
->window
;
3246 gdk_window_get_origin( source
, &org_x
, &org_y
);
3250 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3252 org_x
+= m_widget
->allocation
.x
;
3253 org_y
+= m_widget
->allocation
.y
;
3261 bool wxWindowGTK::Show( bool show
)
3263 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3265 if (!wxWindowBase::Show(show
))
3272 gtk_widget_show( m_widget
);
3274 gtk_widget_hide( m_widget
);
3276 wxShowEvent
eventShow(GetId(), show
);
3277 eventShow
.SetEventObject(this);
3279 GetEventHandler()->ProcessEvent(eventShow
);
3284 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3286 win
->OnParentEnable(enable
);
3288 // Recurse, so that children have the opportunity to Do The Right Thing
3289 // and reset colours that have been messed up by a parent's (really ancestor's)
3291 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3293 node
= node
->GetNext() )
3295 wxWindow
*child
= node
->GetData();
3296 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3297 wxWindowNotifyEnable(child
, enable
);
3301 bool wxWindowGTK::Enable( bool enable
)
3303 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3305 if (!wxWindowBase::Enable(enable
))
3311 gtk_widget_set_sensitive( m_widget
, enable
);
3313 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3315 wxWindowNotifyEnable(this, enable
);
3320 int wxWindowGTK::GetCharHeight() const
3322 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3324 wxFont font
= GetFont();
3325 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3327 PangoContext
*context
= NULL
;
3329 context
= gtk_widget_get_pango_context( m_widget
);
3334 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3335 PangoLayout
*layout
= pango_layout_new(context
);
3336 pango_layout_set_font_description(layout
, desc
);
3337 pango_layout_set_text(layout
, "H", 1);
3338 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3340 PangoRectangle rect
;
3341 pango_layout_line_get_extents(line
, NULL
, &rect
);
3343 g_object_unref( G_OBJECT( layout
) );
3345 return (int) PANGO_PIXELS(rect
.height
);
3348 int wxWindowGTK::GetCharWidth() const
3350 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3352 wxFont font
= GetFont();
3353 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3355 PangoContext
*context
= NULL
;
3357 context
= gtk_widget_get_pango_context( m_widget
);
3362 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3363 PangoLayout
*layout
= pango_layout_new(context
);
3364 pango_layout_set_font_description(layout
, desc
);
3365 pango_layout_set_text(layout
, "g", 1);
3366 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3368 PangoRectangle rect
;
3369 pango_layout_line_get_extents(line
, NULL
, &rect
);
3371 g_object_unref( G_OBJECT( layout
) );
3373 return (int) PANGO_PIXELS(rect
.width
);
3376 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3380 int *externalLeading
,
3381 const wxFont
*theFont
) const
3383 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3385 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3394 PangoContext
*context
= NULL
;
3396 context
= gtk_widget_get_pango_context( m_widget
);
3405 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3406 PangoLayout
*layout
= pango_layout_new(context
);
3407 pango_layout_set_font_description(layout
, desc
);
3410 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3411 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3413 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3414 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3415 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3419 PangoRectangle rect
;
3420 pango_layout_get_extents(layout
, NULL
, &rect
);
3422 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3423 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3426 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3427 int baseline
= pango_layout_iter_get_baseline(iter
);
3428 pango_layout_iter_free(iter
);
3429 *descent
= *y
- PANGO_PIXELS(baseline
);
3431 if (externalLeading
) (*externalLeading
) = 0; // ??
3433 g_object_unref( G_OBJECT( layout
) );
3436 void wxWindowGTK::SetFocus()
3438 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3441 // don't do anything if we already have focus
3447 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3449 gtk_widget_grab_focus (m_wxwindow
);
3454 if (GTK_IS_CONTAINER(m_widget
))
3456 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3459 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3462 if (!GTK_WIDGET_REALIZED(m_widget
))
3464 // we can't set the focus to the widget now so we remember that
3465 // it should be focused and will do it later, during the idle
3466 // time, as soon as we can
3467 wxLogTrace(TRACE_FOCUS
,
3468 _T("Delaying setting focus to %s(%s)"),
3469 GetClassInfo()->GetClassName(), GetLabel().c_str());
3471 g_delayedFocus
= this;
3475 wxLogTrace(TRACE_FOCUS
,
3476 _T("Setting focus to %s(%s)"),
3477 GetClassInfo()->GetClassName(), GetLabel().c_str());
3479 gtk_widget_grab_focus (m_widget
);
3484 wxLogTrace(TRACE_FOCUS
,
3485 _T("Can't set focus to %s(%s)"),
3486 GetClassInfo()->GetClassName(), GetLabel().c_str());
3491 bool wxWindowGTK::AcceptsFocus() const
3493 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3496 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3498 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3500 wxWindowGTK
*oldParent
= m_parent
,
3501 *newParent
= (wxWindowGTK
*)newParentBase
;
3503 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3505 if ( !wxWindowBase::Reparent(newParent
) )
3508 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3510 /* prevent GTK from deleting the widget arbitrarily */
3511 gtk_widget_ref( m_widget
);
3515 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3518 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3522 /* insert GTK representation */
3523 (*(newParent
->m_insertCallback
))(newParent
, this);
3526 /* reverse: prevent GTK from deleting the widget arbitrarily */
3527 gtk_widget_unref( m_widget
);
3532 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3534 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3536 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3538 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3543 /* insert GTK representation */
3544 (*m_insertCallback
)(this, child
);
3547 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3549 wxWindowBase::AddChild(child
);
3550 m_dirtyTabOrder
= true;
3552 wxapp_install_idle_handler();
3555 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3557 wxWindowBase::RemoveChild(child
);
3558 m_dirtyTabOrder
= true;
3560 wxapp_install_idle_handler();
3563 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3565 wxWindowBase::DoMoveInTabOrder(win
, move
);
3566 m_dirtyTabOrder
= true;
3568 wxapp_install_idle_handler();
3571 void wxWindowGTK::RealizeTabOrder()
3575 if ( !m_children
.empty() )
3578 // we don't only construct the correct focus chain but also use
3579 // this opportunity to update the mnemonic widgets for all labels
3581 // it would be nice to extract this code from here and put it in
3582 // stattext.cpp to reduce dependencies but there is no really easy
3583 // way to do it unfortunately
3584 wxStaticText
*lastLabel
= NULL
;
3585 #endif // wxUSE_STATTEXT
3587 GList
*chain
= NULL
;
3589 for ( wxWindowList::const_iterator i
= m_children
.begin();
3590 i
!= m_children
.end();
3593 wxWindowGTK
*win
= *i
;
3597 if ( win
->AcceptsFocusFromKeyboard() )
3599 GtkLabel
*l
= GTK_LABEL(lastLabel
->m_widget
);
3600 gtk_label_set_mnemonic_widget(l
, win
->m_widget
);
3604 else // check if this one is a label
3606 lastLabel
= wxDynamicCast(win
, wxStaticText
);
3608 #endif // wxUSE_STATTEXT
3610 chain
= g_list_prepend(chain
, win
->m_widget
);
3613 chain
= g_list_reverse(chain
);
3615 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3620 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3625 void wxWindowGTK::Raise()
3627 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3629 if (m_wxwindow
&& m_wxwindow
->window
)
3631 gdk_window_raise( m_wxwindow
->window
);
3633 else if (m_widget
->window
)
3635 gdk_window_raise( m_widget
->window
);
3639 void wxWindowGTK::Lower()
3641 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3643 if (m_wxwindow
&& m_wxwindow
->window
)
3645 gdk_window_lower( m_wxwindow
->window
);
3647 else if (m_widget
->window
)
3649 gdk_window_lower( m_widget
->window
);
3653 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3655 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3657 if (cursor
== m_cursor
)
3661 wxapp_install_idle_handler();
3663 if (cursor
== wxNullCursor
)
3664 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3666 return wxWindowBase::SetCursor( cursor
);
3669 void wxWindowGTK::WarpPointer( int x
, int y
)
3671 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3673 // We provide this function ourselves as it is
3674 // missing in GDK (top of this file).
3676 GdkWindow
*window
= (GdkWindow
*) NULL
;
3678 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3680 window
= GetConnectWidget()->window
;
3683 gdk_window_warp_pointer( window
, x
, y
);
3686 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3688 double value_start
= adj
->value
;
3689 double value
= value_start
+ change
;
3690 double upper
= adj
->upper
- adj
->page_size
;
3695 // Lower bound will be checked by gtk_adjustment_set_value
3696 gtk_adjustment_set_value(adj
, value
);
3697 return adj
->value
!= value_start
;
3700 bool wxWindowGTK::ScrollLines(int lines
)
3703 m_vAdjust
!= NULL
&&
3704 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3707 bool wxWindowGTK::ScrollPages(int pages
)
3710 m_vAdjust
!= NULL
&&
3711 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3714 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3716 wxASSERT(m_vAdjust
== NULL
);
3720 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3724 if (!m_widget
->window
)
3729 GdkRectangle gdk_rect
,
3733 gdk_rect
.x
= rect
->x
;
3734 gdk_rect
.y
= rect
->y
;
3735 gdk_rect
.width
= rect
->width
;
3736 gdk_rect
.height
= rect
->height
;
3739 else // invalidate everything
3744 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3748 void wxWindowGTK::Update()
3752 // when we call Update() we really want to update the window immediately on
3753 // screen, even if it means flushing the entire queue and hence slowing down
3754 // everything -- but it should still be done, it's just that Update() should
3755 // be called very rarely
3759 void wxWindowGTK::GtkUpdate()
3761 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3762 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3764 // for consistency with other platforms (and also because it's convenient
3765 // to be able to update an entire TLW by calling Update() only once), we
3766 // should also update all our children here
3767 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3769 node
= node
->GetNext() )
3771 node
->GetData()->GtkUpdate();
3775 void wxWindowGTK::GtkSendPaintEvents()
3779 m_updateRegion
.Clear();
3783 // Clip to paint region in wxClientDC
3784 m_clipPaintRegion
= true;
3786 // widget to draw on
3787 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3789 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3791 // find ancestor from which to steal background
3792 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3794 parent
= (wxWindow
*)this;
3796 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3798 wxRegionIterator
upd( m_updateRegion
);
3802 rect
.x
= upd
.GetX();
3803 rect
.y
= upd
.GetY();
3804 rect
.width
= upd
.GetWidth();
3805 rect
.height
= upd
.GetHeight();
3807 gtk_paint_flat_box( parent
->m_widget
->style
,
3809 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3823 wxWindowDC
dc( (wxWindow
*)this );
3824 dc
.SetClippingRegion( m_updateRegion
);
3826 wxEraseEvent
erase_event( GetId(), &dc
);
3827 erase_event
.SetEventObject( this );
3829 GetEventHandler()->ProcessEvent(erase_event
);
3832 wxNcPaintEvent
nc_paint_event( GetId() );
3833 nc_paint_event
.SetEventObject( this );
3834 GetEventHandler()->ProcessEvent( nc_paint_event
);
3836 wxPaintEvent
paint_event( GetId() );
3837 paint_event
.SetEventObject( this );
3838 GetEventHandler()->ProcessEvent( paint_event
);
3840 m_clipPaintRegion
= false;
3842 m_updateRegion
.Clear();
3845 void wxWindowGTK::ClearBackground()
3847 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3851 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3853 wxWindowBase::DoSetToolTip(tip
);
3856 m_tooltip
->Apply( (wxWindow
*)this );
3859 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3861 wxString
tmp( tip
);
3862 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3864 #endif // wxUSE_TOOLTIPS
3866 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3868 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3870 if (!wxWindowBase::SetBackgroundColour(colour
))
3875 // We need the pixel value e.g. for background clearing.
3876 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3879 // apply style change (forceStyle=true so that new style is applied
3880 // even if the bg colour changed from valid to wxNullColour)
3881 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3882 ApplyWidgetStyle(true);
3887 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3889 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3891 if (!wxWindowBase::SetForegroundColour(colour
))
3898 // We need the pixel value e.g. for background clearing.
3899 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3902 // apply style change (forceStyle=true so that new style is applied
3903 // even if the bg colour changed from valid to wxNullColour):
3904 ApplyWidgetStyle(true);
3909 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3911 return gtk_widget_get_pango_context( m_widget
);
3914 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3916 // do we need to apply any changes at all?
3919 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3924 GtkRcStyle
*style
= gtk_rc_style_new();
3929 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3932 if ( m_foregroundColour
.Ok() )
3934 GdkColor
*fg
= m_foregroundColour
.GetColor();
3936 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3937 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3939 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3940 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3942 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3943 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3946 if ( m_backgroundColour
.Ok() )
3948 GdkColor
*bg
= m_backgroundColour
.GetColor();
3950 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3951 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3952 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3953 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3955 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3956 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3957 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3958 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3960 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3961 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3962 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3963 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3965 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3966 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3967 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3968 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3974 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3976 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3979 DoApplyWidgetStyle(style
);
3980 gtk_rc_style_unref(style
);
3983 // Style change may affect GTK+'s size calculation:
3984 InvalidateBestSize();
3987 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3990 gtk_widget_modify_style(m_wxwindow
, style
);
3992 gtk_widget_modify_style(m_widget
, style
);
3995 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3997 wxWindowBase::SetBackgroundStyle(style
);
3999 if (style
== wxBG_STYLE_CUSTOM
)
4001 GdkWindow
*window
= (GdkWindow
*) NULL
;
4003 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4005 window
= GetConnectWidget()->window
;
4009 // Make sure GDK/X11 doesn't refresh the window
4011 gdk_window_set_back_pixmap( window
, None
, False
);
4013 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4016 m_needsStyleChange
= false;
4019 // Do in OnIdle, because the window is not yet available
4020 m_needsStyleChange
= true;
4022 // Don't apply widget style, or we get a grey background
4026 // apply style change (forceStyle=true so that new style is applied
4027 // even if the bg colour changed from valid to wxNullColour):
4028 ApplyWidgetStyle(true);
4033 #if wxUSE_DRAG_AND_DROP
4035 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4037 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4039 GtkWidget
*dnd_widget
= GetConnectWidget();
4041 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4043 if (m_dropTarget
) delete m_dropTarget
;
4044 m_dropTarget
= dropTarget
;
4046 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4049 #endif // wxUSE_DRAG_AND_DROP
4051 GtkWidget
* wxWindowGTK::GetConnectWidget()
4053 GtkWidget
*connect_widget
= m_widget
;
4054 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4056 return connect_widget
;
4059 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4062 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4064 return (window
== m_widget
->window
);
4067 bool wxWindowGTK::SetFont( const wxFont
&font
)
4069 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4071 if (!wxWindowBase::SetFont(font
))
4074 // apply style change (forceStyle=true so that new style is applied
4075 // even if the font changed from valid to wxNullFont):
4076 ApplyWidgetStyle(true);
4081 void wxWindowGTK::DoCaptureMouse()
4083 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4085 GdkWindow
*window
= (GdkWindow
*) NULL
;
4087 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4089 window
= GetConnectWidget()->window
;
4091 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4093 wxCursor
* cursor
= & m_cursor
;
4095 cursor
= wxSTANDARD_CURSOR
;
4097 gdk_pointer_grab( window
, FALSE
,
4099 (GDK_BUTTON_PRESS_MASK
|
4100 GDK_BUTTON_RELEASE_MASK
|
4101 GDK_POINTER_MOTION_HINT_MASK
|
4102 GDK_POINTER_MOTION_MASK
),
4104 cursor
->GetCursor(),
4105 (guint32
)GDK_CURRENT_TIME
);
4106 g_captureWindow
= this;
4107 g_captureWindowHasMouse
= true;
4110 void wxWindowGTK::DoReleaseMouse()
4112 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4114 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4116 g_captureWindow
= (wxWindowGTK
*) NULL
;
4118 GdkWindow
*window
= (GdkWindow
*) NULL
;
4120 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4122 window
= GetConnectWidget()->window
;
4127 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4131 wxWindow
*wxWindowBase::GetCapture()
4133 return (wxWindow
*)g_captureWindow
;
4136 bool wxWindowGTK::IsRetained() const
4141 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4142 int range
, bool refresh
)
4144 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4146 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4148 m_hasScrolling
= true;
4150 if (orient
== wxHORIZONTAL
)
4152 float fpos
= (float)pos
;
4153 float frange
= (float)range
;
4154 float fthumb
= (float)thumbVisible
;
4155 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4156 if (fpos
< 0.0) fpos
= 0.0;
4158 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4159 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4161 SetScrollPos( orient
, pos
, refresh
);
4165 m_oldHorizontalPos
= fpos
;
4167 m_hAdjust
->lower
= 0.0;
4168 m_hAdjust
->upper
= frange
;
4169 m_hAdjust
->value
= fpos
;
4170 m_hAdjust
->step_increment
= 1.0;
4171 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4172 m_hAdjust
->page_size
= fthumb
;
4176 float fpos
= (float)pos
;
4177 float frange
= (float)range
;
4178 float fthumb
= (float)thumbVisible
;
4179 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4180 if (fpos
< 0.0) fpos
= 0.0;
4182 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4183 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4185 SetScrollPos( orient
, pos
, refresh
);
4189 m_oldVerticalPos
= fpos
;
4191 m_vAdjust
->lower
= 0.0;
4192 m_vAdjust
->upper
= frange
;
4193 m_vAdjust
->value
= fpos
;
4194 m_vAdjust
->step_increment
= 1.0;
4195 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4196 m_vAdjust
->page_size
= fthumb
;
4199 if (orient
== wxHORIZONTAL
)
4200 g_signal_emit_by_name (m_hAdjust
, "changed");
4202 g_signal_emit_by_name (m_vAdjust
, "changed");
4205 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4207 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4208 gpointer fn
= orient
== wxHORIZONTAL
4209 ? (gpointer
) gtk_window_hscroll_callback
4210 : (gpointer
) gtk_window_vscroll_callback
;
4212 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4213 g_signal_emit_by_name (adj
, "value_changed");
4214 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4217 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4219 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4220 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4222 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4224 float fpos
= (float)pos
;
4225 if (fpos
> adj
->upper
- adj
->page_size
)
4226 fpos
= adj
->upper
- adj
->page_size
;
4229 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4231 if (fabs(fpos
-adj
->value
) < 0.2)
4235 if ( m_wxwindow
->window
)
4240 int wxWindowGTK::GetScrollThumb( int orient
) const
4242 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4244 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4246 if (orient
== wxHORIZONTAL
)
4247 return (int)(m_hAdjust
->page_size
+0.5);
4249 return (int)(m_vAdjust
->page_size
+0.5);
4252 int wxWindowGTK::GetScrollPos( int orient
) const
4254 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4256 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4258 if (orient
== wxHORIZONTAL
)
4259 return (int)(m_hAdjust
->value
+0.5);
4261 return (int)(m_vAdjust
->value
+0.5);
4264 int wxWindowGTK::GetScrollRange( int orient
) const
4266 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4268 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4270 if (orient
== wxHORIZONTAL
)
4271 return (int)(m_hAdjust
->upper
+0.5);
4273 return (int)(m_vAdjust
->upper
+0.5);
4276 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4278 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4280 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4282 // No scrolling requested.
4283 if ((dx
== 0) && (dy
== 0)) return;
4285 m_clipPaintRegion
= true;
4287 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4289 m_clipPaintRegion
= false;
4292 void wxWindowGTK::SetWindowStyleFlag( long style
)
4294 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4295 wxWindowBase::SetWindowStyleFlag(style
);
4298 // Find the wxWindow at the current mouse position, also returning the mouse
4300 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4302 pt
= wxGetMousePosition();
4303 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4307 // Get the current mouse position.
4308 wxPoint
wxGetMousePosition()
4310 /* This crashes when used within wxHelpContext,
4311 so we have to use the X-specific implementation below.
4313 GdkModifierType *mask;
4314 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4316 return wxPoint(x, y);
4320 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4322 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4323 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4324 Window rootReturn
, childReturn
;
4325 int rootX
, rootY
, winX
, winY
;
4326 unsigned int maskReturn
;
4328 XQueryPointer (display
,
4332 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4333 return wxPoint(rootX
, rootY
);
4337 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4338 void wxAddGrab(wxWindow
* window
)
4340 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4343 void wxRemoveGrab(wxWindow
* window
)
4345 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4348 // ----------------------------------------------------------------------------
4350 // ----------------------------------------------------------------------------
4352 class wxWinModule
: public wxModule
4359 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4362 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4364 bool wxWinModule::OnInit()
4366 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4367 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4372 void wxWinModule::OnExit()
4375 gdk_gc_unref( g_eraseGC
);