1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/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"
27 #if wxUSE_TOOLBAR_NATIVE
28 #include "wx/toolbar.h"
31 #if wxUSE_DRAG_AND_DROP
36 #include "wx/tooltip.h"
44 #include "wx/textctrl.h"
48 #include "wx/statusbr.h"
50 #include "wx/settings.h"
52 #include "wx/fontutil.h"
55 #include "wx/thread.h"
61 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
62 #include <gtk/gtkversion.h>
63 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
64 #undef GTK_DISABLE_DEPRECATED
67 #include "wx/gtk/private.h"
68 #include <gdk/gdkprivate.h>
69 #include <gdk/gdkkeysyms.h>
73 #include <gtk/gtkprivate.h>
75 #include "wx/gtk/win_gtk.h"
77 #include <pango/pangox.h>
83 extern GtkContainerClass
*pizza_parent_class
;
85 //-----------------------------------------------------------------------------
86 // documentation on internals
87 //-----------------------------------------------------------------------------
90 I have been asked several times about writing some documentation about
91 the GTK port of wxWidgets, especially its internal structures. Obviously,
92 you cannot understand wxGTK without knowing a little about the GTK, but
93 some more information about what the wxWindow, which is the base class
94 for all other window classes, does seems required as well.
98 What does wxWindow do? It contains the common interface for the following
99 jobs of its descendants:
101 1) Define the rudimentary behaviour common to all window classes, such as
102 resizing, intercepting user input (so as to make it possible to use these
103 events for special purposes in a derived class), window names etc.
105 2) Provide the possibility to contain and manage children, if the derived
106 class is allowed to contain children, which holds true for those window
107 classes which do not display a native GTK widget. To name them, these
108 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
109 work classes are a special case and are handled a bit differently from
110 the rest. The same holds true for the wxNotebook class.
112 3) Provide the possibility to draw into a client area of a window. This,
113 too, only holds true for classes that do not display a native GTK widget
116 4) Provide the entire mechanism for scrolling widgets. This actual inter-
117 face for this is usually in wxScrolledWindow, but the GTK implementation
120 5) A multitude of helper or extra methods for special purposes, such as
121 Drag'n'Drop, managing validators etc.
123 6) Display a border (sunken, raised, simple or none).
125 Normally one might expect, that one wxWidgets window would always correspond
126 to one GTK widget. Under GTK, there is no such allround widget that has all
127 the functionality. Moreover, the GTK defines a client area as a different
128 widget from the actual widget you are handling. Last but not least some
129 special classes (e.g. wxFrame) handle different categories of widgets and
130 still have the possibility to draw something in the client area.
131 It was therefore required to write a special purpose GTK widget, that would
132 represent a client area in the sense of wxWidgets capable to do the jobs
133 2), 3) and 4). I have written this class and it resides in win_gtk.c of
136 All windows must have a widget, with which they interact with other under-
137 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
138 the wxWindow class has a member variable called m_widget which holds a
139 pointer to this widget. When the window class represents a GTK native widget,
140 this is (in most cases) the only GTK widget the class manages. E.g. the
141 wxStaticText class handles only a GtkLabel widget a pointer to which you
142 can find in m_widget (defined in wxWindow)
144 When the class has a client area for drawing into and for containing children
145 it has to handle the client area widget (of the type GtkPizza, defined in
146 win_gtk.c), but there could be any number of widgets, handled by a class
147 The common rule for all windows is only, that the widget that interacts with
148 the rest of GTK must be referenced in m_widget and all other widgets must be
149 children of this widget on the GTK level. The top-most widget, which also
150 represents the client area, must be in the m_wxwindow field and must be of
153 As I said, the window classes that display a GTK native widget only have
154 one widget, so in the case of e.g. the wxButton class m_widget holds a
155 pointer to a GtkButton widget. But windows with client areas (for drawing
156 and children) have a m_widget field that is a pointer to a GtkScrolled-
157 Window and a m_wxwindow field that is pointer to a GtkPizza and this
158 one is (in the GTK sense) a child of the GtkScrolledWindow.
160 If the m_wxwindow field is set, then all input to this widget is inter-
161 cepted and sent to the wxWidgets class. If not, all input to the widget
162 that gets pointed to by m_widget gets intercepted and sent to the class.
166 The design of scrolling in wxWidgets is markedly different from that offered
167 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
168 clicking on a scrollbar belonging to scrolled window will inevitably move
169 the window. In wxWidgets, the scrollbar will only emit an event, send this
170 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
171 which actually moves the window and its subchildren. Note that GtkPizza
172 memorizes how much it has been scrolled but that wxWidgets forgets this
173 so that the two coordinates systems have to be kept in synch. This is done
174 in various places using the pizza->xoffset and pizza->yoffset values.
178 Singularily the most broken code in GTK is the code that is supposed to
179 inform subwindows (child windows) about new positions. Very often, duplicate
180 events are sent without changes in size or position, equally often no
181 events are sent at all (All this is due to a bug in the GtkContainer code
182 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
183 GTK's own system and it simply waits for size events for toplevel windows
184 and then iterates down the respective size events to all window. This has
185 the disadvantage that windows might get size events before the GTK widget
186 actually has the reported size. This doesn't normally pose any problem, but
187 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
188 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
189 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
190 window that is used for OpenGL output really has that size (as reported by
195 If someone at some point of time feels the immense desire to have a look at,
196 change or attempt to optimise the Refresh() logic, this person will need an
197 intimate understanding of what "draw" and "expose" events are and what
198 they are used for, in particular when used in connection with GTK's
199 own windowless widgets. Beware.
203 Cursors, too, have been a constant source of pleasure. The main difficulty
204 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
205 for the parent. To prevent this from doing too much harm, I use idle time
206 to set the cursor over and over again, starting from the toplevel windows
207 and ending with the youngest generation (speaking of parent and child windows).
208 Also don't forget that cursors (like much else) are connected to GdkWindows,
209 not GtkWidgets and that the "window" field of a GtkWidget might very well
210 point to the GdkWindow of the parent widget (-> "window-less widget") and
211 that the two obviously have very different meanings.
215 //-----------------------------------------------------------------------------
217 //-----------------------------------------------------------------------------
219 extern wxList wxPendingDelete
;
220 extern bool g_blockEventsOnDrag
;
221 extern bool g_blockEventsOnScroll
;
222 extern wxCursor g_globalCursor
;
224 static GdkGC
*g_eraseGC
= NULL
;
226 // mouse capture state: the window which has it and if the mouse is currently
228 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
229 static bool g_captureWindowHasMouse
= false;
231 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
233 // the last window which had the focus - this is normally never NULL (except
234 // if we never had focus at all) as even when g_focusWindow is NULL it still
235 // keeps its previous value
236 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
238 // If a window get the focus set but has not been realized
239 // yet, defer setting the focus to idle time.
240 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
242 extern bool g_mainThreadLocked
;
244 //-----------------------------------------------------------------------------
246 //-----------------------------------------------------------------------------
251 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
253 # define DEBUG_MAIN_THREAD
256 #define DEBUG_MAIN_THREAD
259 // the trace mask used for the focus debugging messages
260 #define TRACE_FOCUS _T("focus")
262 //-----------------------------------------------------------------------------
263 // missing gdk functions
264 //-----------------------------------------------------------------------------
267 gdk_window_warp_pointer (GdkWindow
*window
,
272 window
= gdk_get_default_root_window();
274 if (!GDK_WINDOW_DESTROYED(window
))
276 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
277 None
, /* not source window -> move from anywhere */
278 GDK_WINDOW_XID(window
), /* dest window */
279 0, 0, 0, 0, /* not source window -> move from anywhere */
284 //-----------------------------------------------------------------------------
285 // local code (see below)
286 //-----------------------------------------------------------------------------
288 // returns the child of win which currently has focus or NULL if not found
290 // Note: can't be static, needed by textctrl.cpp.
291 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
293 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
295 return (wxWindow
*)NULL
;
297 if ( winFocus
== win
)
298 return (wxWindow
*)win
;
300 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
302 node
= node
->GetNext() )
304 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
309 return (wxWindow
*)NULL
;
312 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
)
314 GtkScrolledWindow
* scroll_window
= GTK_SCROLLED_WINDOW(widget
);
315 GtkScrolledWindowClass
* scroll_class
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
));
316 GtkRequisition scroll_req
;
319 if (scroll_window
->vscrollbar_visible
)
321 scroll_req
.width
= 2;
322 scroll_req
.height
= 2;
323 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
324 (scroll_window
->vscrollbar
, &scroll_req
);
325 w
= scroll_req
.width
+
326 scroll_class
->scrollbar_spacing
;
330 if (scroll_window
->hscrollbar_visible
)
332 scroll_req
.width
= 2;
333 scroll_req
.height
= 2;
334 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
335 (scroll_window
->hscrollbar
, &scroll_req
);
336 h
= scroll_req
.height
+
337 scroll_class
->scrollbar_spacing
;
341 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
343 // wxUniversal widgets draw the borders and scrollbars themselves
344 #ifndef __WXUNIVERSAL__
351 if (win
->m_hasScrolling
)
353 GetScrollbarWidth(widget
, dw
, dh
);
358 if (GTK_WIDGET_NO_WINDOW (widget
))
360 dx
+= widget
->allocation
.x
;
361 dy
+= widget
->allocation
.y
;
364 if (win
->HasFlag(wxRAISED_BORDER
))
366 gtk_paint_shadow (widget
->style
,
370 NULL
, NULL
, NULL
, // FIXME: No clipping?
372 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
376 if (win
->HasFlag(wxSUNKEN_BORDER
))
378 gtk_paint_shadow (widget
->style
,
382 NULL
, NULL
, NULL
, // FIXME: No clipping?
384 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
388 if (win
->HasFlag(wxSIMPLE_BORDER
))
391 gc
= gdk_gc_new( widget
->window
);
392 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
393 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
395 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
396 g_object_unref (G_OBJECT (gc
));
399 #endif // __WXUNIVERSAL__
402 //-----------------------------------------------------------------------------
403 // "expose_event" of m_widget
404 //-----------------------------------------------------------------------------
408 gtk_window_own_expose_callback( GtkWidget
*widget
,
409 GdkEventExpose
*gdk_event
,
412 if (gdk_event
->count
> 0) return FALSE
;
414 draw_frame( widget
, win
);
416 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
422 //-----------------------------------------------------------------------------
423 // "size_request" of m_widget
424 //-----------------------------------------------------------------------------
426 // make it extern because wxStaticText needs to disconnect this one
428 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
429 GtkRequisition
*requisition
,
433 win
->GetSize( &w
, &h
);
439 requisition
->height
= h
;
440 requisition
->width
= w
;
446 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
447 GtkRequisition
*requisition
,
450 // This callback is actually hooked into the text entry
451 // of the combo box, not the GtkHBox.
454 win
->GetSize( &w
, &h
);
460 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
462 GtkRequisition entry_req
;
464 entry_req
.height
= 2;
465 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
466 (gcombo
->button
, &entry_req
);
468 requisition
->width
= w
- entry_req
.width
;
469 requisition
->height
= entry_req
.height
;
473 //-----------------------------------------------------------------------------
474 // "expose_event" of m_wxwindow
475 //-----------------------------------------------------------------------------
479 gtk_window_expose_callback( GtkWidget
*widget
,
480 GdkEventExpose
*gdk_event
,
486 wxapp_install_idle_handler();
488 // This callback gets called in drawing-idle time under
489 // GTK 2.0, so we don't need to defer anything to idle
492 GtkPizza
*pizza
= GTK_PIZZA( widget
);
493 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
498 wxPrintf( wxT("OnExpose from ") );
499 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
500 wxPrintf( win
->GetClassInfo()->GetClassName() );
501 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
502 (int)gdk_event
->area
.y
,
503 (int)gdk_event
->area
.width
,
504 (int)gdk_event
->area
.height
);
509 win
->m_wxwindow
->style
,
513 (GdkRectangle
*) NULL
,
515 (char *)"button", // const_cast
520 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
522 win
->GtkSendPaintEvents();
525 // Let parent window draw window-less widgets
526 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
532 //-----------------------------------------------------------------------------
533 // "key_press_event" from any window
534 //-----------------------------------------------------------------------------
536 // set WXTRACE to this to see the key event codes on the console
537 #define TRACE_KEYS _T("keyevent")
539 // translates an X key symbol to WXK_XXX value
541 // if isChar is true it means that the value returned will be used for EVT_CHAR
542 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
543 // for example, while if it is false it means that the value is going to be
544 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
546 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
552 // Shift, Control and Alt don't generate the CHAR events at all
555 key_code
= isChar
? 0 : WXK_SHIFT
;
559 key_code
= isChar
? 0 : WXK_CONTROL
;
567 key_code
= isChar
? 0 : WXK_ALT
;
570 // neither do the toggle modifies
571 case GDK_Scroll_Lock
:
572 key_code
= isChar
? 0 : WXK_SCROLL
;
576 key_code
= isChar
? 0 : WXK_CAPITAL
;
580 key_code
= isChar
? 0 : WXK_NUMLOCK
;
584 // various other special keys
597 case GDK_ISO_Left_Tab
:
604 key_code
= WXK_RETURN
;
608 key_code
= WXK_CLEAR
;
612 key_code
= WXK_PAUSE
;
616 key_code
= WXK_SELECT
;
620 key_code
= WXK_PRINT
;
624 key_code
= WXK_EXECUTE
;
628 key_code
= WXK_ESCAPE
;
631 // cursor and other extended keyboard keys
633 key_code
= WXK_DELETE
;
649 key_code
= WXK_RIGHT
;
656 case GDK_Prior
: // == GDK_Page_Up
657 key_code
= WXK_PAGEUP
;
660 case GDK_Next
: // == GDK_Page_Down
661 key_code
= WXK_PAGEDOWN
;
673 key_code
= WXK_INSERT
;
688 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
692 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
696 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
700 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
704 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
708 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
712 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
716 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
720 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
724 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
728 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
732 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
736 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
739 case GDK_KP_Prior
: // == GDK_KP_Page_Up
740 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
743 case GDK_KP_Next
: // == GDK_KP_Page_Down
744 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
748 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
752 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
756 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
760 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
764 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
767 case GDK_KP_Multiply
:
768 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
772 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
775 case GDK_KP_Separator
:
776 // FIXME: what is this?
777 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
780 case GDK_KP_Subtract
:
781 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
785 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
789 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
806 key_code
= WXK_F1
+ keysym
- GDK_F1
;
816 static inline bool wxIsAsciiKeysym(KeySym ks
)
821 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
823 GdkEventKey
*gdk_event
)
827 GdkModifierType state
;
828 if (gdk_event
->window
)
829 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
831 event
.SetTimestamp( gdk_event
->time
);
832 event
.SetId(win
->GetId());
833 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
834 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
835 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
836 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
837 event
.m_scanCode
= gdk_event
->keyval
;
838 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
839 event
.m_rawFlags
= 0;
841 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
843 wxGetMousePosition( &x
, &y
);
844 win
->ScreenToClient( &x
, &y
);
847 event
.SetEventObject( win
);
852 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
854 GdkEventKey
*gdk_event
)
856 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
857 // but only event->keyval which is quite useless to us, so remember
858 // the last character from GDK_KEY_PRESS and reuse it as last resort
860 // NB: should be MT-safe as we're always called from the main thread only
865 } s_lastKeyPress
= { 0, 0 };
867 KeySym keysym
= gdk_event
->keyval
;
869 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
870 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
874 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
878 // do we have the translation or is it a plain ASCII character?
879 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
881 // we should use keysym if it is ASCII as X does some translations
882 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
883 // which we don't want here (but which we do use for OnChar())
884 if ( !wxIsAsciiKeysym(keysym
) )
886 keysym
= (KeySym
)gdk_event
->string
[0];
889 // we want to always get the same key code when the same key is
890 // pressed regardless of the state of the modifiers, i.e. on a
891 // standard US keyboard pressing '5' or '%' ('5' key with
892 // Shift) should result in the same key code in OnKeyDown():
893 // '5' (although OnChar() will get either '5' or '%').
895 // to do it we first translate keysym to keycode (== scan code)
896 // and then back but always using the lower register
897 Display
*dpy
= (Display
*)wxGetDisplay();
898 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
900 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
902 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
904 // use the normalized, i.e. lower register, keysym if we've
906 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
908 // as explained above, we want to have lower register key codes
909 // normally but for the letter keys we want to have the upper ones
911 // NB: don't use XConvertCase() here, we want to do it for letters
913 key_code
= toupper(key_code
);
915 else // non ASCII key, what to do?
917 // by default, ignore it
920 // but if we have cached information from the last KEY_PRESS
921 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
924 if ( keysym
== s_lastKeyPress
.keysym
)
926 key_code
= s_lastKeyPress
.keycode
;
931 if ( gdk_event
->type
== GDK_KEY_PRESS
)
933 // remember it to be reused for KEY_UP event later
934 s_lastKeyPress
.keysym
= keysym
;
935 s_lastKeyPress
.keycode
= key_code
;
939 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
941 // sending unknown key events doesn't really make sense
945 // now fill all the other fields
946 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
948 event
.m_keyCode
= key_code
;
950 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
952 event
.m_uniChar
= key_code
;
962 GtkIMContext
*context
;
963 GdkEventKey
*lastKeyEvent
;
967 context
= gtk_im_multicontext_new();
972 g_object_unref(context
);
978 gtk_window_key_press_callback( GtkWidget
*widget
,
979 GdkEventKey
*gdk_event
,
985 wxapp_install_idle_handler();
989 if (g_blockEventsOnDrag
)
993 wxKeyEvent
event( wxEVT_KEY_DOWN
);
995 bool return_after_IM
= false;
997 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
999 // Emit KEY_DOWN event
1000 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1004 // Return after IM processing as we cannot do
1005 // anything with it anyhow.
1006 return_after_IM
= true;
1009 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1010 // When we get a key_press event here, it could be originate
1011 // from the current widget or its child widgets. However, only the widget
1012 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1013 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1014 // originated from its child widgets and shouldn't be passed to IM context.
1015 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1016 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1017 // widgets has both IM context and input focus, the event should be filtered
1018 // by gtk_im_context_filter_keypress().
1019 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1020 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1022 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1023 // docs, if IM filter returns true, no further processing should be done.
1024 // we should send the key_down event anyway.
1025 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1026 win
->m_imData
->lastKeyEvent
= NULL
;
1027 if (intercepted_by_IM
)
1029 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1034 if (return_after_IM
)
1040 wxWindowGTK
*ancestor
= win
;
1043 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1046 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1047 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1050 if (ancestor
->IsTopLevel())
1052 ancestor
= ancestor
->GetParent();
1055 #endif // wxUSE_ACCEL
1057 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1058 // will only be sent if it is not in an accelerator table.
1062 KeySym keysym
= gdk_event
->keyval
;
1063 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1064 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1067 if ( wxIsAsciiKeysym(keysym
) )
1070 key_code
= (unsigned char)keysym
;
1072 // gdk_event->string is actually deprecated
1073 else if ( gdk_event
->length
== 1 )
1075 key_code
= (unsigned char)gdk_event
->string
[0];
1081 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1083 event
.m_keyCode
= key_code
;
1085 // To conform to the docs we need to translate Ctrl-alpha
1086 // characters to values in the range 1-26.
1087 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1089 event
.m_keyCode
= key_code
- 'a' + 1;
1091 event
.m_uniChar
= event
.m_keyCode
;
1095 // Implement OnCharHook by checking ancestor top level windows
1096 wxWindow
*parent
= win
;
1097 while (parent
&& !parent
->IsTopLevel())
1098 parent
= parent
->GetParent();
1101 event
.SetEventType( wxEVT_CHAR_HOOK
);
1102 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1107 event
.SetEventType(wxEVT_CHAR
);
1108 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1117 // win is a control: tab can be propagated up
1119 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1120 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1121 // have this style, yet choose not to process this particular TAB in which
1122 // case TAB must still work as a navigational character
1123 // JS: enabling again to make consistent with other platforms
1124 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1125 // navigation behaviour)
1127 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1129 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1131 wxNavigationKeyEvent new_event
;
1132 new_event
.SetEventObject( win
->GetParent() );
1133 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1134 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1135 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1136 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1137 new_event
.SetCurrentFocus( win
);
1138 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1141 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1143 (gdk_event
->keyval
== GDK_Escape
) )
1145 // however only do it if we have a Cancel button in the dialog,
1146 // otherwise the user code may get confused by the events from a
1147 // non-existing button and, worse, a wxButton might get button event
1148 // from another button which is not really expected
1149 wxWindow
*winForCancel
= win
,
1151 while ( winForCancel
)
1153 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1156 // found a cancel button
1160 if ( winForCancel
->IsTopLevel() )
1162 // no need to look further
1166 // maybe our parent has a cancel button?
1167 winForCancel
= winForCancel
->GetParent();
1172 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1173 eventClick
.SetEventObject(btnCancel
);
1174 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1180 g_signal_stop_emission_by_name (widget
, "key_press_event");
1190 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1194 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1196 // take modifiers, cursor position, timestamp etc. from the last
1197 // key_press_event that was fed into Input Method:
1198 if (window
->m_imData
->lastKeyEvent
)
1200 wxFillOtherKeyEventFields(event
,
1201 window
, window
->m_imData
->lastKeyEvent
);
1204 const wxWxCharBuffer
data(wxGTK_CONV_BACK(str
));
1210 // Implement OnCharHook by checking ancestor top level windows
1211 wxWindow
*parent
= window
;
1212 while (parent
&& !parent
->IsTopLevel())
1213 parent
= parent
->GetParent();
1215 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1218 event
.m_uniChar
= *pstr
;
1219 // Backward compatible for ISO-8859-1
1220 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1221 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1223 event
.m_keyCode
= *pstr
;
1224 #endif // wxUSE_UNICODE
1226 // To conform to the docs we need to translate Ctrl-alpha
1227 // characters to values in the range 1-26.
1228 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1230 event
.m_keyCode
= *pstr
- 'a' + 1;
1232 event
.m_uniChar
= event
.m_keyCode
;
1238 event
.SetEventType( wxEVT_CHAR_HOOK
);
1239 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1244 event
.SetEventType(wxEVT_CHAR
);
1245 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1252 //-----------------------------------------------------------------------------
1253 // "key_release_event" from any window
1254 //-----------------------------------------------------------------------------
1258 gtk_window_key_release_callback( GtkWidget
*widget
,
1259 GdkEventKey
*gdk_event
,
1265 wxapp_install_idle_handler();
1270 if (g_blockEventsOnDrag
)
1273 wxKeyEvent
event( wxEVT_KEY_UP
);
1274 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1276 // unknown key pressed, ignore (the event would be useless anyhow)
1280 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1283 g_signal_stop_emission_by_name (widget
, "key_release_event");
1288 // ============================================================================
1290 // ============================================================================
1292 // ----------------------------------------------------------------------------
1293 // mouse event processing helpers
1294 // ----------------------------------------------------------------------------
1296 // init wxMouseEvent with the info from GdkEventXXX struct
1297 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1298 wxMouseEvent
& event
,
1301 event
.SetTimestamp( gdk_event
->time
);
1302 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1303 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1304 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1305 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1306 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1307 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1308 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1309 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1311 event
.m_linesPerAction
= 3;
1312 event
.m_wheelDelta
= 120;
1313 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1314 event
.m_wheelRotation
= 120;
1315 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1316 event
.m_wheelRotation
= -120;
1319 wxPoint pt
= win
->GetClientAreaOrigin();
1320 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1321 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1323 event
.SetEventObject( win
);
1324 event
.SetId( win
->GetId() );
1325 event
.SetTimestamp( gdk_event
->time
);
1328 static void AdjustEventButtonState(wxMouseEvent
& event
)
1330 // GDK reports the old state of the button for a button press event, but
1331 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1332 // for a LEFT_DOWN event, not FALSE, so we will invert
1333 // left/right/middleDown for the corresponding click events
1335 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1336 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1337 (event
.GetEventType() == wxEVT_LEFT_UP
))
1339 event
.m_leftDown
= !event
.m_leftDown
;
1343 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1344 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1345 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1347 event
.m_middleDown
= !event
.m_middleDown
;
1351 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1352 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1353 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1355 event
.m_rightDown
= !event
.m_rightDown
;
1360 // find the window to send the mouse event too
1362 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1367 if (win
->m_wxwindow
)
1369 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1370 xx
+= pizza
->xoffset
;
1371 yy
+= pizza
->yoffset
;
1374 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1377 wxWindowGTK
*child
= node
->GetData();
1379 node
= node
->GetNext();
1380 if (!child
->IsShown())
1383 if (child
->IsTransparentForMouse())
1385 // wxStaticBox is transparent in the box itself
1386 int xx1
= child
->m_x
;
1387 int yy1
= child
->m_y
;
1388 int xx2
= child
->m_x
+ child
->m_width
;
1389 int yy2
= child
->m_y
+ child
->m_height
;
1392 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1394 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1396 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1398 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1409 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1410 (child
->m_x
<= xx
) &&
1411 (child
->m_y
<= yy
) &&
1412 (child
->m_x
+child
->m_width
>= xx
) &&
1413 (child
->m_y
+child
->m_height
>= yy
))
1426 //-----------------------------------------------------------------------------
1427 // "button_press_event"
1428 //-----------------------------------------------------------------------------
1432 gtk_window_button_press_callback( GtkWidget
*widget
,
1433 GdkEventButton
*gdk_event
,
1439 wxapp_install_idle_handler();
1442 wxPrintf( wxT("1) OnButtonPress from ") );
1443 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1444 wxPrintf( win->GetClassInfo()->GetClassName() );
1445 wxPrintf( wxT(".\n") );
1447 if (!win
->m_hasVMT
) return FALSE
;
1448 if (g_blockEventsOnDrag
) return TRUE
;
1449 if (g_blockEventsOnScroll
) return TRUE
;
1451 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1453 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1455 gtk_widget_grab_focus( win
->m_wxwindow
);
1457 wxPrintf( wxT("GrabFocus from ") );
1458 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1459 wxPrintf( win->GetClassInfo()->GetClassName() );
1460 wxPrintf( wxT(".\n") );
1464 // GDK sends surplus button down events
1465 // before a double click event. We
1466 // need to filter these out.
1467 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1469 GdkEvent
*peek_event
= gdk_event_peek();
1472 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1473 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1475 gdk_event_free( peek_event
);
1480 gdk_event_free( peek_event
);
1485 wxEventType event_type
= wxEVT_NULL
;
1487 // GdkDisplay is a GTK+ 2.2.0 thing
1488 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1489 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1490 !gtk_check_version(2,2,0) &&
1491 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1493 // Reset GDK internal timestamp variables in order to disable GDK
1494 // triple click events. GDK will then next time believe no button has
1495 // been clicked just before, and send a normal button click event.
1496 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1497 display
->button_click_time
[1] = 0;
1498 display
->button_click_time
[0] = 0;
1502 if (gdk_event
->button
== 1)
1504 // note that GDK generates triple click events which are not supported
1505 // by wxWidgets but still have to be passed to the app as otherwise
1506 // clicks would simply go missing
1507 switch (gdk_event
->type
)
1509 // we shouldn't get triple clicks at all for GTK2 because we
1510 // suppress them artificially using the code above but we still
1511 // should map them to something for GTK1 and not just ignore them
1512 // as this would lose clicks
1513 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1514 case GDK_BUTTON_PRESS
:
1515 event_type
= wxEVT_LEFT_DOWN
;
1518 case GDK_2BUTTON_PRESS
:
1519 event_type
= wxEVT_LEFT_DCLICK
;
1523 // just to silence gcc warnings
1527 else if (gdk_event
->button
== 2)
1529 switch (gdk_event
->type
)
1531 case GDK_3BUTTON_PRESS
:
1532 case GDK_BUTTON_PRESS
:
1533 event_type
= wxEVT_MIDDLE_DOWN
;
1536 case GDK_2BUTTON_PRESS
:
1537 event_type
= wxEVT_MIDDLE_DCLICK
;
1544 else if (gdk_event
->button
== 3)
1546 switch (gdk_event
->type
)
1548 case GDK_3BUTTON_PRESS
:
1549 case GDK_BUTTON_PRESS
:
1550 event_type
= wxEVT_RIGHT_DOWN
;
1553 case GDK_2BUTTON_PRESS
:
1554 event_type
= wxEVT_RIGHT_DCLICK
;
1561 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1563 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1565 event_type
= wxEVT_MOUSEWHEEL
;
1569 if ( event_type
== wxEVT_NULL
)
1571 // unknown mouse button or click type
1575 wxMouseEvent
event( event_type
);
1576 InitMouseEvent( win
, event
, gdk_event
);
1578 AdjustEventButtonState(event
);
1580 // wxListBox actually gets mouse events from the item, so we need to give it
1581 // a chance to correct this
1582 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1584 // find the correct window to send the event to: it may be a different one
1585 // from the one which got it at GTK+ level because some controls don't have
1586 // their own X window and thus cannot get any events.
1587 if ( !g_captureWindow
)
1588 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1590 if (win
->GetEventHandler()->ProcessEvent( event
))
1592 g_signal_stop_emission_by_name (widget
, "button_press_event");
1596 if (event_type
== wxEVT_RIGHT_DOWN
)
1598 // generate a "context menu" event: this is similar to right mouse
1599 // click under many GUIs except that it is generated differently
1600 // (right up under MSW, ctrl-click under Mac, right down here) and
1602 // (a) it's a command event and so is propagated to the parent
1603 // (b) under some ports it can be generated from kbd too
1604 // (c) it uses screen coords (because of (a))
1605 wxContextMenuEvent
evtCtx(
1608 win
->ClientToScreen(event
.GetPosition()));
1609 evtCtx
.SetEventObject(win
);
1610 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1617 //-----------------------------------------------------------------------------
1618 // "button_release_event"
1619 //-----------------------------------------------------------------------------
1623 gtk_window_button_release_callback( GtkWidget
*widget
,
1624 GdkEventButton
*gdk_event
,
1630 wxapp_install_idle_handler();
1632 if (!win
->m_hasVMT
) return FALSE
;
1633 if (g_blockEventsOnDrag
) return FALSE
;
1634 if (g_blockEventsOnScroll
) return FALSE
;
1636 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1638 wxEventType event_type
= wxEVT_NULL
;
1640 switch (gdk_event
->button
)
1643 event_type
= wxEVT_LEFT_UP
;
1647 event_type
= wxEVT_MIDDLE_UP
;
1651 event_type
= wxEVT_RIGHT_UP
;
1655 // unknwon button, don't process
1659 wxMouseEvent
event( event_type
);
1660 InitMouseEvent( win
, event
, gdk_event
);
1662 AdjustEventButtonState(event
);
1664 // same wxListBox hack as above
1665 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1667 if ( !g_captureWindow
)
1668 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1670 if (win
->GetEventHandler()->ProcessEvent( event
))
1672 g_signal_stop_emission_by_name (widget
, "button_release_event");
1680 //-----------------------------------------------------------------------------
1681 // "motion_notify_event"
1682 //-----------------------------------------------------------------------------
1686 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1687 GdkEventMotion
*gdk_event
,
1693 wxapp_install_idle_handler();
1695 if (!win
->m_hasVMT
) return FALSE
;
1696 if (g_blockEventsOnDrag
) return FALSE
;
1697 if (g_blockEventsOnScroll
) return FALSE
;
1699 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1701 if (gdk_event
->is_hint
)
1705 GdkModifierType state
;
1706 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1712 printf( "OnMotion from " );
1713 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1714 printf( win->GetClassInfo()->GetClassName() );
1718 wxMouseEvent
event( wxEVT_MOTION
);
1719 InitMouseEvent(win
, event
, gdk_event
);
1721 if ( g_captureWindow
)
1723 // synthetize a mouse enter or leave event if needed
1724 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1725 // This seems to be necessary and actually been added to
1726 // GDK itself in version 2.0.X
1729 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1730 if ( hasMouse
!= g_captureWindowHasMouse
)
1732 // the mouse changed window
1733 g_captureWindowHasMouse
= hasMouse
;
1735 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1736 : wxEVT_LEAVE_WINDOW
);
1737 InitMouseEvent(win
, eventM
, gdk_event
);
1738 eventM
.SetEventObject(win
);
1739 win
->GetEventHandler()->ProcessEvent(eventM
);
1744 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1747 if ( !g_captureWindow
)
1749 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1750 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1752 // Rewrite cursor handling here (away from idle).
1756 if (win
->GetEventHandler()->ProcessEvent( event
))
1758 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1766 //-----------------------------------------------------------------------------
1767 // "mouse_wheel_event"
1768 //-----------------------------------------------------------------------------
1772 gtk_window_wheel_callback (GtkWidget
* widget
,
1773 GdkEventScroll
* gdk_event
,
1779 wxapp_install_idle_handler();
1781 wxEventType event_type
= wxEVT_NULL
;
1782 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1783 event_type
= wxEVT_MOUSEWHEEL
;
1784 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1785 event_type
= wxEVT_MOUSEWHEEL
;
1789 wxMouseEvent
event( event_type
);
1790 // Can't use InitMouse macro because scroll events don't have button
1791 event
.SetTimestamp( gdk_event
->time
);
1792 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1793 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1794 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1795 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1796 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1797 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1798 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1799 event
.m_linesPerAction
= 3;
1800 event
.m_wheelDelta
= 120;
1801 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1802 event
.m_wheelRotation
= 120;
1804 event
.m_wheelRotation
= -120;
1806 wxPoint pt
= win
->GetClientAreaOrigin();
1807 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1808 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1810 event
.SetEventObject( win
);
1811 event
.SetId( win
->GetId() );
1812 event
.SetTimestamp( gdk_event
->time
);
1814 if (win
->GetEventHandler()->ProcessEvent( event
))
1816 g_signal_stop_emission_by_name (widget
, "scroll_event");
1824 //-----------------------------------------------------------------------------
1826 //-----------------------------------------------------------------------------
1828 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1830 wxContextMenuEvent
event(
1834 event
.SetEventObject(win
);
1835 return win
->GetEventHandler()->ProcessEvent(event
);
1839 //-----------------------------------------------------------------------------
1841 //-----------------------------------------------------------------------------
1843 // send the wxChildFocusEvent and wxFocusEvent, common code of
1844 // gtk_window_focus_in_callback() and SetFocus()
1845 static bool DoSendFocusEvents(wxWindow
*win
)
1847 // Notify the parent keeping track of focus for the kbd navigation
1848 // purposes that we got it.
1849 wxChildFocusEvent
eventChildFocus(win
);
1850 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1852 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1853 eventFocus
.SetEventObject(win
);
1855 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1860 gtk_window_focus_in_callback( GtkWidget
*widget
,
1861 GdkEventFocus
*WXUNUSED(event
),
1867 wxapp_install_idle_handler();
1870 gtk_im_context_focus_in(win
->m_imData
->context
);
1873 g_focusWindow
= win
;
1875 wxLogTrace(TRACE_FOCUS
,
1876 _T("%s: focus in"), win
->GetName().c_str());
1880 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1884 // caret needs to be informed about focus change
1885 wxCaret
*caret
= win
->GetCaret();
1888 caret
->OnSetFocus();
1890 #endif // wxUSE_CARET
1892 gboolean ret
= FALSE
;
1894 // does the window itself think that it has the focus?
1895 if ( !win
->m_hasFocus
)
1897 // not yet, notify it
1898 win
->m_hasFocus
= true;
1900 (void)DoSendFocusEvents(win
);
1905 // Disable default focus handling for custom windows
1906 // since the default GTK+ handler issues a repaint
1907 if (win
->m_wxwindow
)
1914 //-----------------------------------------------------------------------------
1915 // "focus_out_event"
1916 //-----------------------------------------------------------------------------
1920 gtk_window_focus_out_callback( GtkWidget
*widget
,
1921 GdkEventFocus
*gdk_event
,
1927 wxapp_install_idle_handler();
1930 gtk_im_context_focus_out(win
->m_imData
->context
);
1932 wxLogTrace( TRACE_FOCUS
,
1933 _T("%s: focus out"), win
->GetName().c_str() );
1936 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1940 g_focusWindow
= (wxWindowGTK
*)NULL
;
1948 // caret needs to be informed about focus change
1949 wxCaret
*caret
= win
->GetCaret();
1952 caret
->OnKillFocus();
1954 #endif // wxUSE_CARET
1956 gboolean ret
= FALSE
;
1958 // don't send the window a kill focus event if it thinks that it doesn't
1959 // have focus already
1960 if ( win
->m_hasFocus
)
1962 win
->m_hasFocus
= false;
1964 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1965 event
.SetEventObject( win
);
1967 (void)win
->GetEventHandler()->ProcessEvent( event
);
1972 // Disable default focus handling for custom windows
1973 // since the default GTK+ handler issues a repaint
1974 if (win
->m_wxwindow
)
1981 //-----------------------------------------------------------------------------
1982 // "enter_notify_event"
1983 //-----------------------------------------------------------------------------
1987 gtk_window_enter_callback( GtkWidget
*widget
,
1988 GdkEventCrossing
*gdk_event
,
1994 wxapp_install_idle_handler();
1996 if (!win
->m_hasVMT
) return FALSE
;
1997 if (g_blockEventsOnDrag
) return FALSE
;
1999 // Event was emitted after a grab
2000 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2002 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2006 GdkModifierType state
= (GdkModifierType
)0;
2008 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2010 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2011 InitMouseEvent(win
, event
, gdk_event
);
2012 wxPoint pt
= win
->GetClientAreaOrigin();
2013 event
.m_x
= x
+ pt
.x
;
2014 event
.m_y
= y
+ pt
.y
;
2016 if ( !g_captureWindow
)
2018 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2019 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2021 // Rewrite cursor handling here (away from idle).
2025 if (win
->GetEventHandler()->ProcessEvent( event
))
2027 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2035 //-----------------------------------------------------------------------------
2036 // "leave_notify_event"
2037 //-----------------------------------------------------------------------------
2041 gtk_window_leave_callback( GtkWidget
*widget
,
2042 GdkEventCrossing
*gdk_event
,
2048 wxapp_install_idle_handler();
2050 if (!win
->m_hasVMT
) return FALSE
;
2051 if (g_blockEventsOnDrag
) return FALSE
;
2053 // Event was emitted after an ungrab
2054 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2056 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2058 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2059 event
.SetTimestamp( gdk_event
->time
);
2060 event
.SetEventObject( win
);
2064 GdkModifierType state
= (GdkModifierType
)0;
2066 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2068 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2069 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2070 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2071 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2072 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2073 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2074 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2076 wxPoint pt
= win
->GetClientAreaOrigin();
2077 event
.m_x
= x
+ pt
.x
;
2078 event
.m_y
= y
+ pt
.y
;
2080 if (win
->GetEventHandler()->ProcessEvent( event
))
2082 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2090 //-----------------------------------------------------------------------------
2091 // "value_changed" from m_vAdjust
2092 //-----------------------------------------------------------------------------
2095 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2101 wxapp_install_idle_handler();
2103 if (g_blockEventsOnDrag
) return;
2105 if (!win
->m_hasVMT
) return;
2107 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2108 if (fabs(diff
) < 0.2) return;
2110 win
->m_oldVerticalPos
= adjust
->value
;
2112 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2114 int value
= (int)(adjust
->value
+0.5);
2116 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2117 event
.SetEventObject( win
);
2118 win
->GetEventHandler()->ProcessEvent( event
);
2122 //-----------------------------------------------------------------------------
2123 // "value_changed" from m_hAdjust
2124 //-----------------------------------------------------------------------------
2127 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2133 wxapp_install_idle_handler();
2135 if (g_blockEventsOnDrag
) return;
2136 if (!win
->m_hasVMT
) return;
2138 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2139 if (fabs(diff
) < 0.2) return;
2141 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2143 win
->m_oldHorizontalPos
= adjust
->value
;
2145 int value
= (int)(adjust
->value
+0.5);
2147 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2148 event
.SetEventObject( win
);
2149 win
->GetEventHandler()->ProcessEvent( event
);
2153 //-----------------------------------------------------------------------------
2154 // "button_press_event" from scrollbar
2155 //-----------------------------------------------------------------------------
2159 gtk_scrollbar_button_press_callback( GtkWidget
*widget
,
2160 GdkEventButton
*gdk_event
,
2166 wxapp_install_idle_handler();
2169 g_blockEventsOnScroll
= true;
2171 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2173 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2180 //-----------------------------------------------------------------------------
2181 // "button_release_event" from scrollbar
2182 //-----------------------------------------------------------------------------
2186 gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2187 GdkEventButton
*WXUNUSED(gdk_event
),
2192 // don't test here as we can release the mouse while being over
2193 // a different window than the slider
2195 // if (gdk_event->window != widget->slider) return FALSE;
2197 g_blockEventsOnScroll
= false;
2199 if (win
->m_isScrolling
)
2201 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2205 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2206 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2208 value
= (int)(win
->m_hAdjust
->value
+0.5);
2211 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2213 value
= (int)(win
->m_vAdjust
->value
+0.5);
2217 wxScrollWinEvent
event( command
, value
, dir
);
2218 event
.SetEventObject( win
);
2219 win
->GetEventHandler()->ProcessEvent( event
);
2222 win
->m_isScrolling
= false;
2228 // ----------------------------------------------------------------------------
2229 // this wxWindowBase function is implemented here (in platform-specific file)
2230 // because it is static and so couldn't be made virtual
2231 // ----------------------------------------------------------------------------
2233 wxWindow
*wxWindowBase::DoFindFocus()
2235 // the cast is necessary when we compile in wxUniversal mode
2236 return (wxWindow
*)g_focusWindow
;
2239 //-----------------------------------------------------------------------------
2240 // "realize" from m_widget
2241 //-----------------------------------------------------------------------------
2243 /* We cannot set colours and fonts before the widget has
2244 been realized, so we do this directly after realization. */
2248 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2253 wxapp_install_idle_handler();
2257 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2258 gtk_im_context_set_client_window( win
->m_imData
->context
,
2259 pizza
->bin_window
);
2262 wxWindowCreateEvent
event( win
);
2263 event
.SetEventObject( win
);
2264 win
->GetEventHandler()->ProcessEvent( event
);
2268 //-----------------------------------------------------------------------------
2270 //-----------------------------------------------------------------------------
2274 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2275 GtkAllocation
*WXUNUSED(alloc
),
2279 wxapp_install_idle_handler();
2281 if (!win
->m_hasScrolling
) return;
2283 int client_width
= 0;
2284 int client_height
= 0;
2285 win
->GetClientSize( &client_width
, &client_height
);
2286 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2289 win
->m_oldClientWidth
= client_width
;
2290 win
->m_oldClientHeight
= client_height
;
2292 if (!win
->m_nativeSizeEvent
)
2294 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2295 event
.SetEventObject( win
);
2296 win
->GetEventHandler()->ProcessEvent( event
);
2303 #define WXUNUSED_UNLESS_XIM(param) param
2305 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2308 /* Resize XIM window */
2312 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2313 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2314 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2317 wxapp_install_idle_handler();
2323 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2327 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2328 win
->m_icattr
->preedit_area
.width
= width
;
2329 win
->m_icattr
->preedit_area
.height
= height
;
2330 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2336 //-----------------------------------------------------------------------------
2337 // "realize" from m_wxwindow
2338 //-----------------------------------------------------------------------------
2340 /* Initialize XIM support */
2344 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2345 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2348 wxapp_install_idle_handler();
2351 if (win
->m_ic
) return;
2352 if (!widget
) return;
2353 if (!gdk_im_ready()) return;
2355 win
->m_icattr
= gdk_ic_attr_new();
2356 if (!win
->m_icattr
) return;
2360 GdkColormap
*colormap
;
2361 GdkICAttr
*attr
= win
->m_icattr
;
2362 unsigned attrmask
= GDK_IC_ALL_REQ
;
2364 GdkIMStyle supported_style
= (GdkIMStyle
)
2365 (GDK_IM_PREEDIT_NONE
|
2366 GDK_IM_PREEDIT_NOTHING
|
2367 GDK_IM_PREEDIT_POSITION
|
2368 GDK_IM_STATUS_NONE
|
2369 GDK_IM_STATUS_NOTHING
);
2371 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2372 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2374 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2375 attr
->client_window
= widget
->window
;
2377 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2378 gtk_widget_get_default_colormap ())
2380 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2381 attr
->preedit_colormap
= colormap
;
2384 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2385 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2386 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2387 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2389 switch (style
& GDK_IM_PREEDIT_MASK
)
2391 case GDK_IM_PREEDIT_POSITION
:
2392 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2394 g_warning ("over-the-spot style requires fontset");
2398 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2400 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2401 attr
->spot_location
.x
= 0;
2402 attr
->spot_location
.y
= height
;
2403 attr
->preedit_area
.x
= 0;
2404 attr
->preedit_area
.y
= 0;
2405 attr
->preedit_area
.width
= width
;
2406 attr
->preedit_area
.height
= height
;
2407 attr
->preedit_fontset
= widget
->style
->font
;
2412 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2414 if (win
->m_ic
== NULL
)
2415 g_warning ("Can't create input context.");
2418 mask
= gdk_window_get_events (widget
->window
);
2419 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2420 gdk_window_set_events (widget
->window
, mask
);
2422 if (GTK_WIDGET_HAS_FOCUS(widget
))
2423 gdk_im_begin (win
->m_ic
, widget
->window
);
2429 //-----------------------------------------------------------------------------
2430 // InsertChild for wxWindowGTK.
2431 //-----------------------------------------------------------------------------
2433 /* Callback for wxWindowGTK. This very strange beast has to be used because
2434 * C++ has no virtual methods in a constructor. We have to emulate a
2435 * virtual function here as wxNotebook requires a different way to insert
2436 * a child in it. I had opted for creating a wxNotebookPage window class
2437 * which would have made this superfluous (such in the MDI window system),
2438 * but no-one was listening to me... */
2440 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2442 /* the window might have been scrolled already, do we
2443 have to adapt the position */
2444 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2445 child
->m_x
+= pizza
->xoffset
;
2446 child
->m_y
+= pizza
->yoffset
;
2448 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2449 GTK_WIDGET(child
->m_widget
),
2456 //-----------------------------------------------------------------------------
2458 //-----------------------------------------------------------------------------
2460 wxWindow
*wxGetActiveWindow()
2462 return wxWindow::FindFocus();
2466 wxMouseState
wxGetMouseState()
2472 GdkModifierType mask
;
2474 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2478 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2479 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2480 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2482 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2483 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2484 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2485 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2490 //-----------------------------------------------------------------------------
2492 //-----------------------------------------------------------------------------
2494 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2496 #ifdef __WXUNIVERSAL__
2497 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2499 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2500 #endif // __WXUNIVERSAL__/__WXGTK__
2502 void wxWindowGTK::Init()
2505 m_widget
= (GtkWidget
*) NULL
;
2506 m_wxwindow
= (GtkWidget
*) NULL
;
2507 m_focusWidget
= (GtkWidget
*) NULL
;
2517 m_needParent
= true;
2518 m_isBeingDeleted
= false;
2521 m_nativeSizeEvent
= false;
2523 m_hasScrolling
= false;
2524 m_isScrolling
= false;
2526 m_hAdjust
= (GtkAdjustment
*) NULL
;
2527 m_vAdjust
= (GtkAdjustment
*) NULL
;
2528 m_oldHorizontalPos
=
2529 m_oldVerticalPos
= 0.0;
2531 m_oldClientHeight
= 0;
2535 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2537 m_acceptsFocus
= false;
2540 m_clipPaintRegion
= false;
2542 m_needsStyleChange
= false;
2544 m_cursor
= *wxSTANDARD_CURSOR
;
2547 m_dirtyTabOrder
= false;
2550 wxWindowGTK::wxWindowGTK()
2555 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2560 const wxString
&name
)
2564 Create( parent
, id
, pos
, size
, style
, name
);
2567 bool wxWindowGTK::Create( wxWindow
*parent
,
2572 const wxString
&name
)
2574 if (!PreCreation( parent
, pos
, size
) ||
2575 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2577 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2581 m_insertCallback
= wxInsertChildInWindow
;
2583 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2584 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2586 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2588 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2589 scroll_class
->scrollbar_spacing
= 0;
2591 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2593 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2594 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2596 m_wxwindow
= gtk_pizza_new();
2598 #ifndef __WXUNIVERSAL__
2599 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2601 if (HasFlag(wxRAISED_BORDER
))
2603 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2605 else if (HasFlag(wxSUNKEN_BORDER
))
2607 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2609 else if (HasFlag(wxSIMPLE_BORDER
))
2611 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2615 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2617 #endif // __WXUNIVERSAL__
2619 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2621 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2622 m_acceptsFocus
= true;
2624 // I _really_ don't want scrollbars in the beginning
2625 m_vAdjust
->lower
= 0.0;
2626 m_vAdjust
->upper
= 1.0;
2627 m_vAdjust
->value
= 0.0;
2628 m_vAdjust
->step_increment
= 1.0;
2629 m_vAdjust
->page_increment
= 1.0;
2630 m_vAdjust
->page_size
= 5.0;
2631 g_signal_emit_by_name (m_vAdjust
, "changed");
2632 m_hAdjust
->lower
= 0.0;
2633 m_hAdjust
->upper
= 1.0;
2634 m_hAdjust
->value
= 0.0;
2635 m_hAdjust
->step_increment
= 1.0;
2636 m_hAdjust
->page_increment
= 1.0;
2637 m_hAdjust
->page_size
= 5.0;
2638 g_signal_emit_by_name (m_hAdjust
, "changed");
2640 // these handlers block mouse events to any window during scrolling such as
2641 // motion events and prevent GTK and wxWidgets from fighting over where the
2643 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2644 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2645 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2646 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2647 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2648 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2649 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2650 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2652 // these handlers get notified when screen updates are required either when
2653 // scrolling or when the window size (and therefore scrollbar configuration)
2656 g_signal_connect (m_hAdjust
, "value_changed",
2657 G_CALLBACK (gtk_window_hscroll_callback
), this);
2658 g_signal_connect (m_vAdjust
, "value_changed",
2659 G_CALLBACK (gtk_window_vscroll_callback
), this);
2661 gtk_widget_show( m_wxwindow
);
2664 m_parent
->DoAddChild( this );
2666 m_focusWidget
= m_wxwindow
;
2673 wxWindowGTK::~wxWindowGTK()
2677 if (g_focusWindow
== this)
2678 g_focusWindow
= NULL
;
2680 if ( g_delayedFocus
== this )
2681 g_delayedFocus
= NULL
;
2683 m_isBeingDeleted
= true;
2686 // destroy children before destroying this window itself
2689 // unhook focus handlers to prevent stray events being
2690 // propagated to this (soon to be) dead object
2691 if (m_focusWidget
!= NULL
)
2693 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2694 (gpointer
) gtk_window_focus_in_callback
,
2696 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2697 (gpointer
) gtk_window_focus_out_callback
,
2706 gdk_ic_destroy (m_ic
);
2708 gdk_ic_attr_destroy (m_icattr
);
2711 // delete before the widgets to avoid a crash on solaris
2716 gtk_widget_destroy( m_wxwindow
);
2717 m_wxwindow
= (GtkWidget
*) NULL
;
2722 gtk_widget_destroy( m_widget
);
2723 m_widget
= (GtkWidget
*) NULL
;
2727 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2729 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2731 // Use either the given size, or the default if -1 is given.
2732 // See wxWindowBase for these functions.
2733 m_width
= WidthDefault(size
.x
) ;
2734 m_height
= HeightDefault(size
.y
);
2742 void wxWindowGTK::PostCreation()
2744 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2750 // these get reported to wxWidgets -> wxPaintEvent
2752 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2754 g_signal_connect (m_wxwindow
, "expose_event",
2755 G_CALLBACK (gtk_window_expose_callback
), this);
2757 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2760 // Create input method handler
2761 m_imData
= new wxGtkIMData
;
2763 // Cannot handle drawing preedited text yet
2764 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2766 g_signal_connect (m_imData
->context
, "commit",
2767 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2769 // these are called when the "sunken" or "raised" borders are drawn
2770 g_signal_connect (m_widget
, "expose_event",
2771 G_CALLBACK (gtk_window_own_expose_callback
), this);
2776 if (!GTK_IS_WINDOW(m_widget
))
2778 if (m_focusWidget
== NULL
)
2779 m_focusWidget
= m_widget
;
2783 g_signal_connect (m_focusWidget
, "focus_in_event",
2784 G_CALLBACK (gtk_window_focus_in_callback
), this);
2785 g_signal_connect (m_focusWidget
, "focus_out_event",
2786 G_CALLBACK (gtk_window_focus_out_callback
), this);
2790 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2791 G_CALLBACK (gtk_window_focus_in_callback
), this);
2792 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2793 G_CALLBACK (gtk_window_focus_out_callback
), this);
2797 // connect to the various key and mouse handlers
2799 GtkWidget
*connect_widget
= GetConnectWidget();
2801 ConnectWidget( connect_widget
);
2803 /* We cannot set colours, fonts and cursors before the widget has
2804 been realized, so we do this directly after realization */
2805 g_signal_connect (connect_widget
, "realize",
2806 G_CALLBACK (gtk_window_realized_callback
), this);
2810 // Catch native resize events
2811 g_signal_connect (m_wxwindow
, "size_allocate",
2812 G_CALLBACK (gtk_window_size_callback
), this);
2814 // Initialize XIM support
2815 g_signal_connect (m_wxwindow
, "realize",
2816 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2818 // And resize XIM window
2819 g_signal_connect (m_wxwindow
, "size_allocate",
2820 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2823 if (GTK_IS_COMBO(m_widget
))
2825 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2827 g_signal_connect (gcombo
->entry
, "size_request",
2828 G_CALLBACK (wxgtk_combo_size_request_callback
),
2833 // This is needed if we want to add our windows into native
2834 // GTK controls, such as the toolbar. With this callback, the
2835 // toolbar gets to know the correct size (the one set by the
2836 // programmer). Sadly, it misbehaves for wxComboBox.
2837 g_signal_connect (m_widget
, "size_request",
2838 G_CALLBACK (wxgtk_window_size_request_callback
),
2842 InheritAttributes();
2846 // unless the window was created initially hidden (i.e. Hide() had been
2847 // called before Create()), we should show it at GTK+ level as well
2849 gtk_widget_show( m_widget
);
2852 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2854 g_signal_connect (widget
, "key_press_event",
2855 G_CALLBACK (gtk_window_key_press_callback
), this);
2856 g_signal_connect (widget
, "key_release_event",
2857 G_CALLBACK (gtk_window_key_release_callback
), this);
2858 g_signal_connect (widget
, "button_press_event",
2859 G_CALLBACK (gtk_window_button_press_callback
), this);
2860 g_signal_connect (widget
, "button_release_event",
2861 G_CALLBACK (gtk_window_button_release_callback
), this);
2862 g_signal_connect (widget
, "motion_notify_event",
2863 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2864 g_signal_connect (widget
, "scroll_event",
2865 G_CALLBACK (gtk_window_wheel_callback
), this);
2866 g_signal_connect (widget
, "popup_menu",
2867 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2868 g_signal_connect (widget
, "enter_notify_event",
2869 G_CALLBACK (gtk_window_enter_callback
), this);
2870 g_signal_connect (widget
, "leave_notify_event",
2871 G_CALLBACK (gtk_window_leave_callback
), this);
2874 bool wxWindowGTK::Destroy()
2876 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2880 return wxWindowBase::Destroy();
2883 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2885 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2888 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2890 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2891 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2894 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2897 if (m_resizing
) return; /* I don't like recursions */
2900 int currentX
, currentY
;
2901 GetPosition(¤tX
, ¤tY
);
2902 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2904 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2906 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2908 // calculate the best size if we should auto size the window
2909 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2910 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2912 const wxSize sizeBest
= GetBestSize();
2913 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2915 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2916 height
= sizeBest
.y
;
2924 int minWidth
= GetMinWidth(),
2925 minHeight
= GetMinHeight(),
2926 maxWidth
= GetMaxWidth(),
2927 maxHeight
= GetMaxHeight();
2929 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2930 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2931 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2932 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2934 #if wxUSE_TOOLBAR_NATIVE
2935 if (wxDynamicCast(GetParent(), wxToolBar
))
2937 // don't take the x,y values, they're wrong because toolbar sets them
2938 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2939 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2940 if (GTK_WIDGET_VISIBLE (widget
))
2941 gtk_widget_queue_resize (widget
);
2945 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2947 // don't set the size for children of wxNotebook, just take the values.
2955 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2956 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2958 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2959 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2963 m_x
= x
+ pizza
->xoffset
;
2964 m_y
= y
+ pizza
->yoffset
;
2967 int left_border
= 0;
2968 int right_border
= 0;
2970 int bottom_border
= 0;
2972 /* the default button has a border around it */
2973 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2975 GtkBorder
*default_border
= NULL
;
2976 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2979 left_border
+= default_border
->left
;
2980 right_border
+= default_border
->right
;
2981 top_border
+= default_border
->top
;
2982 bottom_border
+= default_border
->bottom
;
2983 g_free( default_border
);
2987 DoMoveWindow( m_x
-top_border
,
2989 m_width
+left_border
+right_border
,
2990 m_height
+top_border
+bottom_border
);
2995 /* Sometimes the client area changes size without the
2996 whole windows's size changing, but if the whole
2997 windows's size doesn't change, no wxSizeEvent will
2998 normally be sent. Here we add an extra test if
2999 the client test has been changed and this will
3001 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3005 wxPrintf( "OnSize sent from " );
3006 if (GetClassInfo() && GetClassInfo()->GetClassName())
3007 wxPrintf( GetClassInfo()->GetClassName() );
3008 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3011 if (!m_nativeSizeEvent
)
3013 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3014 event
.SetEventObject( this );
3015 GetEventHandler()->ProcessEvent( event
);
3021 void wxWindowGTK::OnInternalIdle()
3023 if ( m_dirtyTabOrder
)
3025 m_dirtyTabOrder
= false;
3029 // Update style if the window was not yet realized
3030 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3031 if (m_needsStyleChange
)
3033 SetBackgroundStyle(GetBackgroundStyle());
3034 m_needsStyleChange
= false;
3037 // Update invalidated regions.
3040 wxCursor cursor
= m_cursor
;
3041 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3045 /* I now set the cursor anew in every OnInternalIdle call
3046 as setting the cursor in a parent window also effects the
3047 windows above so that checking for the current cursor is
3052 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3054 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3056 if (!g_globalCursor
.Ok())
3057 cursor
= *wxSTANDARD_CURSOR
;
3059 window
= m_widget
->window
;
3060 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3061 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3067 GdkWindow
*window
= m_widget
->window
;
3068 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3069 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3074 if (wxUpdateUIEvent::CanUpdate(this))
3075 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3078 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3080 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3082 if (width
) (*width
) = m_width
;
3083 if (height
) (*height
) = m_height
;
3086 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3088 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3097 GetScrollbarWidth(m_widget
, dw
, dh
);
3100 #ifndef __WXUNIVERSAL__
3101 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3103 // shadow border size is 2
3107 if (HasFlag(wxSIMPLE_BORDER
))
3109 // simple border size is 1
3113 #endif // __WXUNIVERSAL__
3119 SetSize(width
, height
);
3122 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3124 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3136 GetScrollbarWidth(m_widget
, dw
, dh
);
3139 #ifndef __WXUNIVERSAL__
3140 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3142 // shadow border size is 2
3146 if (HasFlag(wxSIMPLE_BORDER
))
3148 // simple border size is 1
3152 #endif // __WXUNIVERSAL__
3158 if (width
) *width
= w
;
3159 if (height
) *height
= h
;
3162 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3164 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3168 if (m_parent
&& m_parent
->m_wxwindow
)
3170 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3171 dx
= pizza
->xoffset
;
3172 dy
= pizza
->yoffset
;
3175 if (x
) (*x
) = m_x
- dx
;
3176 if (y
) (*y
) = m_y
- dy
;
3179 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3181 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3183 if (!m_widget
->window
) return;
3185 GdkWindow
*source
= (GdkWindow
*) NULL
;
3187 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3189 source
= m_widget
->window
;
3193 gdk_window_get_origin( source
, &org_x
, &org_y
);
3197 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3199 org_x
+= m_widget
->allocation
.x
;
3200 org_y
+= m_widget
->allocation
.y
;
3208 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3210 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3212 if (!m_widget
->window
) return;
3214 GdkWindow
*source
= (GdkWindow
*) NULL
;
3216 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3218 source
= m_widget
->window
;
3222 gdk_window_get_origin( source
, &org_x
, &org_y
);
3226 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3228 org_x
+= m_widget
->allocation
.x
;
3229 org_y
+= m_widget
->allocation
.y
;
3237 bool wxWindowGTK::Show( bool show
)
3239 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3241 if (!wxWindowBase::Show(show
))
3248 gtk_widget_show( m_widget
);
3250 gtk_widget_hide( m_widget
);
3252 wxShowEvent
eventShow(GetId(), show
);
3253 eventShow
.SetEventObject(this);
3255 GetEventHandler()->ProcessEvent(eventShow
);
3260 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3262 win
->OnParentEnable(enable
);
3264 // Recurse, so that children have the opportunity to Do The Right Thing
3265 // and reset colours that have been messed up by a parent's (really ancestor's)
3267 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3269 node
= node
->GetNext() )
3271 wxWindow
*child
= node
->GetData();
3272 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3273 wxWindowNotifyEnable(child
, enable
);
3277 bool wxWindowGTK::Enable( bool enable
)
3279 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3281 if (!wxWindowBase::Enable(enable
))
3287 gtk_widget_set_sensitive( m_widget
, enable
);
3289 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3291 wxWindowNotifyEnable(this, enable
);
3296 int wxWindowGTK::GetCharHeight() const
3298 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3300 wxFont font
= GetFont();
3301 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3303 PangoContext
*context
= NULL
;
3305 context
= gtk_widget_get_pango_context( m_widget
);
3310 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3311 PangoLayout
*layout
= pango_layout_new(context
);
3312 pango_layout_set_font_description(layout
, desc
);
3313 pango_layout_set_text(layout
, "H", 1);
3314 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3316 PangoRectangle rect
;
3317 pango_layout_line_get_extents(line
, NULL
, &rect
);
3319 g_object_unref( G_OBJECT( layout
) );
3321 return (int) PANGO_PIXELS(rect
.height
);
3324 int wxWindowGTK::GetCharWidth() const
3326 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3328 wxFont font
= GetFont();
3329 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3331 PangoContext
*context
= NULL
;
3333 context
= gtk_widget_get_pango_context( m_widget
);
3338 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3339 PangoLayout
*layout
= pango_layout_new(context
);
3340 pango_layout_set_font_description(layout
, desc
);
3341 pango_layout_set_text(layout
, "g", 1);
3342 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3344 PangoRectangle rect
;
3345 pango_layout_line_get_extents(line
, NULL
, &rect
);
3347 g_object_unref( G_OBJECT( layout
) );
3349 return (int) PANGO_PIXELS(rect
.width
);
3352 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3356 int *externalLeading
,
3357 const wxFont
*theFont
) const
3359 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3361 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3370 PangoContext
*context
= NULL
;
3372 context
= gtk_widget_get_pango_context( m_widget
);
3381 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3382 PangoLayout
*layout
= pango_layout_new(context
);
3383 pango_layout_set_font_description(layout
, desc
);
3385 const wxCharBuffer data
= wxGTK_CONV( string
);
3387 pango_layout_set_text(layout
, data
, strlen(data
));
3390 PangoRectangle rect
;
3391 pango_layout_get_extents(layout
, NULL
, &rect
);
3393 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3394 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3397 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3398 int baseline
= pango_layout_iter_get_baseline(iter
);
3399 pango_layout_iter_free(iter
);
3400 *descent
= *y
- PANGO_PIXELS(baseline
);
3402 if (externalLeading
) (*externalLeading
) = 0; // ??
3404 g_object_unref( G_OBJECT( layout
) );
3407 void wxWindowGTK::SetFocus()
3409 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3412 // don't do anything if we already have focus
3418 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3420 gtk_widget_grab_focus (m_wxwindow
);
3425 if (GTK_IS_CONTAINER(m_widget
))
3427 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3430 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3433 if (!GTK_WIDGET_REALIZED(m_widget
))
3435 // we can't set the focus to the widget now so we remember that
3436 // it should be focused and will do it later, during the idle
3437 // time, as soon as we can
3438 wxLogTrace(TRACE_FOCUS
,
3439 _T("Delaying setting focus to %s(%s)"),
3440 GetClassInfo()->GetClassName(), GetLabel().c_str());
3442 g_delayedFocus
= this;
3446 wxLogTrace(TRACE_FOCUS
,
3447 _T("Setting focus to %s(%s)"),
3448 GetClassInfo()->GetClassName(), GetLabel().c_str());
3450 gtk_widget_grab_focus (m_widget
);
3455 wxLogTrace(TRACE_FOCUS
,
3456 _T("Can't set focus to %s(%s)"),
3457 GetClassInfo()->GetClassName(), GetLabel().c_str());
3462 bool wxWindowGTK::AcceptsFocus() const
3464 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3467 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3469 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3471 wxWindowGTK
*oldParent
= m_parent
,
3472 *newParent
= (wxWindowGTK
*)newParentBase
;
3474 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3476 if ( !wxWindowBase::Reparent(newParent
) )
3479 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3481 /* prevent GTK from deleting the widget arbitrarily */
3482 gtk_widget_ref( m_widget
);
3486 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3489 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3493 /* insert GTK representation */
3494 (*(newParent
->m_insertCallback
))(newParent
, this);
3497 /* reverse: prevent GTK from deleting the widget arbitrarily */
3498 gtk_widget_unref( m_widget
);
3503 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3505 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3507 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3509 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3514 /* insert GTK representation */
3515 (*m_insertCallback
)(this, child
);
3518 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3520 wxWindowBase::AddChild(child
);
3521 m_dirtyTabOrder
= true;
3523 wxapp_install_idle_handler();
3526 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3528 wxWindowBase::RemoveChild(child
);
3529 m_dirtyTabOrder
= true;
3531 wxapp_install_idle_handler();
3534 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3536 wxWindowBase::DoMoveInTabOrder(win
, move
);
3537 m_dirtyTabOrder
= true;
3539 wxapp_install_idle_handler();
3542 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3544 // none needed by default
3548 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3550 // nothing to do by default since none is needed
3553 void wxWindowGTK::RealizeTabOrder()
3557 if ( !m_children
.empty() )
3559 // we don't only construct the correct focus chain but also use
3560 // this opportunity to update the mnemonic widgets for the widgets
3563 GList
*chain
= NULL
;
3564 wxWindowGTK
* mnemonicWindow
= NULL
;
3566 for ( wxWindowList::const_iterator i
= m_children
.begin();
3567 i
!= m_children
.end();
3570 wxWindowGTK
*win
= *i
;
3572 if ( mnemonicWindow
)
3574 if ( win
->AcceptsFocusFromKeyboard() )
3576 // wxComboBox et al. needs to focus on on a different
3577 // widget than m_widget, so if the main widget isn't
3578 // focusable try the connect widget
3579 GtkWidget
* w
= win
->m_widget
;
3580 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3582 w
= win
->GetConnectWidget();
3583 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3589 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3590 mnemonicWindow
= NULL
;
3594 else if ( win
->GTKWidgetNeedsMnemonic() )
3596 mnemonicWindow
= win
;
3599 chain
= g_list_prepend(chain
, win
->m_widget
);
3602 chain
= g_list_reverse(chain
);
3604 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3609 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3614 void wxWindowGTK::Raise()
3616 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3618 if (m_wxwindow
&& m_wxwindow
->window
)
3620 gdk_window_raise( m_wxwindow
->window
);
3622 else if (m_widget
->window
)
3624 gdk_window_raise( m_widget
->window
);
3628 void wxWindowGTK::Lower()
3630 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3632 if (m_wxwindow
&& m_wxwindow
->window
)
3634 gdk_window_lower( m_wxwindow
->window
);
3636 else if (m_widget
->window
)
3638 gdk_window_lower( m_widget
->window
);
3642 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3644 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3646 if (cursor
== m_cursor
)
3650 wxapp_install_idle_handler();
3652 if (cursor
== wxNullCursor
)
3653 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3655 return wxWindowBase::SetCursor( cursor
);
3658 void wxWindowGTK::WarpPointer( int x
, int y
)
3660 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3662 // We provide this function ourselves as it is
3663 // missing in GDK (top of this file).
3665 GdkWindow
*window
= (GdkWindow
*) NULL
;
3667 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3669 window
= GetConnectWidget()->window
;
3672 gdk_window_warp_pointer( window
, x
, y
);
3675 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3677 double value_start
= adj
->value
;
3678 double value
= value_start
+ change
;
3679 double upper
= adj
->upper
- adj
->page_size
;
3684 // Lower bound will be checked by gtk_adjustment_set_value
3685 gtk_adjustment_set_value(adj
, value
);
3686 return adj
->value
!= value_start
;
3689 bool wxWindowGTK::ScrollLines(int lines
)
3692 m_vAdjust
!= NULL
&&
3693 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3696 bool wxWindowGTK::ScrollPages(int pages
)
3699 m_vAdjust
!= NULL
&&
3700 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3703 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3705 wxASSERT(m_vAdjust
== NULL
);
3709 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3713 if (!m_widget
->window
)
3718 GdkRectangle gdk_rect
,
3722 gdk_rect
.x
= rect
->x
;
3723 gdk_rect
.y
= rect
->y
;
3724 gdk_rect
.width
= rect
->width
;
3725 gdk_rect
.height
= rect
->height
;
3728 else // invalidate everything
3733 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3737 void wxWindowGTK::Update()
3741 // when we call Update() we really want to update the window immediately on
3742 // screen, even if it means flushing the entire queue and hence slowing down
3743 // everything -- but it should still be done, it's just that Update() should
3744 // be called very rarely
3748 void wxWindowGTK::GtkUpdate()
3750 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3751 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3753 // for consistency with other platforms (and also because it's convenient
3754 // to be able to update an entire TLW by calling Update() only once), we
3755 // should also update all our children here
3756 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3758 node
= node
->GetNext() )
3760 node
->GetData()->GtkUpdate();
3764 void wxWindowGTK::GtkSendPaintEvents()
3768 m_updateRegion
.Clear();
3772 // Clip to paint region in wxClientDC
3773 m_clipPaintRegion
= true;
3775 // widget to draw on
3776 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3778 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3780 // find ancestor from which to steal background
3781 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3783 parent
= (wxWindow
*)this;
3785 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3787 wxRegionIterator
upd( m_updateRegion
);
3791 rect
.x
= upd
.GetX();
3792 rect
.y
= upd
.GetY();
3793 rect
.width
= upd
.GetWidth();
3794 rect
.height
= upd
.GetHeight();
3796 gtk_paint_flat_box( parent
->m_widget
->style
,
3798 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3812 wxWindowDC
dc( (wxWindow
*)this );
3813 dc
.SetClippingRegion( m_updateRegion
);
3815 wxEraseEvent
erase_event( GetId(), &dc
);
3816 erase_event
.SetEventObject( this );
3818 GetEventHandler()->ProcessEvent(erase_event
);
3821 wxNcPaintEvent
nc_paint_event( GetId() );
3822 nc_paint_event
.SetEventObject( this );
3823 GetEventHandler()->ProcessEvent( nc_paint_event
);
3825 wxPaintEvent
paint_event( GetId() );
3826 paint_event
.SetEventObject( this );
3827 GetEventHandler()->ProcessEvent( paint_event
);
3829 m_clipPaintRegion
= false;
3831 m_updateRegion
.Clear();
3834 void wxWindowGTK::ClearBackground()
3836 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3840 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3842 wxWindowBase::DoSetToolTip(tip
);
3845 m_tooltip
->Apply( (wxWindow
*)this );
3848 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3850 wxString
tmp( tip
);
3851 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3853 #endif // wxUSE_TOOLTIPS
3855 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3857 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3859 if (!wxWindowBase::SetBackgroundColour(colour
))
3864 // We need the pixel value e.g. for background clearing.
3865 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3868 // apply style change (forceStyle=true so that new style is applied
3869 // even if the bg colour changed from valid to wxNullColour)
3870 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3871 ApplyWidgetStyle(true);
3876 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3878 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3880 if (!wxWindowBase::SetForegroundColour(colour
))
3887 // We need the pixel value e.g. for background clearing.
3888 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3891 // apply style change (forceStyle=true so that new style is applied
3892 // even if the bg colour changed from valid to wxNullColour):
3893 ApplyWidgetStyle(true);
3898 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3900 return gtk_widget_get_pango_context( m_widget
);
3903 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3905 // do we need to apply any changes at all?
3908 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3913 GtkRcStyle
*style
= gtk_rc_style_new();
3918 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3921 if ( m_foregroundColour
.Ok() )
3923 GdkColor
*fg
= m_foregroundColour
.GetColor();
3925 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3926 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3928 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3929 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3931 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3932 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3935 if ( m_backgroundColour
.Ok() )
3937 GdkColor
*bg
= m_backgroundColour
.GetColor();
3939 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3940 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3941 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3942 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3944 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3945 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3946 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3947 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3949 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3950 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3951 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3952 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3954 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3955 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3956 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3957 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3963 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3965 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3968 DoApplyWidgetStyle(style
);
3969 gtk_rc_style_unref(style
);
3972 // Style change may affect GTK+'s size calculation:
3973 InvalidateBestSize();
3976 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3979 gtk_widget_modify_style(m_wxwindow
, style
);
3981 gtk_widget_modify_style(m_widget
, style
);
3984 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3986 wxWindowBase::SetBackgroundStyle(style
);
3988 if (style
== wxBG_STYLE_CUSTOM
)
3990 GdkWindow
*window
= (GdkWindow
*) NULL
;
3992 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3994 window
= GetConnectWidget()->window
;
3998 // Make sure GDK/X11 doesn't refresh the window
4000 gdk_window_set_back_pixmap( window
, None
, False
);
4002 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4005 m_needsStyleChange
= false;
4008 // Do in OnIdle, because the window is not yet available
4009 m_needsStyleChange
= true;
4011 // Don't apply widget style, or we get a grey background
4015 // apply style change (forceStyle=true so that new style is applied
4016 // even if the bg colour changed from valid to wxNullColour):
4017 ApplyWidgetStyle(true);
4022 #if wxUSE_DRAG_AND_DROP
4024 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4026 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4028 GtkWidget
*dnd_widget
= GetConnectWidget();
4030 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4032 if (m_dropTarget
) delete m_dropTarget
;
4033 m_dropTarget
= dropTarget
;
4035 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4038 #endif // wxUSE_DRAG_AND_DROP
4040 GtkWidget
* wxWindowGTK::GetConnectWidget()
4042 GtkWidget
*connect_widget
= m_widget
;
4043 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4045 return connect_widget
;
4048 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4051 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4053 return (window
== m_widget
->window
);
4056 bool wxWindowGTK::SetFont( const wxFont
&font
)
4058 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4060 if (!wxWindowBase::SetFont(font
))
4063 // apply style change (forceStyle=true so that new style is applied
4064 // even if the font changed from valid to wxNullFont):
4065 ApplyWidgetStyle(true);
4070 void wxWindowGTK::DoCaptureMouse()
4072 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4074 GdkWindow
*window
= (GdkWindow
*) NULL
;
4076 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4078 window
= GetConnectWidget()->window
;
4080 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4082 const wxCursor
* cursor
= &m_cursor
;
4084 cursor
= wxSTANDARD_CURSOR
;
4086 gdk_pointer_grab( window
, FALSE
,
4088 (GDK_BUTTON_PRESS_MASK
|
4089 GDK_BUTTON_RELEASE_MASK
|
4090 GDK_POINTER_MOTION_HINT_MASK
|
4091 GDK_POINTER_MOTION_MASK
),
4093 cursor
->GetCursor(),
4094 (guint32
)GDK_CURRENT_TIME
);
4095 g_captureWindow
= this;
4096 g_captureWindowHasMouse
= true;
4099 void wxWindowGTK::DoReleaseMouse()
4101 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4103 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4105 g_captureWindow
= (wxWindowGTK
*) NULL
;
4107 GdkWindow
*window
= (GdkWindow
*) NULL
;
4109 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4111 window
= GetConnectWidget()->window
;
4116 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4120 wxWindow
*wxWindowBase::GetCapture()
4122 return (wxWindow
*)g_captureWindow
;
4125 bool wxWindowGTK::IsRetained() const
4130 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4131 int range
, bool refresh
)
4133 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4135 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4137 m_hasScrolling
= true;
4139 if (orient
== wxHORIZONTAL
)
4141 float fpos
= (float)pos
;
4142 float frange
= (float)range
;
4143 float fthumb
= (float)thumbVisible
;
4144 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4145 if (fpos
< 0.0) fpos
= 0.0;
4147 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4148 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4150 SetScrollPos( orient
, pos
, refresh
);
4154 m_oldHorizontalPos
= fpos
;
4156 m_hAdjust
->lower
= 0.0;
4157 m_hAdjust
->upper
= frange
;
4158 m_hAdjust
->value
= fpos
;
4159 m_hAdjust
->step_increment
= 1.0;
4160 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4161 m_hAdjust
->page_size
= fthumb
;
4165 float fpos
= (float)pos
;
4166 float frange
= (float)range
;
4167 float fthumb
= (float)thumbVisible
;
4168 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4169 if (fpos
< 0.0) fpos
= 0.0;
4171 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4172 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4174 SetScrollPos( orient
, pos
, refresh
);
4178 m_oldVerticalPos
= fpos
;
4180 m_vAdjust
->lower
= 0.0;
4181 m_vAdjust
->upper
= frange
;
4182 m_vAdjust
->value
= fpos
;
4183 m_vAdjust
->step_increment
= 1.0;
4184 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4185 m_vAdjust
->page_size
= fthumb
;
4188 if (orient
== wxHORIZONTAL
)
4189 g_signal_emit_by_name (m_hAdjust
, "changed");
4191 g_signal_emit_by_name (m_vAdjust
, "changed");
4194 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4196 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4197 gpointer fn
= orient
== wxHORIZONTAL
4198 ? (gpointer
) gtk_window_hscroll_callback
4199 : (gpointer
) gtk_window_vscroll_callback
;
4201 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4202 g_signal_emit_by_name (adj
, "value_changed");
4203 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4206 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4208 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4209 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4211 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4213 float fpos
= (float)pos
;
4214 if (fpos
> adj
->upper
- adj
->page_size
)
4215 fpos
= adj
->upper
- adj
->page_size
;
4218 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4220 if (fabs(fpos
-adj
->value
) < 0.2)
4224 if ( m_wxwindow
->window
)
4229 int wxWindowGTK::GetScrollThumb( int orient
) const
4231 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4233 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4235 if (orient
== wxHORIZONTAL
)
4236 return (int)(m_hAdjust
->page_size
+0.5);
4238 return (int)(m_vAdjust
->page_size
+0.5);
4241 int wxWindowGTK::GetScrollPos( int orient
) const
4243 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4245 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4247 if (orient
== wxHORIZONTAL
)
4248 return (int)(m_hAdjust
->value
+0.5);
4250 return (int)(m_vAdjust
->value
+0.5);
4253 int wxWindowGTK::GetScrollRange( int orient
) const
4255 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4257 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4259 if (orient
== wxHORIZONTAL
)
4260 return (int)(m_hAdjust
->upper
+0.5);
4262 return (int)(m_vAdjust
->upper
+0.5);
4265 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4267 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4269 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4271 // No scrolling requested.
4272 if ((dx
== 0) && (dy
== 0)) return;
4274 m_clipPaintRegion
= true;
4276 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4278 m_clipPaintRegion
= false;
4281 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4283 //RN: Note that static controls usually have no border on gtk, so maybe
4284 //it makes sense to treat that as simply no border at the wx level
4286 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4288 GtkShadowType gtkstyle
;
4290 if(wxstyle
& wxBORDER_RAISED
)
4291 gtkstyle
= GTK_SHADOW_OUT
;
4292 else if (wxstyle
& wxBORDER_SUNKEN
)
4293 gtkstyle
= GTK_SHADOW_IN
;
4294 else if (wxstyle
& wxBORDER_DOUBLE
)
4295 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4297 gtkstyle
= GTK_SHADOW_IN
;
4299 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4304 void wxWindowGTK::SetWindowStyleFlag( long style
)
4306 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4307 wxWindowBase::SetWindowStyleFlag(style
);
4310 // Find the wxWindow at the current mouse position, also returning the mouse
4312 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4314 pt
= wxGetMousePosition();
4315 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4319 // Get the current mouse position.
4320 wxPoint
wxGetMousePosition()
4322 /* This crashes when used within wxHelpContext,
4323 so we have to use the X-specific implementation below.
4325 GdkModifierType *mask;
4326 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4328 return wxPoint(x, y);
4332 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4334 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4335 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4336 Window rootReturn
, childReturn
;
4337 int rootX
, rootY
, winX
, winY
;
4338 unsigned int maskReturn
;
4340 XQueryPointer (display
,
4344 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4345 return wxPoint(rootX
, rootY
);
4349 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4350 void wxAddGrab(wxWindow
* window
)
4352 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4355 void wxRemoveGrab(wxWindow
* window
)
4357 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4360 // ----------------------------------------------------------------------------
4362 // ----------------------------------------------------------------------------
4364 class wxWinModule
: public wxModule
4371 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4374 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4376 bool wxWinModule::OnInit()
4378 // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() );
4379 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4384 void wxWinModule::OnExit()
4387 g_object_unref (G_OBJECT (g_eraseGC
));