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 ( !g_captureWindow
)
1744 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1745 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1747 // Rewrite cursor handling here (away from idle).
1751 if (win
->GetEventHandler()->ProcessEvent( event
))
1753 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1761 //-----------------------------------------------------------------------------
1762 // "mouse_wheel_event"
1763 //-----------------------------------------------------------------------------
1766 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1767 GdkEventScroll
* gdk_event
,
1773 wxapp_install_idle_handler();
1775 wxEventType event_type
= wxEVT_NULL
;
1776 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1777 event_type
= wxEVT_MOUSEWHEEL
;
1778 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1779 event_type
= wxEVT_MOUSEWHEEL
;
1783 wxMouseEvent
event( event_type
);
1784 // Can't use InitMouse macro because scroll events don't have button
1785 event
.SetTimestamp( gdk_event
->time
);
1786 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1787 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1788 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1789 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1790 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1791 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1792 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1793 event
.m_linesPerAction
= 3;
1794 event
.m_wheelDelta
= 120;
1795 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1796 event
.m_wheelRotation
= 120;
1798 event
.m_wheelRotation
= -120;
1800 wxPoint pt
= win
->GetClientAreaOrigin();
1801 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1802 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1804 event
.SetEventObject( win
);
1805 event
.SetId( win
->GetId() );
1806 event
.SetTimestamp( gdk_event
->time
);
1808 if (win
->GetEventHandler()->ProcessEvent( event
))
1810 g_signal_stop_emission_by_name (widget
, "scroll_event");
1818 //-----------------------------------------------------------------------------
1820 //-----------------------------------------------------------------------------
1822 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1824 wxContextMenuEvent
event(
1828 event
.SetEventObject(win
);
1829 return win
->GetEventHandler()->ProcessEvent(event
);
1833 //-----------------------------------------------------------------------------
1835 //-----------------------------------------------------------------------------
1837 // send the wxChildFocusEvent and wxFocusEvent, common code of
1838 // gtk_window_focus_in_callback() and SetFocus()
1839 static bool DoSendFocusEvents(wxWindow
*win
)
1841 // Notify the parent keeping track of focus for the kbd navigation
1842 // purposes that we got it.
1843 wxChildFocusEvent
eventChildFocus(win
);
1844 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1846 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1847 eventFocus
.SetEventObject(win
);
1849 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1853 static gboolean
gtk_window_focus_in_callback( GtkWidget
*widget
,
1854 GdkEvent
*WXUNUSED(event
),
1860 wxapp_install_idle_handler();
1863 gtk_im_context_focus_in(win
->m_imData
->context
);
1866 g_focusWindow
= win
;
1868 wxLogTrace(TRACE_FOCUS
,
1869 _T("%s: focus in"), win
->GetName().c_str());
1873 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1877 // caret needs to be informed about focus change
1878 wxCaret
*caret
= win
->GetCaret();
1881 caret
->OnSetFocus();
1883 #endif // wxUSE_CARET
1885 gboolean ret
= FALSE
;
1887 // does the window itself think that it has the focus?
1888 if ( !win
->m_hasFocus
)
1890 // not yet, notify it
1891 win
->m_hasFocus
= true;
1893 (void)DoSendFocusEvents(win
);
1898 // Disable default focus handling for custom windows
1899 // since the default GTK+ handler issues a repaint
1900 if (win
->m_wxwindow
)
1907 //-----------------------------------------------------------------------------
1908 // "focus_out_event"
1909 //-----------------------------------------------------------------------------
1912 static gboolean
gtk_window_focus_out_callback( GtkWidget
*widget
,
1913 GdkEventFocus
*gdk_event
,
1919 wxapp_install_idle_handler();
1922 gtk_im_context_focus_out(win
->m_imData
->context
);
1924 wxLogTrace( TRACE_FOCUS
,
1925 _T("%s: focus out"), win
->GetName().c_str() );
1928 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1932 g_focusWindow
= (wxWindowGTK
*)NULL
;
1940 // caret needs to be informed about focus change
1941 wxCaret
*caret
= win
->GetCaret();
1944 caret
->OnKillFocus();
1946 #endif // wxUSE_CARET
1948 gboolean ret
= FALSE
;
1950 // don't send the window a kill focus event if it thinks that it doesn't
1951 // have focus already
1952 if ( win
->m_hasFocus
)
1954 win
->m_hasFocus
= false;
1956 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1957 event
.SetEventObject( win
);
1959 (void)win
->GetEventHandler()->ProcessEvent( event
);
1964 // Disable default focus handling for custom windows
1965 // since the default GTK+ handler issues a repaint
1966 if (win
->m_wxwindow
)
1973 //-----------------------------------------------------------------------------
1974 // "enter_notify_event"
1975 //-----------------------------------------------------------------------------
1979 gtk_window_enter_callback( GtkWidget
*widget
,
1980 GdkEventCrossing
*gdk_event
,
1986 wxapp_install_idle_handler();
1988 if (!win
->m_hasVMT
) return FALSE
;
1989 if (g_blockEventsOnDrag
) return FALSE
;
1991 // Event was emitted after a grab
1992 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1994 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1998 GdkModifierType state
= (GdkModifierType
)0;
2000 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2002 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2003 InitMouseEvent(win
, event
, gdk_event
);
2004 wxPoint pt
= win
->GetClientAreaOrigin();
2005 event
.m_x
= x
+ pt
.x
;
2006 event
.m_y
= y
+ pt
.y
;
2008 if ( !g_captureWindow
)
2010 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2011 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2013 // Rewrite cursor handling here (away from idle).
2017 if (win
->GetEventHandler()->ProcessEvent( event
))
2019 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2027 //-----------------------------------------------------------------------------
2028 // "leave_notify_event"
2029 //-----------------------------------------------------------------------------
2033 gtk_window_leave_callback( GtkWidget
*widget
,
2034 GdkEventCrossing
*gdk_event
,
2040 wxapp_install_idle_handler();
2042 if (!win
->m_hasVMT
) return FALSE
;
2043 if (g_blockEventsOnDrag
) return FALSE
;
2045 // Event was emitted after an ungrab
2046 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2048 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2050 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2051 event
.SetTimestamp( gdk_event
->time
);
2052 event
.SetEventObject( win
);
2056 GdkModifierType state
= (GdkModifierType
)0;
2058 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2060 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2061 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2062 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2063 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2064 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2065 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2066 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2068 wxPoint pt
= win
->GetClientAreaOrigin();
2069 event
.m_x
= x
+ pt
.x
;
2070 event
.m_y
= y
+ pt
.y
;
2072 if (win
->GetEventHandler()->ProcessEvent( event
))
2074 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2082 //-----------------------------------------------------------------------------
2083 // "value_changed" from m_vAdjust
2084 //-----------------------------------------------------------------------------
2087 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2093 wxapp_install_idle_handler();
2095 if (g_blockEventsOnDrag
) return;
2097 if (!win
->m_hasVMT
) return;
2099 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2100 if (fabs(diff
) < 0.2) return;
2102 win
->m_oldVerticalPos
= adjust
->value
;
2104 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2106 int value
= (int)(adjust
->value
+0.5);
2108 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2109 event
.SetEventObject( win
);
2110 win
->GetEventHandler()->ProcessEvent( event
);
2114 //-----------------------------------------------------------------------------
2115 // "value_changed" from m_hAdjust
2116 //-----------------------------------------------------------------------------
2119 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2125 wxapp_install_idle_handler();
2127 if (g_blockEventsOnDrag
) return;
2128 if (!win
->m_hasVMT
) return;
2130 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2131 if (fabs(diff
) < 0.2) return;
2133 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2135 win
->m_oldHorizontalPos
= adjust
->value
;
2137 int value
= (int)(adjust
->value
+0.5);
2139 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2140 event
.SetEventObject( win
);
2141 win
->GetEventHandler()->ProcessEvent( event
);
2145 //-----------------------------------------------------------------------------
2146 // "button_press_event" from scrollbar
2147 //-----------------------------------------------------------------------------
2150 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2151 GdkEventButton
*gdk_event
,
2157 wxapp_install_idle_handler();
2160 g_blockEventsOnScroll
= true;
2162 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2164 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2171 //-----------------------------------------------------------------------------
2172 // "button_release_event" from scrollbar
2173 //-----------------------------------------------------------------------------
2176 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2177 GdkEventButton
*WXUNUSED(gdk_event
),
2182 // don't test here as we can release the mouse while being over
2183 // a different window than the slider
2185 // if (gdk_event->window != widget->slider) return FALSE;
2187 g_blockEventsOnScroll
= false;
2189 if (win
->m_isScrolling
)
2191 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2195 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2196 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2198 value
= (int)(win
->m_hAdjust
->value
+0.5);
2201 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2203 value
= (int)(win
->m_vAdjust
->value
+0.5);
2207 wxScrollWinEvent
event( command
, value
, dir
);
2208 event
.SetEventObject( win
);
2209 win
->GetEventHandler()->ProcessEvent( event
);
2212 win
->m_isScrolling
= false;
2218 // ----------------------------------------------------------------------------
2219 // this wxWindowBase function is implemented here (in platform-specific file)
2220 // because it is static and so couldn't be made virtual
2221 // ----------------------------------------------------------------------------
2223 wxWindow
*wxWindowBase::DoFindFocus()
2225 // the cast is necessary when we compile in wxUniversal mode
2226 return (wxWindow
*)g_focusWindow
;
2229 //-----------------------------------------------------------------------------
2230 // "realize" from m_widget
2231 //-----------------------------------------------------------------------------
2233 /* We cannot set colours and fonts before the widget has
2234 been realized, so we do this directly after realization. */
2238 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2243 wxapp_install_idle_handler();
2247 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2248 gtk_im_context_set_client_window( win
->m_imData
->context
,
2249 pizza
->bin_window
);
2252 wxWindowCreateEvent
event( win
);
2253 event
.SetEventObject( win
);
2254 win
->GetEventHandler()->ProcessEvent( event
);
2260 //-----------------------------------------------------------------------------
2262 //-----------------------------------------------------------------------------
2266 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2267 GtkAllocation
*WXUNUSED(alloc
),
2271 wxapp_install_idle_handler();
2273 if (!win
->m_hasScrolling
) return;
2275 int client_width
= 0;
2276 int client_height
= 0;
2277 win
->GetClientSize( &client_width
, &client_height
);
2278 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2281 win
->m_oldClientWidth
= client_width
;
2282 win
->m_oldClientHeight
= client_height
;
2284 if (!win
->m_nativeSizeEvent
)
2286 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2287 event
.SetEventObject( win
);
2288 win
->GetEventHandler()->ProcessEvent( event
);
2295 #define WXUNUSED_UNLESS_XIM(param) param
2297 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2300 /* Resize XIM window */
2304 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2305 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2306 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2309 wxapp_install_idle_handler();
2315 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2319 gdk_window_get_size (widget
->window
, &width
, &height
);
2320 win
->m_icattr
->preedit_area
.width
= width
;
2321 win
->m_icattr
->preedit_area
.height
= height
;
2322 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2328 //-----------------------------------------------------------------------------
2329 // "realize" from m_wxwindow
2330 //-----------------------------------------------------------------------------
2332 /* Initialize XIM support */
2336 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2337 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2340 wxapp_install_idle_handler();
2343 if (win
->m_ic
) return FALSE
;
2344 if (!widget
) return FALSE
;
2345 if (!gdk_im_ready()) return FALSE
;
2347 win
->m_icattr
= gdk_ic_attr_new();
2348 if (!win
->m_icattr
) return FALSE
;
2352 GdkColormap
*colormap
;
2353 GdkICAttr
*attr
= win
->m_icattr
;
2354 unsigned attrmask
= GDK_IC_ALL_REQ
;
2356 GdkIMStyle supported_style
= (GdkIMStyle
)
2357 (GDK_IM_PREEDIT_NONE
|
2358 GDK_IM_PREEDIT_NOTHING
|
2359 GDK_IM_PREEDIT_POSITION
|
2360 GDK_IM_STATUS_NONE
|
2361 GDK_IM_STATUS_NOTHING
);
2363 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2364 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2366 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2367 attr
->client_window
= widget
->window
;
2369 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2370 gtk_widget_get_default_colormap ())
2372 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2373 attr
->preedit_colormap
= colormap
;
2376 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2377 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2378 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2379 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2381 switch (style
& GDK_IM_PREEDIT_MASK
)
2383 case GDK_IM_PREEDIT_POSITION
:
2384 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2386 g_warning ("over-the-spot style requires fontset");
2390 gdk_window_get_size (widget
->window
, &width
, &height
);
2392 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2393 attr
->spot_location
.x
= 0;
2394 attr
->spot_location
.y
= height
;
2395 attr
->preedit_area
.x
= 0;
2396 attr
->preedit_area
.y
= 0;
2397 attr
->preedit_area
.width
= width
;
2398 attr
->preedit_area
.height
= height
;
2399 attr
->preedit_fontset
= widget
->style
->font
;
2404 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2406 if (win
->m_ic
== NULL
)
2407 g_warning ("Can't create input context.");
2410 mask
= gdk_window_get_events (widget
->window
);
2411 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2412 gdk_window_set_events (widget
->window
, mask
);
2414 if (GTK_WIDGET_HAS_FOCUS(widget
))
2415 gdk_im_begin (win
->m_ic
, widget
->window
);
2423 //-----------------------------------------------------------------------------
2424 // InsertChild for wxWindowGTK.
2425 //-----------------------------------------------------------------------------
2427 /* Callback for wxWindowGTK. This very strange beast has to be used because
2428 * C++ has no virtual methods in a constructor. We have to emulate a
2429 * virtual function here as wxNotebook requires a different way to insert
2430 * a child in it. I had opted for creating a wxNotebookPage window class
2431 * which would have made this superfluous (such in the MDI window system),
2432 * but no-one was listening to me... */
2434 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2436 /* the window might have been scrolled already, do we
2437 have to adapt the position */
2438 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2439 child
->m_x
+= pizza
->xoffset
;
2440 child
->m_y
+= pizza
->yoffset
;
2442 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2443 GTK_WIDGET(child
->m_widget
),
2450 //-----------------------------------------------------------------------------
2452 //-----------------------------------------------------------------------------
2454 wxWindow
*wxGetActiveWindow()
2456 return wxWindow::FindFocus();
2460 wxMouseState
wxGetMouseState()
2466 GdkModifierType mask
;
2468 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2472 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2473 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2474 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2476 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2477 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2478 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2479 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2484 //-----------------------------------------------------------------------------
2486 //-----------------------------------------------------------------------------
2488 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2490 #ifdef __WXUNIVERSAL__
2491 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2493 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2494 #endif // __WXUNIVERSAL__/__WXGTK__
2496 void wxWindowGTK::Init()
2499 m_widget
= (GtkWidget
*) NULL
;
2500 m_wxwindow
= (GtkWidget
*) NULL
;
2501 m_focusWidget
= (GtkWidget
*) NULL
;
2511 m_needParent
= true;
2512 m_isBeingDeleted
= false;
2515 m_nativeSizeEvent
= false;
2517 m_hasScrolling
= false;
2518 m_isScrolling
= false;
2520 m_hAdjust
= (GtkAdjustment
*) NULL
;
2521 m_vAdjust
= (GtkAdjustment
*) NULL
;
2522 m_oldHorizontalPos
=
2523 m_oldVerticalPos
= 0.0;
2525 m_oldClientHeight
= 0;
2529 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2531 m_acceptsFocus
= false;
2534 m_clipPaintRegion
= false;
2536 m_needsStyleChange
= false;
2538 m_cursor
= *wxSTANDARD_CURSOR
;
2541 m_dirtyTabOrder
= false;
2544 wxWindowGTK::wxWindowGTK()
2549 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2554 const wxString
&name
)
2558 Create( parent
, id
, pos
, size
, style
, name
);
2561 bool wxWindowGTK::Create( wxWindow
*parent
,
2566 const wxString
&name
)
2568 if (!PreCreation( parent
, pos
, size
) ||
2569 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2571 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2575 m_insertCallback
= wxInsertChildInWindow
;
2577 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2578 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2580 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2582 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2583 scroll_class
->scrollbar_spacing
= 0;
2585 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2587 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2588 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2590 m_wxwindow
= gtk_pizza_new();
2592 #ifndef __WXUNIVERSAL__
2593 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2595 if (HasFlag(wxRAISED_BORDER
))
2597 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2599 else if (HasFlag(wxSUNKEN_BORDER
))
2601 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2603 else if (HasFlag(wxSIMPLE_BORDER
))
2605 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2609 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2611 #endif // __WXUNIVERSAL__
2613 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2615 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2616 m_acceptsFocus
= true;
2618 // I _really_ don't want scrollbars in the beginning
2619 m_vAdjust
->lower
= 0.0;
2620 m_vAdjust
->upper
= 1.0;
2621 m_vAdjust
->value
= 0.0;
2622 m_vAdjust
->step_increment
= 1.0;
2623 m_vAdjust
->page_increment
= 1.0;
2624 m_vAdjust
->page_size
= 5.0;
2625 g_signal_emit_by_name (m_vAdjust
, "changed");
2626 m_hAdjust
->lower
= 0.0;
2627 m_hAdjust
->upper
= 1.0;
2628 m_hAdjust
->value
= 0.0;
2629 m_hAdjust
->step_increment
= 1.0;
2630 m_hAdjust
->page_increment
= 1.0;
2631 m_hAdjust
->page_size
= 5.0;
2632 g_signal_emit_by_name (m_hAdjust
, "changed");
2634 // these handlers block mouse events to any window during scrolling such as
2635 // motion events and prevent GTK and wxWidgets from fighting over where the
2637 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2638 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2639 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2640 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2641 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2642 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2643 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2644 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2646 // these handlers get notified when screen updates are required either when
2647 // scrolling or when the window size (and therefore scrollbar configuration)
2650 g_signal_connect (m_hAdjust
, "value_changed",
2651 G_CALLBACK (gtk_window_hscroll_callback
), this);
2652 g_signal_connect (m_vAdjust
, "value_changed",
2653 G_CALLBACK (gtk_window_vscroll_callback
), this);
2655 gtk_widget_show( m_wxwindow
);
2658 m_parent
->DoAddChild( this );
2660 m_focusWidget
= m_wxwindow
;
2667 wxWindowGTK::~wxWindowGTK()
2671 if (g_focusWindow
== this)
2672 g_focusWindow
= NULL
;
2674 if ( g_delayedFocus
== this )
2675 g_delayedFocus
= NULL
;
2677 m_isBeingDeleted
= true;
2680 // destroy children before destroying this window itself
2683 // unhook focus handlers to prevent stray events being
2684 // propagated to this (soon to be) dead object
2685 if (m_focusWidget
!= NULL
)
2687 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2688 (gpointer
) gtk_window_focus_in_callback
,
2690 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2691 (gpointer
) gtk_window_focus_out_callback
,
2700 gdk_ic_destroy (m_ic
);
2702 gdk_ic_attr_destroy (m_icattr
);
2705 // delete before the widgets to avoid a crash on solaris
2710 gtk_widget_destroy( m_wxwindow
);
2711 m_wxwindow
= (GtkWidget
*) NULL
;
2716 gtk_widget_destroy( m_widget
);
2717 m_widget
= (GtkWidget
*) NULL
;
2721 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2723 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2725 // Use either the given size, or the default if -1 is given.
2726 // See wxWindowBase for these functions.
2727 m_width
= WidthDefault(size
.x
) ;
2728 m_height
= HeightDefault(size
.y
);
2736 void wxWindowGTK::PostCreation()
2738 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2744 // these get reported to wxWidgets -> wxPaintEvent
2746 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2748 g_signal_connect (m_wxwindow
, "expose_event",
2749 G_CALLBACK (gtk_window_expose_callback
), this);
2751 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2754 // Create input method handler
2755 m_imData
= new wxGtkIMData
;
2757 // Cannot handle drawing preedited text yet
2758 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2760 g_signal_connect (m_imData
->context
, "commit",
2761 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2763 // these are called when the "sunken" or "raised" borders are drawn
2764 g_signal_connect (m_widget
, "expose_event",
2765 G_CALLBACK (gtk_window_own_expose_callback
), this);
2770 if (!GTK_IS_WINDOW(m_widget
))
2772 if (m_focusWidget
== NULL
)
2773 m_focusWidget
= m_widget
;
2777 g_signal_connect (m_focusWidget
, "focus_in_event",
2778 G_CALLBACK (gtk_window_focus_in_callback
), this);
2779 g_signal_connect (m_focusWidget
, "focus_out_event",
2780 G_CALLBACK (gtk_window_focus_out_callback
), this);
2784 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2785 G_CALLBACK (gtk_window_focus_in_callback
), this);
2786 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2787 G_CALLBACK (gtk_window_focus_out_callback
), this);
2791 // connect to the various key and mouse handlers
2793 GtkWidget
*connect_widget
= GetConnectWidget();
2795 ConnectWidget( connect_widget
);
2797 /* We cannot set colours, fonts and cursors before the widget has
2798 been realized, so we do this directly after realization */
2799 g_signal_connect (connect_widget
, "realize",
2800 G_CALLBACK (gtk_window_realized_callback
), this);
2804 // Catch native resize events
2805 g_signal_connect (m_wxwindow
, "size_allocate",
2806 G_CALLBACK (gtk_window_size_callback
), this);
2808 // Initialize XIM support
2809 g_signal_connect (m_wxwindow
, "realize",
2810 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2812 // And resize XIM window
2813 g_signal_connect (m_wxwindow
, "size_allocate",
2814 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2817 if (GTK_IS_COMBO(m_widget
))
2819 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2821 g_signal_connect (gcombo
->entry
, "size_request",
2822 G_CALLBACK (wxgtk_combo_size_request_callback
),
2827 // This is needed if we want to add our windows into native
2828 // GTK controls, such as the toolbar. With this callback, the
2829 // toolbar gets to know the correct size (the one set by the
2830 // programmer). Sadly, it misbehaves for wxComboBox.
2831 g_signal_connect (m_widget
, "size_request",
2832 G_CALLBACK (wxgtk_window_size_request_callback
),
2836 InheritAttributes();
2840 // unless the window was created initially hidden (i.e. Hide() had been
2841 // called before Create()), we should show it at GTK+ level as well
2843 gtk_widget_show( m_widget
);
2846 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2848 g_signal_connect (widget
, "key_press_event",
2849 G_CALLBACK (gtk_window_key_press_callback
), this);
2850 g_signal_connect (widget
, "key_release_event",
2851 G_CALLBACK (gtk_window_key_release_callback
), this);
2852 g_signal_connect (widget
, "button_press_event",
2853 G_CALLBACK (gtk_window_button_press_callback
), this);
2854 g_signal_connect (widget
, "button_release_event",
2855 G_CALLBACK (gtk_window_button_release_callback
), this);
2856 g_signal_connect (widget
, "motion_notify_event",
2857 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2858 g_signal_connect (widget
, "scroll_event",
2859 G_CALLBACK (gtk_window_wheel_callback
), this);
2860 g_signal_connect (widget
, "popup_menu",
2861 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2862 g_signal_connect (widget
, "enter_notify_event",
2863 G_CALLBACK (gtk_window_enter_callback
), this);
2864 g_signal_connect (widget
, "leave_notify_event",
2865 G_CALLBACK (gtk_window_leave_callback
), this);
2868 bool wxWindowGTK::Destroy()
2870 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2874 return wxWindowBase::Destroy();
2877 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2879 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2882 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2884 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2885 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2888 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2891 if (m_resizing
) return; /* I don't like recursions */
2894 int currentX
, currentY
;
2895 GetPosition(¤tX
, ¤tY
);
2896 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2898 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2900 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2902 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2904 /* don't set the size for children of wxNotebook, just take the values. */
2912 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2913 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2915 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2916 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2920 m_x
= x
+ pizza
->xoffset
;
2921 m_y
= y
+ pizza
->yoffset
;
2924 // calculate the best size if we should auto size the window
2925 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2926 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2928 const wxSize sizeBest
= GetBestSize();
2929 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2931 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2932 height
= sizeBest
.y
;
2940 int minWidth
= GetMinWidth(),
2941 minHeight
= GetMinHeight(),
2942 maxWidth
= GetMaxWidth(),
2943 maxHeight
= GetMaxHeight();
2945 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2946 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2947 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2948 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2950 int left_border
= 0;
2951 int right_border
= 0;
2953 int bottom_border
= 0;
2955 /* the default button has a border around it */
2956 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2958 GtkBorder
*default_border
= NULL
;
2959 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2962 left_border
+= default_border
->left
;
2963 right_border
+= default_border
->right
;
2964 top_border
+= default_border
->top
;
2965 bottom_border
+= default_border
->bottom
;
2966 g_free( default_border
);
2970 DoMoveWindow( m_x
-top_border
,
2972 m_width
+left_border
+right_border
,
2973 m_height
+top_border
+bottom_border
);
2978 /* Sometimes the client area changes size without the
2979 whole windows's size changing, but if the whole
2980 windows's size doesn't change, no wxSizeEvent will
2981 normally be sent. Here we add an extra test if
2982 the client test has been changed and this will
2984 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2988 wxPrintf( "OnSize sent from " );
2989 if (GetClassInfo() && GetClassInfo()->GetClassName())
2990 wxPrintf( GetClassInfo()->GetClassName() );
2991 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2994 if (!m_nativeSizeEvent
)
2996 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2997 event
.SetEventObject( this );
2998 GetEventHandler()->ProcessEvent( event
);
3004 void wxWindowGTK::OnInternalIdle()
3006 if ( m_dirtyTabOrder
)
3008 m_dirtyTabOrder
= false;
3012 // Update style if the window was not yet realized
3013 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3014 if (m_needsStyleChange
)
3016 SetBackgroundStyle(GetBackgroundStyle());
3017 m_needsStyleChange
= false;
3020 // Update invalidated regions.
3023 wxCursor cursor
= m_cursor
;
3024 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3028 /* I now set the cursor anew in every OnInternalIdle call
3029 as setting the cursor in a parent window also effects the
3030 windows above so that checking for the current cursor is
3035 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3037 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3039 if (!g_globalCursor
.Ok())
3040 cursor
= *wxSTANDARD_CURSOR
;
3042 window
= m_widget
->window
;
3043 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3044 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3050 GdkWindow
*window
= m_widget
->window
;
3051 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3052 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3057 if (wxUpdateUIEvent::CanUpdate(this))
3058 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3061 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3063 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3065 if (width
) (*width
) = m_width
;
3066 if (height
) (*height
) = m_height
;
3069 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3071 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3075 SetSize( width
, height
);
3082 #ifndef __WXUNIVERSAL__
3083 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3085 /* when using GTK 1.2 we set the shadow border size to 2 */
3089 if (HasFlag(wxSIMPLE_BORDER
))
3091 /* when using GTK 1.2 we set the simple border size to 1 */
3095 #endif // __WXUNIVERSAL__
3099 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3101 GtkRequisition vscroll_req
;
3102 vscroll_req
.width
= 2;
3103 vscroll_req
.height
= 2;
3104 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3105 (scroll_window
->vscrollbar
, &vscroll_req
);
3107 GtkRequisition hscroll_req
;
3108 hscroll_req
.width
= 2;
3109 hscroll_req
.height
= 2;
3110 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3111 (scroll_window
->hscrollbar
, &hscroll_req
);
3113 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3115 if (scroll_window
->vscrollbar_visible
)
3117 dw
+= vscroll_req
.width
;
3118 dw
+= scroll_class
->scrollbar_spacing
;
3121 if (scroll_window
->hscrollbar_visible
)
3123 dh
+= hscroll_req
.height
;
3124 dh
+= scroll_class
->scrollbar_spacing
;
3128 SetSize( width
+dw
, height
+dh
);
3132 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3134 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3138 if (width
) (*width
) = m_width
;
3139 if (height
) (*height
) = m_height
;
3146 #ifndef __WXUNIVERSAL__
3147 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3149 /* when using GTK 1.2 we set the shadow border size to 2 */
3153 if (HasFlag(wxSIMPLE_BORDER
))
3155 /* when using GTK 1.2 we set the simple border size to 1 */
3159 #endif // __WXUNIVERSAL__
3163 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3165 GtkRequisition vscroll_req
;
3166 vscroll_req
.width
= 2;
3167 vscroll_req
.height
= 2;
3168 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3169 (scroll_window
->vscrollbar
, &vscroll_req
);
3171 GtkRequisition hscroll_req
;
3172 hscroll_req
.width
= 2;
3173 hscroll_req
.height
= 2;
3174 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3175 (scroll_window
->hscrollbar
, &hscroll_req
);
3177 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3179 if (scroll_window
->vscrollbar_visible
)
3181 dw
+= vscroll_req
.width
;
3182 dw
+= scroll_class
->scrollbar_spacing
;
3185 if (scroll_window
->hscrollbar_visible
)
3187 dh
+= hscroll_req
.height
;
3188 dh
+= scroll_class
->scrollbar_spacing
;
3192 if (width
) (*width
) = m_width
- dw
;
3193 if (height
) (*height
) = m_height
- dh
;
3197 printf( "GetClientSize, name %s ", GetName().c_str() );
3198 if (width) printf( " width = %d", (*width) );
3199 if (height) printf( " height = %d", (*height) );
3204 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3206 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3210 if (m_parent
&& m_parent
->m_wxwindow
)
3212 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3213 dx
= pizza
->xoffset
;
3214 dy
= pizza
->yoffset
;
3217 if (x
) (*x
) = m_x
- dx
;
3218 if (y
) (*y
) = m_y
- dy
;
3221 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3223 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3225 if (!m_widget
->window
) return;
3227 GdkWindow
*source
= (GdkWindow
*) NULL
;
3229 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3231 source
= m_widget
->window
;
3235 gdk_window_get_origin( source
, &org_x
, &org_y
);
3239 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3241 org_x
+= m_widget
->allocation
.x
;
3242 org_y
+= m_widget
->allocation
.y
;
3250 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3252 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3254 if (!m_widget
->window
) return;
3256 GdkWindow
*source
= (GdkWindow
*) NULL
;
3258 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3260 source
= m_widget
->window
;
3264 gdk_window_get_origin( source
, &org_x
, &org_y
);
3268 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3270 org_x
+= m_widget
->allocation
.x
;
3271 org_y
+= m_widget
->allocation
.y
;
3279 bool wxWindowGTK::Show( bool show
)
3281 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3283 if (!wxWindowBase::Show(show
))
3290 gtk_widget_show( m_widget
);
3292 gtk_widget_hide( m_widget
);
3294 wxShowEvent
eventShow(GetId(), show
);
3295 eventShow
.SetEventObject(this);
3297 GetEventHandler()->ProcessEvent(eventShow
);
3302 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3304 win
->OnParentEnable(enable
);
3306 // Recurse, so that children have the opportunity to Do The Right Thing
3307 // and reset colours that have been messed up by a parent's (really ancestor's)
3309 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3311 node
= node
->GetNext() )
3313 wxWindow
*child
= node
->GetData();
3314 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3315 wxWindowNotifyEnable(child
, enable
);
3319 bool wxWindowGTK::Enable( bool enable
)
3321 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3323 if (!wxWindowBase::Enable(enable
))
3329 gtk_widget_set_sensitive( m_widget
, enable
);
3331 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3333 wxWindowNotifyEnable(this, enable
);
3338 int wxWindowGTK::GetCharHeight() const
3340 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3342 wxFont font
= GetFont();
3343 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3345 PangoContext
*context
= NULL
;
3347 context
= gtk_widget_get_pango_context( m_widget
);
3352 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3353 PangoLayout
*layout
= pango_layout_new(context
);
3354 pango_layout_set_font_description(layout
, desc
);
3355 pango_layout_set_text(layout
, "H", 1);
3356 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3358 PangoRectangle rect
;
3359 pango_layout_line_get_extents(line
, NULL
, &rect
);
3361 g_object_unref( G_OBJECT( layout
) );
3363 return (int) PANGO_PIXELS(rect
.height
);
3366 int wxWindowGTK::GetCharWidth() const
3368 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3370 wxFont font
= GetFont();
3371 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3373 PangoContext
*context
= NULL
;
3375 context
= gtk_widget_get_pango_context( m_widget
);
3380 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3381 PangoLayout
*layout
= pango_layout_new(context
);
3382 pango_layout_set_font_description(layout
, desc
);
3383 pango_layout_set_text(layout
, "g", 1);
3384 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3386 PangoRectangle rect
;
3387 pango_layout_line_get_extents(line
, NULL
, &rect
);
3389 g_object_unref( G_OBJECT( layout
) );
3391 return (int) PANGO_PIXELS(rect
.width
);
3394 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3398 int *externalLeading
,
3399 const wxFont
*theFont
) const
3401 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3403 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3412 PangoContext
*context
= NULL
;
3414 context
= gtk_widget_get_pango_context( m_widget
);
3423 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3424 PangoLayout
*layout
= pango_layout_new(context
);
3425 pango_layout_set_font_description(layout
, desc
);
3428 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3429 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3431 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3432 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3433 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3437 PangoRectangle rect
;
3438 pango_layout_get_extents(layout
, NULL
, &rect
);
3440 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3441 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3444 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3445 int baseline
= pango_layout_iter_get_baseline(iter
);
3446 pango_layout_iter_free(iter
);
3447 *descent
= *y
- PANGO_PIXELS(baseline
);
3449 if (externalLeading
) (*externalLeading
) = 0; // ??
3451 g_object_unref( G_OBJECT( layout
) );
3454 void wxWindowGTK::SetFocus()
3456 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3459 // don't do anything if we already have focus
3465 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3467 gtk_widget_grab_focus (m_wxwindow
);
3472 if (GTK_IS_CONTAINER(m_widget
))
3474 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3477 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3480 if (!GTK_WIDGET_REALIZED(m_widget
))
3482 // we can't set the focus to the widget now so we remember that
3483 // it should be focused and will do it later, during the idle
3484 // time, as soon as we can
3485 wxLogTrace(TRACE_FOCUS
,
3486 _T("Delaying setting focus to %s(%s)"),
3487 GetClassInfo()->GetClassName(), GetLabel().c_str());
3489 g_delayedFocus
= this;
3493 wxLogTrace(TRACE_FOCUS
,
3494 _T("Setting focus to %s(%s)"),
3495 GetClassInfo()->GetClassName(), GetLabel().c_str());
3497 gtk_widget_grab_focus (m_widget
);
3502 wxLogTrace(TRACE_FOCUS
,
3503 _T("Can't set focus to %s(%s)"),
3504 GetClassInfo()->GetClassName(), GetLabel().c_str());
3509 bool wxWindowGTK::AcceptsFocus() const
3511 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3514 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3516 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3518 wxWindowGTK
*oldParent
= m_parent
,
3519 *newParent
= (wxWindowGTK
*)newParentBase
;
3521 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3523 if ( !wxWindowBase::Reparent(newParent
) )
3526 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3528 /* prevent GTK from deleting the widget arbitrarily */
3529 gtk_widget_ref( m_widget
);
3533 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3536 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3540 /* insert GTK representation */
3541 (*(newParent
->m_insertCallback
))(newParent
, this);
3544 /* reverse: prevent GTK from deleting the widget arbitrarily */
3545 gtk_widget_unref( m_widget
);
3550 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3552 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3554 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3556 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3561 /* insert GTK representation */
3562 (*m_insertCallback
)(this, child
);
3565 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3567 wxWindowBase::AddChild(child
);
3568 m_dirtyTabOrder
= true;
3570 wxapp_install_idle_handler();
3573 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3575 wxWindowBase::RemoveChild(child
);
3576 m_dirtyTabOrder
= true;
3578 wxapp_install_idle_handler();
3581 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3583 wxWindowBase::DoMoveInTabOrder(win
, move
);
3584 m_dirtyTabOrder
= true;
3586 wxapp_install_idle_handler();
3589 void wxWindowGTK::RealizeTabOrder()
3593 if ( !m_children
.empty() )
3596 // we don't only construct the correct focus chain but also use
3597 // this opportunity to update the mnemonic widgets for all labels
3599 // it would be nice to extract this code from here and put it in
3600 // stattext.cpp to reduce dependencies but there is no really easy
3601 // way to do it unfortunately
3602 wxStaticText
*lastLabel
= NULL
;
3603 #endif // wxUSE_STATTEXT
3605 GList
*chain
= NULL
;
3607 for ( wxWindowList::const_iterator i
= m_children
.begin();
3608 i
!= m_children
.end();
3611 wxWindowGTK
*win
= *i
;
3615 if ( win
->AcceptsFocusFromKeyboard() )
3617 GtkLabel
*l
= GTK_LABEL(lastLabel
->m_widget
);
3618 gtk_label_set_mnemonic_widget(l
, win
->m_widget
);
3622 else // check if this one is a label
3624 lastLabel
= wxDynamicCast(win
, wxStaticText
);
3626 #endif // wxUSE_STATTEXT
3628 chain
= g_list_prepend(chain
, win
->m_widget
);
3631 chain
= g_list_reverse(chain
);
3633 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3638 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3643 void wxWindowGTK::Raise()
3645 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3647 if (m_wxwindow
&& m_wxwindow
->window
)
3649 gdk_window_raise( m_wxwindow
->window
);
3651 else if (m_widget
->window
)
3653 gdk_window_raise( m_widget
->window
);
3657 void wxWindowGTK::Lower()
3659 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3661 if (m_wxwindow
&& m_wxwindow
->window
)
3663 gdk_window_lower( m_wxwindow
->window
);
3665 else if (m_widget
->window
)
3667 gdk_window_lower( m_widget
->window
);
3671 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3673 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3675 if (cursor
== m_cursor
)
3679 wxapp_install_idle_handler();
3681 if (cursor
== wxNullCursor
)
3682 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3684 return wxWindowBase::SetCursor( cursor
);
3687 void wxWindowGTK::WarpPointer( int x
, int y
)
3689 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3691 // We provide this function ourselves as it is
3692 // missing in GDK (top of this file).
3694 GdkWindow
*window
= (GdkWindow
*) NULL
;
3696 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3698 window
= GetConnectWidget()->window
;
3701 gdk_window_warp_pointer( window
, x
, y
);
3704 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3706 double value_start
= adj
->value
;
3707 double value
= value_start
+ change
;
3708 double upper
= adj
->upper
- adj
->page_size
;
3713 // Lower bound will be checked by gtk_adjustment_set_value
3714 gtk_adjustment_set_value(adj
, value
);
3715 return adj
->value
!= value_start
;
3718 bool wxWindowGTK::ScrollLines(int lines
)
3721 m_vAdjust
!= NULL
&&
3722 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3725 bool wxWindowGTK::ScrollPages(int pages
)
3728 m_vAdjust
!= NULL
&&
3729 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3732 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3734 wxASSERT(m_vAdjust
== NULL
);
3738 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3742 if (!m_widget
->window
)
3747 GdkRectangle gdk_rect
,
3751 gdk_rect
.x
= rect
->x
;
3752 gdk_rect
.y
= rect
->y
;
3753 gdk_rect
.width
= rect
->width
;
3754 gdk_rect
.height
= rect
->height
;
3757 else // invalidate everything
3762 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3766 void wxWindowGTK::Update()
3770 // when we call Update() we really want to update the window immediately on
3771 // screen, even if it means flushing the entire queue and hence slowing down
3772 // everything -- but it should still be done, it's just that Update() should
3773 // be called very rarely
3777 void wxWindowGTK::GtkUpdate()
3779 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3780 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3782 // for consistency with other platforms (and also because it's convenient
3783 // to be able to update an entire TLW by calling Update() only once), we
3784 // should also update all our children here
3785 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3787 node
= node
->GetNext() )
3789 node
->GetData()->GtkUpdate();
3793 void wxWindowGTK::GtkSendPaintEvents()
3797 m_updateRegion
.Clear();
3801 // Clip to paint region in wxClientDC
3802 m_clipPaintRegion
= true;
3804 // widget to draw on
3805 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3807 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3809 // find ancestor from which to steal background
3810 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3812 parent
= (wxWindow
*)this;
3814 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3816 wxRegionIterator
upd( m_updateRegion
);
3820 rect
.x
= upd
.GetX();
3821 rect
.y
= upd
.GetY();
3822 rect
.width
= upd
.GetWidth();
3823 rect
.height
= upd
.GetHeight();
3825 gtk_paint_flat_box( parent
->m_widget
->style
,
3827 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3841 wxWindowDC
dc( (wxWindow
*)this );
3842 dc
.SetClippingRegion( m_updateRegion
);
3844 wxEraseEvent
erase_event( GetId(), &dc
);
3845 erase_event
.SetEventObject( this );
3847 GetEventHandler()->ProcessEvent(erase_event
);
3850 wxNcPaintEvent
nc_paint_event( GetId() );
3851 nc_paint_event
.SetEventObject( this );
3852 GetEventHandler()->ProcessEvent( nc_paint_event
);
3854 wxPaintEvent
paint_event( GetId() );
3855 paint_event
.SetEventObject( this );
3856 GetEventHandler()->ProcessEvent( paint_event
);
3858 m_clipPaintRegion
= false;
3860 m_updateRegion
.Clear();
3863 void wxWindowGTK::ClearBackground()
3865 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3869 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3871 wxWindowBase::DoSetToolTip(tip
);
3874 m_tooltip
->Apply( (wxWindow
*)this );
3877 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3879 wxString
tmp( tip
);
3880 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3882 #endif // wxUSE_TOOLTIPS
3884 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3886 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3888 if (!wxWindowBase::SetBackgroundColour(colour
))
3893 // We need the pixel value e.g. for background clearing.
3894 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3897 // apply style change (forceStyle=true so that new style is applied
3898 // even if the bg colour changed from valid to wxNullColour)
3899 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3900 ApplyWidgetStyle(true);
3905 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3907 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3909 if (!wxWindowBase::SetForegroundColour(colour
))
3916 // We need the pixel value e.g. for background clearing.
3917 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3920 // apply style change (forceStyle=true so that new style is applied
3921 // even if the bg colour changed from valid to wxNullColour):
3922 ApplyWidgetStyle(true);
3927 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3929 return gtk_widget_get_pango_context( m_widget
);
3932 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3934 // do we need to apply any changes at all?
3937 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3942 GtkRcStyle
*style
= gtk_rc_style_new();
3947 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3950 if ( m_foregroundColour
.Ok() )
3952 GdkColor
*fg
= m_foregroundColour
.GetColor();
3954 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3955 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3957 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3958 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3960 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3961 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3964 if ( m_backgroundColour
.Ok() )
3966 GdkColor
*bg
= m_backgroundColour
.GetColor();
3968 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3969 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3970 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3971 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3973 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3974 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3975 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3976 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3978 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3979 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3980 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3981 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3983 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3984 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3985 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3986 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3992 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3994 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3997 DoApplyWidgetStyle(style
);
3998 gtk_rc_style_unref(style
);
4001 // Style change may affect GTK+'s size calculation:
4002 InvalidateBestSize();
4005 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4008 gtk_widget_modify_style(m_wxwindow
, style
);
4010 gtk_widget_modify_style(m_widget
, style
);
4013 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4015 wxWindowBase::SetBackgroundStyle(style
);
4017 if (style
== wxBG_STYLE_CUSTOM
)
4019 GdkWindow
*window
= (GdkWindow
*) NULL
;
4021 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4023 window
= GetConnectWidget()->window
;
4027 // Make sure GDK/X11 doesn't refresh the window
4029 gdk_window_set_back_pixmap( window
, None
, False
);
4031 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4034 m_needsStyleChange
= false;
4037 // Do in OnIdle, because the window is not yet available
4038 m_needsStyleChange
= true;
4040 // Don't apply widget style, or we get a grey background
4044 // apply style change (forceStyle=true so that new style is applied
4045 // even if the bg colour changed from valid to wxNullColour):
4046 ApplyWidgetStyle(true);
4051 #if wxUSE_DRAG_AND_DROP
4053 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4055 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4057 GtkWidget
*dnd_widget
= GetConnectWidget();
4059 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4061 if (m_dropTarget
) delete m_dropTarget
;
4062 m_dropTarget
= dropTarget
;
4064 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4067 #endif // wxUSE_DRAG_AND_DROP
4069 GtkWidget
* wxWindowGTK::GetConnectWidget()
4071 GtkWidget
*connect_widget
= m_widget
;
4072 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4074 return connect_widget
;
4077 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4080 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4082 return (window
== m_widget
->window
);
4085 bool wxWindowGTK::SetFont( const wxFont
&font
)
4087 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4089 if (!wxWindowBase::SetFont(font
))
4092 // apply style change (forceStyle=true so that new style is applied
4093 // even if the font changed from valid to wxNullFont):
4094 ApplyWidgetStyle(true);
4099 void wxWindowGTK::DoCaptureMouse()
4101 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4103 GdkWindow
*window
= (GdkWindow
*) NULL
;
4105 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4107 window
= GetConnectWidget()->window
;
4109 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4111 wxCursor
* cursor
= & m_cursor
;
4113 cursor
= wxSTANDARD_CURSOR
;
4115 gdk_pointer_grab( window
, FALSE
,
4117 (GDK_BUTTON_PRESS_MASK
|
4118 GDK_BUTTON_RELEASE_MASK
|
4119 GDK_POINTER_MOTION_HINT_MASK
|
4120 GDK_POINTER_MOTION_MASK
),
4122 cursor
->GetCursor(),
4123 (guint32
)GDK_CURRENT_TIME
);
4124 g_captureWindow
= this;
4125 g_captureWindowHasMouse
= true;
4128 void wxWindowGTK::DoReleaseMouse()
4130 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4132 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4134 g_captureWindow
= (wxWindowGTK
*) NULL
;
4136 GdkWindow
*window
= (GdkWindow
*) NULL
;
4138 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4140 window
= GetConnectWidget()->window
;
4145 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4149 wxWindow
*wxWindowBase::GetCapture()
4151 return (wxWindow
*)g_captureWindow
;
4154 bool wxWindowGTK::IsRetained() const
4159 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4160 int range
, bool refresh
)
4162 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4164 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4166 m_hasScrolling
= true;
4168 if (orient
== wxHORIZONTAL
)
4170 float fpos
= (float)pos
;
4171 float frange
= (float)range
;
4172 float fthumb
= (float)thumbVisible
;
4173 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4174 if (fpos
< 0.0) fpos
= 0.0;
4176 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4177 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4179 SetScrollPos( orient
, pos
, refresh
);
4183 m_oldHorizontalPos
= fpos
;
4185 m_hAdjust
->lower
= 0.0;
4186 m_hAdjust
->upper
= frange
;
4187 m_hAdjust
->value
= fpos
;
4188 m_hAdjust
->step_increment
= 1.0;
4189 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4190 m_hAdjust
->page_size
= fthumb
;
4194 float fpos
= (float)pos
;
4195 float frange
= (float)range
;
4196 float fthumb
= (float)thumbVisible
;
4197 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4198 if (fpos
< 0.0) fpos
= 0.0;
4200 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4201 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4203 SetScrollPos( orient
, pos
, refresh
);
4207 m_oldVerticalPos
= fpos
;
4209 m_vAdjust
->lower
= 0.0;
4210 m_vAdjust
->upper
= frange
;
4211 m_vAdjust
->value
= fpos
;
4212 m_vAdjust
->step_increment
= 1.0;
4213 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4214 m_vAdjust
->page_size
= fthumb
;
4217 if (orient
== wxHORIZONTAL
)
4218 g_signal_emit_by_name (m_hAdjust
, "changed");
4220 g_signal_emit_by_name (m_vAdjust
, "changed");
4223 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4225 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4226 gpointer fn
= orient
== wxHORIZONTAL
4227 ? (gpointer
) gtk_window_hscroll_callback
4228 : (gpointer
) gtk_window_vscroll_callback
;
4230 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4231 g_signal_emit_by_name (adj
, "value_changed");
4232 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4235 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4237 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4238 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4240 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4242 float fpos
= (float)pos
;
4243 if (fpos
> adj
->upper
- adj
->page_size
)
4244 fpos
= adj
->upper
- adj
->page_size
;
4247 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4249 if (fabs(fpos
-adj
->value
) < 0.2)
4253 if ( m_wxwindow
->window
)
4258 int wxWindowGTK::GetScrollThumb( int orient
) const
4260 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4262 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4264 if (orient
== wxHORIZONTAL
)
4265 return (int)(m_hAdjust
->page_size
+0.5);
4267 return (int)(m_vAdjust
->page_size
+0.5);
4270 int wxWindowGTK::GetScrollPos( int orient
) const
4272 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4274 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4276 if (orient
== wxHORIZONTAL
)
4277 return (int)(m_hAdjust
->value
+0.5);
4279 return (int)(m_vAdjust
->value
+0.5);
4282 int wxWindowGTK::GetScrollRange( int orient
) const
4284 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4286 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4288 if (orient
== wxHORIZONTAL
)
4289 return (int)(m_hAdjust
->upper
+0.5);
4291 return (int)(m_vAdjust
->upper
+0.5);
4294 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4296 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4298 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4300 // No scrolling requested.
4301 if ((dx
== 0) && (dy
== 0)) return;
4303 m_clipPaintRegion
= true;
4305 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4307 m_clipPaintRegion
= false;
4310 void wxWindowGTK::SetWindowStyleFlag( long style
)
4312 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4313 wxWindowBase::SetWindowStyleFlag(style
);
4316 // Find the wxWindow at the current mouse position, also returning the mouse
4318 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4320 pt
= wxGetMousePosition();
4321 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4325 // Get the current mouse position.
4326 wxPoint
wxGetMousePosition()
4328 /* This crashes when used within wxHelpContext,
4329 so we have to use the X-specific implementation below.
4331 GdkModifierType *mask;
4332 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4334 return wxPoint(x, y);
4338 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4340 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4341 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4342 Window rootReturn
, childReturn
;
4343 int rootX
, rootY
, winX
, winY
;
4344 unsigned int maskReturn
;
4346 XQueryPointer (display
,
4350 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4351 return wxPoint(rootX
, rootY
);
4355 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4356 void wxAddGrab(wxWindow
* window
)
4358 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4361 void wxRemoveGrab(wxWindow
* window
)
4363 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4366 // ----------------------------------------------------------------------------
4368 // ----------------------------------------------------------------------------
4370 class wxWinModule
: public wxModule
4377 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4380 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4382 bool wxWinModule::OnInit()
4384 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4385 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4390 void wxWinModule::OnExit()
4393 gdk_gc_unref( g_eraseGC
);