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"
25 #include "wx/dcclient.h"
27 #include "wx/dialog.h"
28 #include "wx/settings.h"
29 #include "wx/msgdlg.h"
30 #include "wx/textctrl.h"
31 #include "wx/toolbar.h"
32 #include "wx/combobox.h"
33 #include "wx/layout.h"
34 #include "wx/statusbr.h"
38 #include "wx/module.h"
40 #if wxUSE_DRAG_AND_DROP
45 #include "wx/tooltip.h"
52 #include "wx/fontutil.h"
55 #include "wx/thread.h"
60 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
61 #include <gtk/gtkversion.h>
62 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
63 #undef GTK_DISABLE_DEPRECATED
66 #include "wx/gtk/private.h"
67 #include <gdk/gdkprivate.h>
68 #include <gdk/gdkkeysyms.h>
72 #include <gtk/gtkprivate.h>
74 #include "wx/gtk/win_gtk.h"
76 #include <pango/pangox.h>
82 extern GtkContainerClass
*pizza_parent_class
;
84 //-----------------------------------------------------------------------------
85 // documentation on internals
86 //-----------------------------------------------------------------------------
89 I have been asked several times about writing some documentation about
90 the GTK port of wxWidgets, especially its internal structures. Obviously,
91 you cannot understand wxGTK without knowing a little about the GTK, but
92 some more information about what the wxWindow, which is the base class
93 for all other window classes, does seems required as well.
97 What does wxWindow do? It contains the common interface for the following
98 jobs of its descendants:
100 1) Define the rudimentary behaviour common to all window classes, such as
101 resizing, intercepting user input (so as to make it possible to use these
102 events for special purposes in a derived class), window names etc.
104 2) Provide the possibility to contain and manage children, if the derived
105 class is allowed to contain children, which holds true for those window
106 classes which do not display a native GTK widget. To name them, these
107 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
108 work classes are a special case and are handled a bit differently from
109 the rest. The same holds true for the wxNotebook class.
111 3) Provide the possibility to draw into a client area of a window. This,
112 too, only holds true for classes that do not display a native GTK widget
115 4) Provide the entire mechanism for scrolling widgets. This actual inter-
116 face for this is usually in wxScrolledWindow, but the GTK implementation
119 5) A multitude of helper or extra methods for special purposes, such as
120 Drag'n'Drop, managing validators etc.
122 6) Display a border (sunken, raised, simple or none).
124 Normally one might expect, that one wxWidgets window would always correspond
125 to one GTK widget. Under GTK, there is no such all-round widget that has all
126 the functionality. Moreover, the GTK defines a client area as a different
127 widget from the actual widget you are handling. Last but not least some
128 special classes (e.g. wxFrame) handle different categories of widgets and
129 still have the possibility to draw something in the client area.
130 It was therefore required to write a special purpose GTK widget, that would
131 represent a client area in the sense of wxWidgets capable to do the jobs
132 2), 3) and 4). I have written this class and it resides in win_gtk.c of
135 All windows must have a widget, with which they interact with other under-
136 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
137 the wxWindow class has a member variable called m_widget which holds a
138 pointer to this widget. When the window class represents a GTK native widget,
139 this is (in most cases) the only GTK widget the class manages. E.g. the
140 wxStaticText class handles only a GtkLabel widget a pointer to which you
141 can find in m_widget (defined in wxWindow)
143 When the class has a client area for drawing into and for containing children
144 it has to handle the client area widget (of the type GtkPizza, defined in
145 win_gtk.c), but there could be any number of widgets, handled by a class
146 The common rule for all windows is only, that the widget that interacts with
147 the rest of GTK must be referenced in m_widget and all other widgets must be
148 children of this widget on the GTK level. The top-most widget, which also
149 represents the client area, must be in the m_wxwindow field and must be of
152 As I said, the window classes that display a GTK native widget only have
153 one widget, so in the case of e.g. the wxButton class m_widget holds a
154 pointer to a GtkButton widget. But windows with client areas (for drawing
155 and children) have a m_widget field that is a pointer to a GtkScrolled-
156 Window and a m_wxwindow field that is pointer to a GtkPizza and this
157 one is (in the GTK sense) a child of the GtkScrolledWindow.
159 If the m_wxwindow field is set, then all input to this widget is inter-
160 cepted and sent to the wxWidgets class. If not, all input to the widget
161 that gets pointed to by m_widget gets intercepted and sent to the class.
165 The design of scrolling in wxWidgets is markedly different from that offered
166 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
167 clicking on a scrollbar belonging to scrolled window will inevitably move
168 the window. In wxWidgets, the scrollbar will only emit an event, send this
169 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
170 which actually moves the window and its sub-windows. Note that GtkPizza
171 memorizes how much it has been scrolled but that wxWidgets forgets this
172 so that the two coordinates systems have to be kept in synch. This is done
173 in various places using the pizza->xoffset and pizza->yoffset values.
177 Singularly the most broken code in GTK is the code that is supposed to
178 inform subwindows (child windows) about new positions. Very often, duplicate
179 events are sent without changes in size or position, equally often no
180 events are sent at all (All this is due to a bug in the GtkContainer code
181 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
182 GTK's own system and it simply waits for size events for toplevel windows
183 and then iterates down the respective size events to all window. This has
184 the disadvantage that windows might get size events before the GTK widget
185 actually has the reported size. This doesn't normally pose any problem, but
186 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
187 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
188 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
189 window that is used for OpenGL output really has that size (as reported by
194 If someone at some point of time feels the immense desire to have a look at,
195 change or attempt to optimise the Refresh() logic, this person will need an
196 intimate understanding of what "draw" and "expose" events are and what
197 they are used for, in particular when used in connection with GTK's
198 own windowless widgets. Beware.
202 Cursors, too, have been a constant source of pleasure. The main difficulty
203 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
204 for the parent. To prevent this from doing too much harm, I use idle time
205 to set the cursor over and over again, starting from the toplevel windows
206 and ending with the youngest generation (speaking of parent and child windows).
207 Also don't forget that cursors (like much else) are connected to GdkWindows,
208 not GtkWidgets and that the "window" field of a GtkWidget might very well
209 point to the GdkWindow of the parent widget (-> "window-less widget") and
210 that the two obviously have very different meanings.
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 extern bool g_blockEventsOnDrag
;
219 extern bool g_blockEventsOnScroll
;
220 extern wxCursor g_globalCursor
;
222 static GdkGC
*g_eraseGC
= NULL
;
224 // mouse capture state: the window which has it and if the mouse is currently
226 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
227 static bool g_captureWindowHasMouse
= false;
229 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
231 // the last window which had the focus - this is normally never NULL (except
232 // if we never had focus at all) as even when g_focusWindow is NULL it still
233 // keeps its previous value
234 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
236 // If a window get the focus set but has not been realized
237 // yet, defer setting the focus to idle time.
238 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
240 extern bool g_mainThreadLocked
;
242 //-----------------------------------------------------------------------------
244 //-----------------------------------------------------------------------------
249 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
251 # define DEBUG_MAIN_THREAD
254 #define DEBUG_MAIN_THREAD
257 // the trace mask used for the focus debugging messages
258 #define TRACE_FOCUS _T("focus")
260 //-----------------------------------------------------------------------------
261 // missing gdk functions
262 //-----------------------------------------------------------------------------
265 gdk_window_warp_pointer (GdkWindow
*window
,
270 window
= gdk_get_default_root_window();
272 if (!GDK_WINDOW_DESTROYED(window
))
274 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
275 None
, /* not source window -> move from anywhere */
276 GDK_WINDOW_XID(window
), /* dest window */
277 0, 0, 0, 0, /* not source window -> move from anywhere */
282 //-----------------------------------------------------------------------------
283 // local code (see below)
284 //-----------------------------------------------------------------------------
286 // returns the child of win which currently has focus or NULL if not found
288 // Note: can't be static, needed by textctrl.cpp.
289 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
291 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
293 return (wxWindow
*)NULL
;
295 if ( winFocus
== win
)
296 return (wxWindow
*)win
;
298 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
300 node
= node
->GetNext() )
302 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
307 return (wxWindow
*)NULL
;
310 static void GetScrollbarWidth(GtkWidget
* widget
, int& w
, int& h
)
312 GtkScrolledWindow
* scroll_window
= GTK_SCROLLED_WINDOW(widget
);
313 GtkScrolledWindowClass
* scroll_class
= GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window
));
314 GtkRequisition scroll_req
;
317 if (scroll_window
->vscrollbar_visible
)
319 scroll_req
.width
= 2;
320 scroll_req
.height
= 2;
321 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
322 (scroll_window
->vscrollbar
, &scroll_req
);
323 w
= scroll_req
.width
+
324 scroll_class
->scrollbar_spacing
;
328 if (scroll_window
->hscrollbar_visible
)
330 scroll_req
.width
= 2;
331 scroll_req
.height
= 2;
332 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
333 (scroll_window
->hscrollbar
, &scroll_req
);
334 h
= scroll_req
.height
+
335 scroll_class
->scrollbar_spacing
;
339 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
341 // wxUniversal widgets draw the borders and scrollbars themselves
342 #ifndef __WXUNIVERSAL__
349 if (win
->m_hasScrolling
)
351 GetScrollbarWidth(widget
, dw
, dh
);
356 if (GTK_WIDGET_NO_WINDOW (widget
))
358 dx
+= widget
->allocation
.x
;
359 dy
+= widget
->allocation
.y
;
362 if (win
->HasFlag(wxRAISED_BORDER
))
364 gtk_paint_shadow (widget
->style
,
368 NULL
, NULL
, NULL
, // FIXME: No clipping?
370 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
374 if (win
->HasFlag(wxSUNKEN_BORDER
))
376 gtk_paint_shadow (widget
->style
,
380 NULL
, NULL
, NULL
, // FIXME: No clipping?
382 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
386 if (win
->HasFlag(wxSIMPLE_BORDER
))
389 gc
= gdk_gc_new( widget
->window
);
390 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
391 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
393 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
397 #endif // __WXUNIVERSAL__
400 //-----------------------------------------------------------------------------
401 // "expose_event" of m_widget
402 //-----------------------------------------------------------------------------
406 gtk_window_own_expose_callback( GtkWidget
*widget
,
407 GdkEventExpose
*gdk_event
,
410 if (gdk_event
->count
> 0) return FALSE
;
412 draw_frame( widget
, win
);
414 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
420 //-----------------------------------------------------------------------------
421 // "size_request" of m_widget
422 //-----------------------------------------------------------------------------
424 // make it extern because wxStaticText needs to disconnect this one
426 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
427 GtkRequisition
*requisition
,
431 win
->GetSize( &w
, &h
);
437 requisition
->height
= h
;
438 requisition
->width
= w
;
444 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
445 GtkRequisition
*requisition
,
448 // This callback is actually hooked into the text entry
449 // of the combo box, not the GtkHBox.
452 win
->GetSize( &w
, &h
);
458 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
460 GtkRequisition entry_req
;
462 entry_req
.height
= 2;
463 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
464 (gcombo
->button
, &entry_req
);
466 requisition
->width
= w
- entry_req
.width
;
467 requisition
->height
= entry_req
.height
;
471 //-----------------------------------------------------------------------------
472 // "expose_event" of m_wxwindow
473 //-----------------------------------------------------------------------------
477 gtk_window_expose_callback( GtkWidget
*widget
,
478 GdkEventExpose
*gdk_event
,
484 wxapp_install_idle_handler();
486 // This callback gets called in drawing-idle time under
487 // GTK 2.0, so we don't need to defer anything to idle
490 GtkPizza
*pizza
= GTK_PIZZA( widget
);
491 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
496 wxPrintf( wxT("OnExpose from ") );
497 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
498 wxPrintf( win
->GetClassInfo()->GetClassName() );
499 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
500 (int)gdk_event
->area
.y
,
501 (int)gdk_event
->area
.width
,
502 (int)gdk_event
->area
.height
);
507 win
->m_wxwindow
->style
,
511 (GdkRectangle
*) NULL
,
513 (char *)"button", // const_cast
518 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
520 win
->GtkSendPaintEvents();
523 // Let parent window draw window-less widgets
524 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
530 //-----------------------------------------------------------------------------
531 // "key_press_event" from any window
532 //-----------------------------------------------------------------------------
534 // These are used when transforming Ctrl-alpha to ascii values 1-26
535 inline bool wxIsLowerChar(int code
)
537 return (code
>= 'a' && code
<= 'z' );
540 inline bool wxIsUpperChar(int code
)
542 return (code
>= 'A' && code
<= 'Z' );
546 // set WXTRACE to this to see the key event codes on the console
547 #define TRACE_KEYS _T("keyevent")
549 // translates an X key symbol to WXK_XXX value
551 // if isChar is true it means that the value returned will be used for EVT_CHAR
552 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
553 // for example, while if it is false it means that the value is going to be
554 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
556 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
562 // Shift, Control and Alt don't generate the CHAR events at all
565 key_code
= isChar
? 0 : WXK_SHIFT
;
569 key_code
= isChar
? 0 : WXK_CONTROL
;
577 key_code
= isChar
? 0 : WXK_ALT
;
580 // neither do the toggle modifies
581 case GDK_Scroll_Lock
:
582 key_code
= isChar
? 0 : WXK_SCROLL
;
586 key_code
= isChar
? 0 : WXK_CAPITAL
;
590 key_code
= isChar
? 0 : WXK_NUMLOCK
;
594 // various other special keys
607 case GDK_ISO_Left_Tab
:
614 key_code
= WXK_RETURN
;
618 key_code
= WXK_CLEAR
;
622 key_code
= WXK_PAUSE
;
626 key_code
= WXK_SELECT
;
630 key_code
= WXK_PRINT
;
634 key_code
= WXK_EXECUTE
;
638 key_code
= WXK_ESCAPE
;
641 // cursor and other extended keyboard keys
643 key_code
= WXK_DELETE
;
659 key_code
= WXK_RIGHT
;
666 case GDK_Prior
: // == GDK_Page_Up
667 key_code
= WXK_PAGEUP
;
670 case GDK_Next
: // == GDK_Page_Down
671 key_code
= WXK_PAGEDOWN
;
683 key_code
= WXK_INSERT
;
698 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
702 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
706 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
710 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
714 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
718 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
722 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
726 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
730 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
734 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
738 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
742 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
746 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
749 case GDK_KP_Prior
: // == GDK_KP_Page_Up
750 key_code
= isChar
? WXK_PAGEUP
: WXK_NUMPAD_PAGEUP
;
753 case GDK_KP_Next
: // == GDK_KP_Page_Down
754 key_code
= isChar
? WXK_PAGEDOWN
: WXK_NUMPAD_PAGEDOWN
;
758 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
762 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
766 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
770 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
774 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
777 case GDK_KP_Multiply
:
778 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
782 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
785 case GDK_KP_Separator
:
786 // FIXME: what is this?
787 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
790 case GDK_KP_Subtract
:
791 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
795 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
799 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
816 key_code
= WXK_F1
+ keysym
- GDK_F1
;
826 static inline bool wxIsAsciiKeysym(KeySym ks
)
831 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
833 GdkEventKey
*gdk_event
)
837 GdkModifierType state
;
838 if (gdk_event
->window
)
839 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
841 event
.SetTimestamp( gdk_event
->time
);
842 event
.SetId(win
->GetId());
843 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
844 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
845 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
846 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
847 event
.m_scanCode
= gdk_event
->keyval
;
848 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
849 event
.m_rawFlags
= 0;
851 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
853 wxGetMousePosition( &x
, &y
);
854 win
->ScreenToClient( &x
, &y
);
857 event
.SetEventObject( win
);
862 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
864 GdkEventKey
*gdk_event
)
866 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
867 // but only event->keyval which is quite useless to us, so remember
868 // the last character from GDK_KEY_PRESS and reuse it as last resort
870 // NB: should be MT-safe as we're always called from the main thread only
875 } s_lastKeyPress
= { 0, 0 };
877 KeySym keysym
= gdk_event
->keyval
;
879 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
880 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
884 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
888 // do we have the translation or is it a plain ASCII character?
889 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
891 // we should use keysym if it is ASCII as X does some translations
892 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
893 // which we don't want here (but which we do use for OnChar())
894 if ( !wxIsAsciiKeysym(keysym
) )
896 keysym
= (KeySym
)gdk_event
->string
[0];
899 // we want to always get the same key code when the same key is
900 // pressed regardless of the state of the modifiers, i.e. on a
901 // standard US keyboard pressing '5' or '%' ('5' key with
902 // Shift) should result in the same key code in OnKeyDown():
903 // '5' (although OnChar() will get either '5' or '%').
905 // to do it we first translate keysym to keycode (== scan code)
906 // and then back but always using the lower register
907 Display
*dpy
= (Display
*)wxGetDisplay();
908 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
910 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
912 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
914 // use the normalized, i.e. lower register, keysym if we've
916 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
918 // as explained above, we want to have lower register key codes
919 // normally but for the letter keys we want to have the upper ones
921 // NB: don't use XConvertCase() here, we want to do it for letters
923 key_code
= toupper(key_code
);
925 else // non ASCII key, what to do?
927 // by default, ignore it
930 // but if we have cached information from the last KEY_PRESS
931 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
934 if ( keysym
== s_lastKeyPress
.keysym
)
936 key_code
= s_lastKeyPress
.keycode
;
941 if ( gdk_event
->type
== GDK_KEY_PRESS
)
943 // remember it to be reused for KEY_UP event later
944 s_lastKeyPress
.keysym
= keysym
;
945 s_lastKeyPress
.keycode
= key_code
;
949 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
951 // sending unknown key events doesn't really make sense
955 // now fill all the other fields
956 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
958 event
.m_keyCode
= key_code
;
960 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
962 event
.m_uniChar
= key_code
;
972 GtkIMContext
*context
;
973 GdkEventKey
*lastKeyEvent
;
977 context
= gtk_im_multicontext_new();
982 g_object_unref (context
);
988 gtk_window_key_press_callback( GtkWidget
*widget
,
989 GdkEventKey
*gdk_event
,
995 wxapp_install_idle_handler();
999 if (g_blockEventsOnDrag
)
1003 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1005 bool return_after_IM
= false;
1007 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1009 // Emit KEY_DOWN event
1010 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1014 // Return after IM processing as we cannot do
1015 // anything with it anyhow.
1016 return_after_IM
= true;
1019 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1020 // When we get a key_press event here, it could be originate
1021 // from the current widget or its child widgets. However, only the widget
1022 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1023 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1024 // originated from its child widgets and shouldn't be passed to IM context.
1025 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1026 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1027 // widgets has both IM context and input focus, the event should be filtered
1028 // by gtk_im_context_filter_keypress().
1029 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1030 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1032 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1033 // docs, if IM filter returns true, no further processing should be done.
1034 // we should send the key_down event anyway.
1035 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1036 win
->m_imData
->lastKeyEvent
= NULL
;
1037 if (intercepted_by_IM
)
1039 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1044 if (return_after_IM
)
1050 wxWindowGTK
*ancestor
= win
;
1053 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1056 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1057 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1060 if (ancestor
->IsTopLevel())
1062 ancestor
= ancestor
->GetParent();
1065 #endif // wxUSE_ACCEL
1067 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1068 // will only be sent if it is not in an accelerator table.
1072 KeySym keysym
= gdk_event
->keyval
;
1073 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1074 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1077 if ( wxIsAsciiKeysym(keysym
) )
1080 key_code
= (unsigned char)keysym
;
1082 // gdk_event->string is actually deprecated
1083 else if ( gdk_event
->length
== 1 )
1085 key_code
= (unsigned char)gdk_event
->string
[0];
1091 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1093 event
.m_keyCode
= key_code
;
1095 // To conform to the docs we need to translate Ctrl-alpha
1096 // characters to values in the range 1-26.
1097 if ( event
.ControlDown() &&
1098 ( wxIsLowerChar(key_code
) || wxIsUpperChar(key_code
) ))
1100 if ( wxIsLowerChar(key_code
) )
1101 event
.m_keyCode
= key_code
- 'a' + 1;
1102 if ( wxIsUpperChar(key_code
) )
1103 event
.m_keyCode
= key_code
- 'A' + 1;
1105 event
.m_uniChar
= event
.m_keyCode
;
1109 // Implement OnCharHook by checking ancestor top level windows
1110 wxWindow
*parent
= win
;
1111 while (parent
&& !parent
->IsTopLevel())
1112 parent
= parent
->GetParent();
1115 event
.SetEventType( wxEVT_CHAR_HOOK
);
1116 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1121 event
.SetEventType(wxEVT_CHAR
);
1122 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1131 // win is a control: tab can be propagated up
1133 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1134 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1135 // have this style, yet choose not to process this particular TAB in which
1136 // case TAB must still work as a navigational character
1137 // JS: enabling again to make consistent with other platforms
1138 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1139 // navigation behaviour)
1141 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1143 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1145 wxNavigationKeyEvent new_event
;
1146 new_event
.SetEventObject( win
->GetParent() );
1147 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1148 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1149 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1150 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1151 new_event
.SetCurrentFocus( win
);
1152 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1157 g_signal_stop_emission_by_name (widget
, "key_press_event");
1167 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1171 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1173 // take modifiers, cursor position, timestamp etc. from the last
1174 // key_press_event that was fed into Input Method:
1175 if (window
->m_imData
->lastKeyEvent
)
1177 wxFillOtherKeyEventFields(event
,
1178 window
, window
->m_imData
->lastKeyEvent
);
1181 const wxWxCharBuffer
data(wxGTK_CONV_BACK(str
));
1187 // Implement OnCharHook by checking ancestor top level windows
1188 wxWindow
*parent
= window
;
1189 while (parent
&& !parent
->IsTopLevel())
1190 parent
= parent
->GetParent();
1192 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1195 event
.m_uniChar
= *pstr
;
1196 // Backward compatible for ISO-8859-1
1197 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1198 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1200 event
.m_keyCode
= *pstr
;
1201 #endif // wxUSE_UNICODE
1203 // To conform to the docs we need to translate Ctrl-alpha
1204 // characters to values in the range 1-26.
1205 if ( event
.ControlDown() &&
1206 ( wxIsLowerChar(*pstr
) || wxIsUpperChar(*pstr
) ))
1208 if ( wxIsLowerChar(*pstr
) )
1209 event
.m_keyCode
= *pstr
- 'a' + 1;
1210 if ( wxIsUpperChar(*pstr
) )
1211 event
.m_keyCode
= *pstr
- 'A' + 1;
1213 event
.m_keyCode
= *pstr
- 'a' + 1;
1215 event
.m_uniChar
= event
.m_keyCode
;
1221 event
.SetEventType( wxEVT_CHAR_HOOK
);
1222 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1227 event
.SetEventType(wxEVT_CHAR
);
1228 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1235 //-----------------------------------------------------------------------------
1236 // "key_release_event" from any window
1237 //-----------------------------------------------------------------------------
1241 gtk_window_key_release_callback( GtkWidget
*widget
,
1242 GdkEventKey
*gdk_event
,
1248 wxapp_install_idle_handler();
1253 if (g_blockEventsOnDrag
)
1256 wxKeyEvent
event( wxEVT_KEY_UP
);
1257 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1259 // unknown key pressed, ignore (the event would be useless anyhow)
1263 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1266 g_signal_stop_emission_by_name (widget
, "key_release_event");
1271 // ============================================================================
1273 // ============================================================================
1275 // ----------------------------------------------------------------------------
1276 // mouse event processing helpers
1277 // ----------------------------------------------------------------------------
1279 // init wxMouseEvent with the info from GdkEventXXX struct
1280 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1281 wxMouseEvent
& event
,
1284 event
.SetTimestamp( gdk_event
->time
);
1285 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1286 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1287 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1288 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1289 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1290 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1291 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1292 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1294 event
.m_linesPerAction
= 3;
1295 event
.m_wheelDelta
= 120;
1296 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1297 event
.m_wheelRotation
= 120;
1298 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1299 event
.m_wheelRotation
= -120;
1302 wxPoint pt
= win
->GetClientAreaOrigin();
1303 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1304 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1306 event
.SetEventObject( win
);
1307 event
.SetId( win
->GetId() );
1308 event
.SetTimestamp( gdk_event
->time
);
1311 static void AdjustEventButtonState(wxMouseEvent
& event
)
1313 // GDK reports the old state of the button for a button press event, but
1314 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1315 // for a LEFT_DOWN event, not FALSE, so we will invert
1316 // left/right/middleDown for the corresponding click events
1318 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1319 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1320 (event
.GetEventType() == wxEVT_LEFT_UP
))
1322 event
.m_leftDown
= !event
.m_leftDown
;
1326 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1327 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1328 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1330 event
.m_middleDown
= !event
.m_middleDown
;
1334 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1335 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1336 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1338 event
.m_rightDown
= !event
.m_rightDown
;
1343 // find the window to send the mouse event too
1345 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1350 if (win
->m_wxwindow
)
1352 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1353 xx
+= pizza
->xoffset
;
1354 yy
+= pizza
->yoffset
;
1357 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1360 wxWindowGTK
*child
= node
->GetData();
1362 node
= node
->GetNext();
1363 if (!child
->IsShown())
1366 if (child
->IsTransparentForMouse())
1368 // wxStaticBox is transparent in the box itself
1369 int xx1
= child
->m_x
;
1370 int yy1
= child
->m_y
;
1371 int xx2
= child
->m_x
+ child
->m_width
;
1372 int yy2
= child
->m_y
+ child
->m_height
;
1375 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1377 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1379 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1381 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1392 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1393 (child
->m_x
<= xx
) &&
1394 (child
->m_y
<= yy
) &&
1395 (child
->m_x
+child
->m_width
>= xx
) &&
1396 (child
->m_y
+child
->m_height
>= yy
))
1409 //-----------------------------------------------------------------------------
1410 // "button_press_event"
1411 //-----------------------------------------------------------------------------
1415 gtk_window_button_press_callback( GtkWidget
*widget
,
1416 GdkEventButton
*gdk_event
,
1422 wxapp_install_idle_handler();
1425 wxPrintf( wxT("1) OnButtonPress from ") );
1426 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1427 wxPrintf( win->GetClassInfo()->GetClassName() );
1428 wxPrintf( wxT(".\n") );
1430 if (!win
->m_hasVMT
) return FALSE
;
1431 if (g_blockEventsOnDrag
) return TRUE
;
1432 if (g_blockEventsOnScroll
) return TRUE
;
1434 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1436 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1438 gtk_widget_grab_focus( win
->m_wxwindow
);
1440 wxPrintf( wxT("GrabFocus from ") );
1441 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1442 wxPrintf( win->GetClassInfo()->GetClassName() );
1443 wxPrintf( wxT(".\n") );
1447 // GDK sends surplus button down events
1448 // before a double click event. We
1449 // need to filter these out.
1450 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1452 GdkEvent
*peek_event
= gdk_event_peek();
1455 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1456 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1458 gdk_event_free( peek_event
);
1463 gdk_event_free( peek_event
);
1468 wxEventType event_type
= wxEVT_NULL
;
1470 // GdkDisplay is a GTK+ 2.2.0 thing
1471 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1472 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1473 !gtk_check_version(2,2,0) &&
1474 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1476 // Reset GDK internal timestamp variables in order to disable GDK
1477 // triple click events. GDK will then next time believe no button has
1478 // been clicked just before, and send a normal button click event.
1479 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1480 display
->button_click_time
[1] = 0;
1481 display
->button_click_time
[0] = 0;
1485 if (gdk_event
->button
== 1)
1487 // note that GDK generates triple click events which are not supported
1488 // by wxWidgets but still have to be passed to the app as otherwise
1489 // clicks would simply go missing
1490 switch (gdk_event
->type
)
1492 // we shouldn't get triple clicks at all for GTK2 because we
1493 // suppress them artificially using the code above but we still
1494 // should map them to something for GTK1 and not just ignore them
1495 // as this would lose clicks
1496 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1497 case GDK_BUTTON_PRESS
:
1498 event_type
= wxEVT_LEFT_DOWN
;
1501 case GDK_2BUTTON_PRESS
:
1502 event_type
= wxEVT_LEFT_DCLICK
;
1506 // just to silence gcc warnings
1510 else if (gdk_event
->button
== 2)
1512 switch (gdk_event
->type
)
1514 case GDK_3BUTTON_PRESS
:
1515 case GDK_BUTTON_PRESS
:
1516 event_type
= wxEVT_MIDDLE_DOWN
;
1519 case GDK_2BUTTON_PRESS
:
1520 event_type
= wxEVT_MIDDLE_DCLICK
;
1527 else if (gdk_event
->button
== 3)
1529 switch (gdk_event
->type
)
1531 case GDK_3BUTTON_PRESS
:
1532 case GDK_BUTTON_PRESS
:
1533 event_type
= wxEVT_RIGHT_DOWN
;
1536 case GDK_2BUTTON_PRESS
:
1537 event_type
= wxEVT_RIGHT_DCLICK
;
1544 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1546 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1548 event_type
= wxEVT_MOUSEWHEEL
;
1552 if ( event_type
== wxEVT_NULL
)
1554 // unknown mouse button or click type
1558 wxMouseEvent
event( event_type
);
1559 InitMouseEvent( win
, event
, gdk_event
);
1561 AdjustEventButtonState(event
);
1563 // wxListBox actually gets mouse events from the item, so we need to give it
1564 // a chance to correct this
1565 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1567 // find the correct window to send the event to: it may be a different one
1568 // from the one which got it at GTK+ level because some controls don't have
1569 // their own X window and thus cannot get any events.
1570 if ( !g_captureWindow
)
1571 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1573 // reset the event object and id in case win changed.
1574 event
.SetEventObject( win
);
1575 event
.SetId( win
->GetId() );
1577 if (win
->GetEventHandler()->ProcessEvent( event
))
1579 g_signal_stop_emission_by_name (widget
, "button_press_event");
1583 if (event_type
== wxEVT_RIGHT_DOWN
)
1585 // generate a "context menu" event: this is similar to right mouse
1586 // click under many GUIs except that it is generated differently
1587 // (right up under MSW, ctrl-click under Mac, right down here) and
1589 // (a) it's a command event and so is propagated to the parent
1590 // (b) under some ports it can be generated from kbd too
1591 // (c) it uses screen coords (because of (a))
1592 wxContextMenuEvent
evtCtx(
1595 win
->ClientToScreen(event
.GetPosition()));
1596 evtCtx
.SetEventObject(win
);
1597 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1604 //-----------------------------------------------------------------------------
1605 // "button_release_event"
1606 //-----------------------------------------------------------------------------
1610 gtk_window_button_release_callback( GtkWidget
*widget
,
1611 GdkEventButton
*gdk_event
,
1617 wxapp_install_idle_handler();
1619 if (!win
->m_hasVMT
) return FALSE
;
1620 if (g_blockEventsOnDrag
) return FALSE
;
1621 if (g_blockEventsOnScroll
) return FALSE
;
1623 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1625 wxEventType event_type
= wxEVT_NULL
;
1627 switch (gdk_event
->button
)
1630 event_type
= wxEVT_LEFT_UP
;
1634 event_type
= wxEVT_MIDDLE_UP
;
1638 event_type
= wxEVT_RIGHT_UP
;
1642 // unknown button, don't process
1646 wxMouseEvent
event( event_type
);
1647 InitMouseEvent( win
, event
, gdk_event
);
1649 AdjustEventButtonState(event
);
1651 // same wxListBox hack as above
1652 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1654 if ( !g_captureWindow
)
1655 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1657 // reset the event object and id in case win changed.
1658 event
.SetEventObject( win
);
1659 event
.SetId( win
->GetId() );
1661 if (win
->GetEventHandler()->ProcessEvent( event
))
1663 g_signal_stop_emission_by_name (widget
, "button_release_event");
1671 //-----------------------------------------------------------------------------
1672 // "motion_notify_event"
1673 //-----------------------------------------------------------------------------
1677 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1678 GdkEventMotion
*gdk_event
,
1684 wxapp_install_idle_handler();
1686 if (!win
->m_hasVMT
) return FALSE
;
1687 if (g_blockEventsOnDrag
) return FALSE
;
1688 if (g_blockEventsOnScroll
) return FALSE
;
1690 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1692 if (gdk_event
->is_hint
)
1696 GdkModifierType state
;
1697 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1703 printf( "OnMotion from " );
1704 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1705 printf( win->GetClassInfo()->GetClassName() );
1709 wxMouseEvent
event( wxEVT_MOTION
);
1710 InitMouseEvent(win
, event
, gdk_event
);
1712 if ( g_captureWindow
)
1714 // synthesise a mouse enter or leave event if needed
1715 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1716 // This seems to be necessary and actually been added to
1717 // GDK itself in version 2.0.X
1720 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1721 if ( hasMouse
!= g_captureWindowHasMouse
)
1723 // the mouse changed window
1724 g_captureWindowHasMouse
= hasMouse
;
1726 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1727 : wxEVT_LEAVE_WINDOW
);
1728 InitMouseEvent(win
, eventM
, gdk_event
);
1729 eventM
.SetEventObject(win
);
1730 win
->GetEventHandler()->ProcessEvent(eventM
);
1735 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1737 // reset the event object and id in case win changed.
1738 event
.SetEventObject( win
);
1739 event
.SetId( win
->GetId() );
1742 if ( !g_captureWindow
)
1744 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1745 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1747 // Rewrite cursor handling here (away from idle).
1751 if (win
->GetEventHandler()->ProcessEvent( event
))
1753 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1761 //-----------------------------------------------------------------------------
1762 // "scroll_event", (mouse wheel event)
1763 //-----------------------------------------------------------------------------
1767 window_scroll_event(GtkWidget
*, GdkEventScroll
* gdk_event
, wxWindow
* win
)
1772 wxapp_install_idle_handler();
1774 if (gdk_event
->direction
!= GDK_SCROLL_UP
&&
1775 gdk_event
->direction
!= GDK_SCROLL_DOWN
)
1780 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
1781 // Can't use InitMouse macro because scroll events don't have button
1782 event
.SetTimestamp( gdk_event
->time
);
1783 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1784 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1785 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1786 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1787 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1788 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1789 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1790 event
.m_linesPerAction
= 3;
1791 event
.m_wheelDelta
= 120;
1792 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1793 event
.m_wheelRotation
= 120;
1795 event
.m_wheelRotation
= -120;
1797 wxPoint pt
= win
->GetClientAreaOrigin();
1798 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1799 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1801 event
.SetEventObject( win
);
1802 event
.SetId( win
->GetId() );
1803 event
.SetTimestamp( gdk_event
->time
);
1805 return win
->GetEventHandler()->ProcessEvent(event
);
1809 //-----------------------------------------------------------------------------
1811 //-----------------------------------------------------------------------------
1813 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1815 wxContextMenuEvent
event(
1819 event
.SetEventObject(win
);
1820 return win
->GetEventHandler()->ProcessEvent(event
);
1824 //-----------------------------------------------------------------------------
1826 //-----------------------------------------------------------------------------
1828 // send the wxChildFocusEvent and wxFocusEvent, common code of
1829 // gtk_window_focus_in_callback() and SetFocus()
1830 static bool DoSendFocusEvents(wxWindow
*win
)
1832 // Notify the parent keeping track of focus for the kbd navigation
1833 // purposes that we got it.
1834 wxChildFocusEvent
eventChildFocus(win
);
1835 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1837 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1838 eventFocus
.SetEventObject(win
);
1840 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1845 gtk_window_focus_in_callback( GtkWidget
*widget
,
1846 GdkEventFocus
*WXUNUSED(event
),
1852 wxapp_install_idle_handler();
1855 gtk_im_context_focus_in(win
->m_imData
->context
);
1858 g_focusWindow
= win
;
1860 wxLogTrace(TRACE_FOCUS
,
1861 _T("%s: focus in"), win
->GetName().c_str());
1865 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1869 // caret needs to be informed about focus change
1870 wxCaret
*caret
= win
->GetCaret();
1873 caret
->OnSetFocus();
1875 #endif // wxUSE_CARET
1877 gboolean ret
= FALSE
;
1879 // does the window itself think that it has the focus?
1880 if ( !win
->m_hasFocus
)
1882 // not yet, notify it
1883 win
->m_hasFocus
= true;
1885 (void)DoSendFocusEvents(win
);
1890 // Disable default focus handling for custom windows
1891 // since the default GTK+ handler issues a repaint
1892 if (win
->m_wxwindow
)
1899 //-----------------------------------------------------------------------------
1900 // "focus_out_event"
1901 //-----------------------------------------------------------------------------
1905 gtk_window_focus_out_callback( GtkWidget
*widget
,
1906 GdkEventFocus
*gdk_event
,
1912 wxapp_install_idle_handler();
1915 gtk_im_context_focus_out(win
->m_imData
->context
);
1917 wxLogTrace( TRACE_FOCUS
,
1918 _T("%s: focus out"), win
->GetName().c_str() );
1921 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1925 g_focusWindow
= (wxWindowGTK
*)NULL
;
1933 // caret needs to be informed about focus change
1934 wxCaret
*caret
= win
->GetCaret();
1937 caret
->OnKillFocus();
1939 #endif // wxUSE_CARET
1941 gboolean ret
= FALSE
;
1943 // don't send the window a kill focus event if it thinks that it doesn't
1944 // have focus already
1945 if ( win
->m_hasFocus
)
1947 win
->m_hasFocus
= false;
1949 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1950 event
.SetEventObject( win
);
1952 (void)win
->GetEventHandler()->ProcessEvent( event
);
1957 // Disable default focus handling for custom windows
1958 // since the default GTK+ handler issues a repaint
1959 if (win
->m_wxwindow
)
1966 //-----------------------------------------------------------------------------
1967 // "enter_notify_event"
1968 //-----------------------------------------------------------------------------
1972 gtk_window_enter_callback( GtkWidget
*widget
,
1973 GdkEventCrossing
*gdk_event
,
1979 wxapp_install_idle_handler();
1981 if (!win
->m_hasVMT
) return FALSE
;
1982 if (g_blockEventsOnDrag
) return FALSE
;
1984 // Event was emitted after a grab
1985 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1987 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1991 GdkModifierType state
= (GdkModifierType
)0;
1993 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1995 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1996 InitMouseEvent(win
, event
, gdk_event
);
1997 wxPoint pt
= win
->GetClientAreaOrigin();
1998 event
.m_x
= x
+ pt
.x
;
1999 event
.m_y
= y
+ pt
.y
;
2001 if ( !g_captureWindow
)
2003 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2004 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2006 // Rewrite cursor handling here (away from idle).
2010 if (win
->GetEventHandler()->ProcessEvent( event
))
2012 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2020 //-----------------------------------------------------------------------------
2021 // "leave_notify_event"
2022 //-----------------------------------------------------------------------------
2026 gtk_window_leave_callback( GtkWidget
*widget
,
2027 GdkEventCrossing
*gdk_event
,
2033 wxapp_install_idle_handler();
2035 if (!win
->m_hasVMT
) return FALSE
;
2036 if (g_blockEventsOnDrag
) return FALSE
;
2038 // Event was emitted after an ungrab
2039 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2041 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2043 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2044 event
.SetTimestamp( gdk_event
->time
);
2045 event
.SetEventObject( win
);
2049 GdkModifierType state
= (GdkModifierType
)0;
2051 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2053 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2054 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2055 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2056 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2057 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2058 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2059 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2061 wxPoint pt
= win
->GetClientAreaOrigin();
2062 event
.m_x
= x
+ pt
.x
;
2063 event
.m_y
= y
+ pt
.y
;
2065 if (win
->GetEventHandler()->ProcessEvent( event
))
2067 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2075 //-----------------------------------------------------------------------------
2076 // "value_changed" from scrollbar
2077 //-----------------------------------------------------------------------------
2081 gtk_scrollbar_value_changed(GtkRange
* range
, wxWindow
* win
)
2083 wxEventType eventType
= win
->GetScrollEventType(range
);
2084 if (eventType
!= wxEVT_NULL
)
2086 // Convert scroll event type to scrollwin event type
2087 eventType
+= wxEVT_SCROLLWIN_TOP
- wxEVT_SCROLL_TOP
;
2089 // find the scrollbar which generated the event
2090 wxWindowGTK::ScrollDir dir
= win
->ScrollDirFromRange(range
);
2092 // generate the corresponding wx event
2093 const int orient
= win
->OrientFromScrollDir(dir
);
2094 wxScrollWinEvent
event(eventType
, win
->GetScrollPos(orient
), orient
);
2095 event
.SetEventObject(win
);
2097 win
->m_blockValueChanged
[dir
] = true;
2098 win
->GetEventHandler()->ProcessEvent(event
);
2099 win
->m_blockValueChanged
[dir
] = false;
2104 //-----------------------------------------------------------------------------
2105 // "button_press_event" from scrollbar
2106 //-----------------------------------------------------------------------------
2110 gtk_scrollbar_button_press_event(GtkRange
*, GdkEventButton
*, wxWindow
* win
)
2115 wxapp_install_idle_handler();
2117 g_blockEventsOnScroll
= true;
2118 win
->m_mouseButtonDown
= true;
2124 //-----------------------------------------------------------------------------
2125 // "event_after" from scrollbar
2126 //-----------------------------------------------------------------------------
2130 gtk_scrollbar_event_after(GtkRange
* range
, GdkEvent
* event
, wxWindow
* win
)
2132 if (event
->type
== GDK_BUTTON_RELEASE
)
2134 g_signal_handlers_block_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
2136 const int orient
= win
->OrientFromScrollDir(
2137 win
->ScrollDirFromRange(range
));
2138 wxScrollWinEvent
event(wxEVT_SCROLLWIN_THUMBRELEASE
, win
->GetScrollPos(orient
), orient
);
2139 event
.SetEventObject(win
);
2140 win
->GetEventHandler()->ProcessEvent(event
);
2145 //-----------------------------------------------------------------------------
2146 // "button_release_event" from scrollbar
2147 //-----------------------------------------------------------------------------
2151 gtk_scrollbar_button_release_event(GtkRange
* range
, GdkEventButton
*, wxWindow
* win
)
2155 g_blockEventsOnScroll
= false;
2156 win
->m_mouseButtonDown
= false;
2157 // If thumb tracking
2158 if (win
->m_isScrolling
)
2160 win
->m_isScrolling
= false;
2161 // Hook up handler to send thumb release event after this emission is finished.
2162 // To allow setting scroll position from event handler, sending event must
2163 // be deferred until after the GtkRange handler for this signal has run
2164 g_signal_handlers_unblock_by_func(range
, (void*)gtk_scrollbar_event_after
, win
);
2171 // ----------------------------------------------------------------------------
2172 // this wxWindowBase function is implemented here (in platform-specific file)
2173 // because it is static and so couldn't be made virtual
2174 // ----------------------------------------------------------------------------
2176 wxWindow
*wxWindowBase::DoFindFocus()
2178 // the cast is necessary when we compile in wxUniversal mode
2179 return (wxWindow
*)g_focusWindow
;
2182 //-----------------------------------------------------------------------------
2183 // "realize" from m_widget
2184 //-----------------------------------------------------------------------------
2186 /* We cannot set colours and fonts before the widget has
2187 been realized, so we do this directly after realization. */
2191 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2196 wxapp_install_idle_handler();
2200 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2201 gtk_im_context_set_client_window( win
->m_imData
->context
,
2202 pizza
->bin_window
);
2205 wxWindowCreateEvent
event( win
);
2206 event
.SetEventObject( win
);
2207 win
->GetEventHandler()->ProcessEvent( event
);
2211 //-----------------------------------------------------------------------------
2213 //-----------------------------------------------------------------------------
2217 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2218 GtkAllocation
*WXUNUSED(alloc
),
2222 wxapp_install_idle_handler();
2224 int client_width
= 0;
2225 int client_height
= 0;
2226 win
->GetClientSize( &client_width
, &client_height
);
2227 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2230 win
->m_oldClientWidth
= client_width
;
2231 win
->m_oldClientHeight
= client_height
;
2233 if (!win
->m_nativeSizeEvent
)
2235 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2236 event
.SetEventObject( win
);
2237 win
->GetEventHandler()->ProcessEvent( event
);
2244 #define WXUNUSED_UNLESS_XIM(param) param
2246 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2249 /* Resize XIM window */
2253 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2254 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2255 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2258 wxapp_install_idle_handler();
2264 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2268 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2269 win
->m_icattr
->preedit_area
.width
= width
;
2270 win
->m_icattr
->preedit_area
.height
= height
;
2271 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2277 //-----------------------------------------------------------------------------
2278 // "realize" from m_wxwindow
2279 //-----------------------------------------------------------------------------
2281 /* Initialize XIM support */
2285 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2286 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2289 wxapp_install_idle_handler();
2292 if (win
->m_ic
) return;
2293 if (!widget
) return;
2294 if (!gdk_im_ready()) return;
2296 win
->m_icattr
= gdk_ic_attr_new();
2297 if (!win
->m_icattr
) return;
2301 GdkColormap
*colormap
;
2302 GdkICAttr
*attr
= win
->m_icattr
;
2303 unsigned attrmask
= GDK_IC_ALL_REQ
;
2305 GdkIMStyle supported_style
= (GdkIMStyle
)
2306 (GDK_IM_PREEDIT_NONE
|
2307 GDK_IM_PREEDIT_NOTHING
|
2308 GDK_IM_PREEDIT_POSITION
|
2309 GDK_IM_STATUS_NONE
|
2310 GDK_IM_STATUS_NOTHING
);
2312 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2313 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2315 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2316 attr
->client_window
= widget
->window
;
2318 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2319 gtk_widget_get_default_colormap ())
2321 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2322 attr
->preedit_colormap
= colormap
;
2325 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2326 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2327 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2328 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2330 switch (style
& GDK_IM_PREEDIT_MASK
)
2332 case GDK_IM_PREEDIT_POSITION
:
2333 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2335 g_warning ("over-the-spot style requires fontset");
2339 gdk_drawable_get_size (widget
->window
, &width
, &height
);
2341 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2342 attr
->spot_location
.x
= 0;
2343 attr
->spot_location
.y
= height
;
2344 attr
->preedit_area
.x
= 0;
2345 attr
->preedit_area
.y
= 0;
2346 attr
->preedit_area
.width
= width
;
2347 attr
->preedit_area
.height
= height
;
2348 attr
->preedit_fontset
= widget
->style
->font
;
2353 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2355 if (win
->m_ic
== NULL
)
2356 g_warning ("Can't create input context.");
2359 mask
= gdk_window_get_events (widget
->window
);
2360 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2361 gdk_window_set_events (widget
->window
, mask
);
2363 if (GTK_WIDGET_HAS_FOCUS(widget
))
2364 gdk_im_begin (win
->m_ic
, widget
->window
);
2370 //-----------------------------------------------------------------------------
2371 // InsertChild for wxWindowGTK.
2372 //-----------------------------------------------------------------------------
2374 /* Callback for wxWindowGTK. This very strange beast has to be used because
2375 * C++ has no virtual methods in a constructor. We have to emulate a
2376 * virtual function here as wxNotebook requires a different way to insert
2377 * a child in it. I had opted for creating a wxNotebookPage window class
2378 * which would have made this superfluous (such in the MDI window system),
2379 * but no-one was listening to me... */
2381 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2383 /* the window might have been scrolled already, do we
2384 have to adapt the position */
2385 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2386 child
->m_x
+= pizza
->xoffset
;
2387 child
->m_y
+= pizza
->yoffset
;
2389 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2390 GTK_WIDGET(child
->m_widget
),
2397 //-----------------------------------------------------------------------------
2399 //-----------------------------------------------------------------------------
2401 wxWindow
*wxGetActiveWindow()
2403 return wxWindow::FindFocus();
2407 wxMouseState
wxGetMouseState()
2413 GdkModifierType mask
;
2415 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2419 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2420 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2421 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2423 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2424 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2425 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2426 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2431 //-----------------------------------------------------------------------------
2433 //-----------------------------------------------------------------------------
2435 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2437 #ifdef __WXUNIVERSAL__
2438 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2440 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2441 #endif // __WXUNIVERSAL__/__WXGTK__
2443 void wxWindowGTK::Init()
2446 m_widget
= (GtkWidget
*) NULL
;
2447 m_wxwindow
= (GtkWidget
*) NULL
;
2448 m_focusWidget
= (GtkWidget
*) NULL
;
2458 m_needParent
= true;
2459 m_isBeingDeleted
= false;
2461 m_showOnIdle
= false;
2464 m_nativeSizeEvent
= false;
2466 m_hasScrolling
= false;
2467 m_isScrolling
= false;
2468 m_mouseButtonDown
= false;
2469 m_blockScrollEvent
= false;
2471 // initialize scrolling stuff
2472 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2474 m_scrollBar
[dir
] = NULL
;
2475 m_scrollPos
[dir
] = 0;
2476 m_blockValueChanged
[dir
] = false;
2480 m_oldClientHeight
= 0;
2484 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2486 m_acceptsFocus
= false;
2489 m_clipPaintRegion
= false;
2491 m_needsStyleChange
= false;
2493 m_cursor
= *wxSTANDARD_CURSOR
;
2496 m_dirtyTabOrder
= false;
2499 wxWindowGTK::wxWindowGTK()
2504 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2509 const wxString
&name
)
2513 Create( parent
, id
, pos
, size
, style
, name
);
2516 bool wxWindowGTK::Create( wxWindow
*parent
,
2521 const wxString
&name
)
2523 if (!PreCreation( parent
, pos
, size
) ||
2524 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2526 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2530 m_insertCallback
= wxInsertChildInWindow
;
2532 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2533 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2535 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2537 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2538 scroll_class
->scrollbar_spacing
= 0;
2540 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2542 m_scrollBar
[ScrollDir_Horz
] = GTK_RANGE(scrolledWindow
->hscrollbar
);
2543 m_scrollBar
[ScrollDir_Vert
] = GTK_RANGE(scrolledWindow
->vscrollbar
);
2545 m_wxwindow
= gtk_pizza_new();
2547 #ifndef __WXUNIVERSAL__
2548 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2550 if (HasFlag(wxRAISED_BORDER
))
2552 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2554 else if (HasFlag(wxSUNKEN_BORDER
))
2556 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2558 else if (HasFlag(wxSIMPLE_BORDER
))
2560 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2564 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2566 #endif // __WXUNIVERSAL__
2568 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2570 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2571 m_acceptsFocus
= true;
2573 // connect various scroll-related events
2574 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
2576 // these handlers block mouse events to any window during scrolling
2577 // such as motion events and prevent GTK and wxWidgets from fighting
2578 // over where the slider should be
2579 g_signal_connect(m_scrollBar
[dir
], "button_press_event",
2580 G_CALLBACK(gtk_scrollbar_button_press_event
), this);
2581 g_signal_connect(m_scrollBar
[dir
], "button_release_event",
2582 G_CALLBACK(gtk_scrollbar_button_release_event
), this);
2584 gulong handler_id
= g_signal_connect(m_scrollBar
[dir
], "event_after",
2585 G_CALLBACK(gtk_scrollbar_event_after
), this);
2586 g_signal_handler_block(m_scrollBar
[dir
], handler_id
);
2588 // these handlers get notified when scrollbar slider moves
2589 g_signal_connect(m_scrollBar
[dir
], "value_changed",
2590 G_CALLBACK(gtk_scrollbar_value_changed
), this);
2593 gtk_widget_show( m_wxwindow
);
2596 m_parent
->DoAddChild( this );
2598 m_focusWidget
= m_wxwindow
;
2605 wxWindowGTK::~wxWindowGTK()
2609 if (g_focusWindow
== this)
2610 g_focusWindow
= NULL
;
2612 if ( g_delayedFocus
== this )
2613 g_delayedFocus
= NULL
;
2615 m_isBeingDeleted
= true;
2618 // destroy children before destroying this window itself
2621 // unhook focus handlers to prevent stray events being
2622 // propagated to this (soon to be) dead object
2623 if (m_focusWidget
!= NULL
)
2625 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2626 (gpointer
) gtk_window_focus_in_callback
,
2628 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2629 (gpointer
) gtk_window_focus_out_callback
,
2638 gdk_ic_destroy (m_ic
);
2640 gdk_ic_attr_destroy (m_icattr
);
2643 // delete before the widgets to avoid a crash on solaris
2648 gtk_widget_destroy( m_wxwindow
);
2649 m_wxwindow
= (GtkWidget
*) NULL
;
2654 gtk_widget_destroy( m_widget
);
2655 m_widget
= (GtkWidget
*) NULL
;
2659 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2661 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2663 // Use either the given size, or the default if -1 is given.
2664 // See wxWindowBase for these functions.
2665 m_width
= WidthDefault(size
.x
) ;
2666 m_height
= HeightDefault(size
.y
);
2674 void wxWindowGTK::PostCreation()
2676 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2682 // these get reported to wxWidgets -> wxPaintEvent
2684 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2686 g_signal_connect (m_wxwindow
, "expose_event",
2687 G_CALLBACK (gtk_window_expose_callback
), this);
2689 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2692 // Create input method handler
2693 m_imData
= new wxGtkIMData
;
2695 // Cannot handle drawing preedited text yet
2696 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2698 g_signal_connect (m_imData
->context
, "commit",
2699 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2701 // these are called when the "sunken" or "raised" borders are drawn
2702 g_signal_connect (m_widget
, "expose_event",
2703 G_CALLBACK (gtk_window_own_expose_callback
), this);
2708 if (!GTK_IS_WINDOW(m_widget
))
2710 if (m_focusWidget
== NULL
)
2711 m_focusWidget
= m_widget
;
2715 g_signal_connect (m_focusWidget
, "focus_in_event",
2716 G_CALLBACK (gtk_window_focus_in_callback
), this);
2717 g_signal_connect (m_focusWidget
, "focus_out_event",
2718 G_CALLBACK (gtk_window_focus_out_callback
), this);
2722 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2723 G_CALLBACK (gtk_window_focus_in_callback
), this);
2724 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2725 G_CALLBACK (gtk_window_focus_out_callback
), this);
2729 // connect to the various key and mouse handlers
2731 GtkWidget
*connect_widget
= GetConnectWidget();
2733 ConnectWidget( connect_widget
);
2735 /* We cannot set colours, fonts and cursors before the widget has
2736 been realized, so we do this directly after realization */
2737 g_signal_connect (connect_widget
, "realize",
2738 G_CALLBACK (gtk_window_realized_callback
), this);
2742 // Catch native resize events
2743 g_signal_connect (m_wxwindow
, "size_allocate",
2744 G_CALLBACK (gtk_window_size_callback
), this);
2746 // Initialize XIM support
2747 g_signal_connect (m_wxwindow
, "realize",
2748 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2750 // And resize XIM window
2751 g_signal_connect (m_wxwindow
, "size_allocate",
2752 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2755 if (GTK_IS_COMBO(m_widget
))
2757 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2759 g_signal_connect (gcombo
->entry
, "size_request",
2760 G_CALLBACK (wxgtk_combo_size_request_callback
),
2763 #ifdef GTK_IS_FILE_CHOOSER_BUTTON
2764 else if (GTK_IS_FILE_CHOOSER_BUTTON(m_widget
))
2766 // If we connect to the "size_request" signal of a GtkFileChooserButton
2767 // then that control won't be sized properly when placed inside sizers
2768 // (this can be tested removing this elseif and running XRC or WIDGETS samples)
2769 // FIXME: what should be done here ?
2774 // This is needed if we want to add our windows into native
2775 // GTK controls, such as the toolbar. With this callback, the
2776 // toolbar gets to know the correct size (the one set by the
2777 // programmer). Sadly, it misbehaves for wxComboBox.
2778 g_signal_connect (m_widget
, "size_request",
2779 G_CALLBACK (wxgtk_window_size_request_callback
),
2783 InheritAttributes();
2787 // unless the window was created initially hidden (i.e. Hide() had been
2788 // called before Create()), we should show it at GTK+ level as well
2790 gtk_widget_show( m_widget
);
2793 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2795 g_signal_connect (widget
, "key_press_event",
2796 G_CALLBACK (gtk_window_key_press_callback
), this);
2797 g_signal_connect (widget
, "key_release_event",
2798 G_CALLBACK (gtk_window_key_release_callback
), this);
2799 g_signal_connect (widget
, "button_press_event",
2800 G_CALLBACK (gtk_window_button_press_callback
), this);
2801 g_signal_connect (widget
, "button_release_event",
2802 G_CALLBACK (gtk_window_button_release_callback
), this);
2803 g_signal_connect (widget
, "motion_notify_event",
2804 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2805 g_signal_connect (widget
, "scroll_event",
2806 G_CALLBACK (window_scroll_event
), this);
2807 g_signal_connect (widget
, "popup_menu",
2808 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2809 g_signal_connect (widget
, "enter_notify_event",
2810 G_CALLBACK (gtk_window_enter_callback
), this);
2811 g_signal_connect (widget
, "leave_notify_event",
2812 G_CALLBACK (gtk_window_leave_callback
), this);
2815 bool wxWindowGTK::Destroy()
2817 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2821 return wxWindowBase::Destroy();
2824 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2826 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2829 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2831 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2832 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2835 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2838 if (m_resizing
) return; /* I don't like recursions */
2841 int currentX
, currentY
;
2842 GetPosition(¤tX
, ¤tY
);
2843 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2845 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2847 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2849 // calculate the best size if we should auto size the window
2850 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2851 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2853 const wxSize sizeBest
= GetBestSize();
2854 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2856 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2857 height
= sizeBest
.y
;
2865 int minWidth
= GetMinWidth(),
2866 minHeight
= GetMinHeight(),
2867 maxWidth
= GetMaxWidth(),
2868 maxHeight
= GetMaxHeight();
2870 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2871 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2872 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2873 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2875 #if wxUSE_TOOLBAR_NATIVE
2876 if (wxDynamicCast(GetParent(), wxToolBar
))
2878 // don't take the x,y values, they're wrong because toolbar sets them
2879 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2880 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2881 if (GTK_WIDGET_VISIBLE (widget
))
2882 gtk_widget_queue_resize (widget
);
2886 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2888 // don't set the size for children of wxNotebook, just take the values.
2896 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2897 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2899 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2900 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2904 m_x
= x
+ pizza
->xoffset
;
2905 m_y
= y
+ pizza
->yoffset
;
2908 int left_border
= 0;
2909 int right_border
= 0;
2911 int bottom_border
= 0;
2913 /* the default button has a border around it */
2914 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2916 GtkBorder
*default_border
= NULL
;
2917 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2920 left_border
+= default_border
->left
;
2921 right_border
+= default_border
->right
;
2922 top_border
+= default_border
->top
;
2923 bottom_border
+= default_border
->bottom
;
2924 g_free( default_border
);
2928 DoMoveWindow( m_x
-top_border
,
2930 m_width
+left_border
+right_border
,
2931 m_height
+top_border
+bottom_border
);
2936 /* Sometimes the client area changes size without the
2937 whole windows's size changing, but if the whole
2938 windows's size doesn't change, no wxSizeEvent will
2939 normally be sent. Here we add an extra test if
2940 the client test has been changed and this will
2942 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2946 wxPrintf( "OnSize sent from " );
2947 if (GetClassInfo() && GetClassInfo()->GetClassName())
2948 wxPrintf( GetClassInfo()->GetClassName() );
2949 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2952 if (!m_nativeSizeEvent
)
2954 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2955 event
.SetEventObject( this );
2956 GetEventHandler()->ProcessEvent( event
);
2962 void wxWindowGTK::OnInternalIdle()
2964 if ( m_dirtyTabOrder
)
2966 m_dirtyTabOrder
= false;
2970 // Update style if the window was not yet realized
2971 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2972 if (m_needsStyleChange
)
2974 SetBackgroundStyle(GetBackgroundStyle());
2975 m_needsStyleChange
= false;
2978 if (IsShown() && m_showOnIdle
&& !GTK_WIDGET_VISIBLE (m_widget
))
2980 GtkAllocation alloc
;
2983 alloc
.width
= m_width
;
2984 alloc
.height
= m_height
;
2985 gtk_widget_size_allocate( m_widget
, &alloc
);
2986 gtk_widget_show( m_widget
);
2987 wxShowEvent
eventShow(GetId(), true);
2988 eventShow
.SetEventObject(this);
2989 GetEventHandler()->ProcessEvent(eventShow
);
2990 m_showOnIdle
= false;
2993 // Update invalidated regions.
2996 wxCursor cursor
= m_cursor
;
2997 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3001 /* I now set the cursor anew in every OnInternalIdle call
3002 as setting the cursor in a parent window also effects the
3003 windows above so that checking for the current cursor is
3008 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3010 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3012 if (!g_globalCursor
.Ok())
3013 cursor
= *wxSTANDARD_CURSOR
;
3015 window
= m_widget
->window
;
3016 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3017 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3020 else if ( m_widget
)
3022 GdkWindow
*window
= m_widget
->window
;
3023 if ( window
&& !GTK_WIDGET_NO_WINDOW(m_widget
) )
3024 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3028 if (wxUpdateUIEvent::CanUpdate(this))
3029 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3032 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3034 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3036 if (width
) (*width
) = m_width
;
3037 if (height
) (*height
) = m_height
;
3040 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3042 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3051 GetScrollbarWidth(m_widget
, dw
, dh
);
3054 #ifndef __WXUNIVERSAL__
3055 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3057 // shadow border size is 2
3061 if (HasFlag(wxSIMPLE_BORDER
))
3063 // simple border size is 1
3067 #endif // __WXUNIVERSAL__
3073 SetSize(width
, height
);
3076 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3078 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3090 GetScrollbarWidth(m_widget
, dw
, dh
);
3093 #ifndef __WXUNIVERSAL__
3094 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3096 // shadow border size is 2
3100 if (HasFlag(wxSIMPLE_BORDER
))
3102 // simple border size is 1
3106 #endif // __WXUNIVERSAL__
3112 if (width
) *width
= w
;
3113 if (height
) *height
= h
;
3116 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3118 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3122 if (m_parent
&& m_parent
->m_wxwindow
)
3124 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3125 dx
= pizza
->xoffset
;
3126 dy
= pizza
->yoffset
;
3129 if (x
) (*x
) = m_x
- dx
;
3130 if (y
) (*y
) = m_y
- dy
;
3133 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3135 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3137 if (!m_widget
->window
) return;
3139 GdkWindow
*source
= (GdkWindow
*) NULL
;
3141 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3143 source
= m_widget
->window
;
3147 gdk_window_get_origin( source
, &org_x
, &org_y
);
3151 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3153 org_x
+= m_widget
->allocation
.x
;
3154 org_y
+= m_widget
->allocation
.y
;
3162 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3164 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3166 if (!m_widget
->window
) return;
3168 GdkWindow
*source
= (GdkWindow
*) NULL
;
3170 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3172 source
= m_widget
->window
;
3176 gdk_window_get_origin( source
, &org_x
, &org_y
);
3180 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3182 org_x
+= m_widget
->allocation
.x
;
3183 org_y
+= m_widget
->allocation
.y
;
3191 bool wxWindowGTK::Show( bool show
)
3193 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3195 if (!wxWindowBase::Show(show
))
3205 gtk_widget_show( m_widget
);
3206 wxShowEvent
eventShow(GetId(), show
);
3207 eventShow
.SetEventObject(this);
3208 GetEventHandler()->ProcessEvent(eventShow
);
3213 gtk_widget_hide( m_widget
);
3214 wxShowEvent
eventShow(GetId(), show
);
3215 eventShow
.SetEventObject(this);
3216 GetEventHandler()->ProcessEvent(eventShow
);
3222 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3224 win
->OnParentEnable(enable
);
3226 // Recurse, so that children have the opportunity to Do The Right Thing
3227 // and reset colours that have been messed up by a parent's (really ancestor's)
3229 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3231 node
= node
->GetNext() )
3233 wxWindow
*child
= node
->GetData();
3234 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3235 wxWindowNotifyEnable(child
, enable
);
3239 bool wxWindowGTK::Enable( bool enable
)
3241 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3243 if (!wxWindowBase::Enable(enable
))
3249 gtk_widget_set_sensitive( m_widget
, enable
);
3251 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3253 wxWindowNotifyEnable(this, enable
);
3258 int wxWindowGTK::GetCharHeight() const
3260 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3262 wxFont font
= GetFont();
3263 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3265 PangoContext
*context
= NULL
;
3267 context
= gtk_widget_get_pango_context( m_widget
);
3272 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3273 PangoLayout
*layout
= pango_layout_new(context
);
3274 pango_layout_set_font_description(layout
, desc
);
3275 pango_layout_set_text(layout
, "H", 1);
3276 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3278 PangoRectangle rect
;
3279 pango_layout_line_get_extents(line
, NULL
, &rect
);
3281 g_object_unref (layout
);
3283 return (int) PANGO_PIXELS(rect
.height
);
3286 int wxWindowGTK::GetCharWidth() const
3288 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3290 wxFont font
= GetFont();
3291 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3293 PangoContext
*context
= NULL
;
3295 context
= gtk_widget_get_pango_context( m_widget
);
3300 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3301 PangoLayout
*layout
= pango_layout_new(context
);
3302 pango_layout_set_font_description(layout
, desc
);
3303 pango_layout_set_text(layout
, "g", 1);
3304 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3306 PangoRectangle rect
;
3307 pango_layout_line_get_extents(line
, NULL
, &rect
);
3309 g_object_unref (layout
);
3311 return (int) PANGO_PIXELS(rect
.width
);
3314 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3318 int *externalLeading
,
3319 const wxFont
*theFont
) const
3321 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3323 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3332 PangoContext
*context
= NULL
;
3334 context
= gtk_widget_get_pango_context( m_widget
);
3343 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3344 PangoLayout
*layout
= pango_layout_new(context
);
3345 pango_layout_set_font_description(layout
, desc
);
3347 const wxCharBuffer data
= wxGTK_CONV( string
);
3349 pango_layout_set_text(layout
, data
, strlen(data
));
3352 PangoRectangle rect
;
3353 pango_layout_get_extents(layout
, NULL
, &rect
);
3355 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3356 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3359 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3360 int baseline
= pango_layout_iter_get_baseline(iter
);
3361 pango_layout_iter_free(iter
);
3362 *descent
= *y
- PANGO_PIXELS(baseline
);
3364 if (externalLeading
) (*externalLeading
) = 0; // ??
3366 g_object_unref (layout
);
3369 void wxWindowGTK::SetFocus()
3371 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3374 // don't do anything if we already have focus
3380 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3382 gtk_widget_grab_focus (m_wxwindow
);
3387 if (GTK_IS_CONTAINER(m_widget
))
3389 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3392 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3395 if (!GTK_WIDGET_REALIZED(m_widget
))
3397 // we can't set the focus to the widget now so we remember that
3398 // it should be focused and will do it later, during the idle
3399 // time, as soon as we can
3400 wxLogTrace(TRACE_FOCUS
,
3401 _T("Delaying setting focus to %s(%s)"),
3402 GetClassInfo()->GetClassName(), GetLabel().c_str());
3404 g_delayedFocus
= this;
3408 wxLogTrace(TRACE_FOCUS
,
3409 _T("Setting focus to %s(%s)"),
3410 GetClassInfo()->GetClassName(), GetLabel().c_str());
3412 gtk_widget_grab_focus (m_widget
);
3417 wxLogTrace(TRACE_FOCUS
,
3418 _T("Can't set focus to %s(%s)"),
3419 GetClassInfo()->GetClassName(), GetLabel().c_str());
3424 bool wxWindowGTK::AcceptsFocus() const
3426 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3429 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3431 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3433 wxWindowGTK
*oldParent
= m_parent
,
3434 *newParent
= (wxWindowGTK
*)newParentBase
;
3436 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3438 if ( !wxWindowBase::Reparent(newParent
) )
3441 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3443 /* prevent GTK from deleting the widget arbitrarily */
3444 gtk_widget_ref( m_widget
);
3448 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3451 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3455 if (GTK_WIDGET_VISIBLE (newParent
->m_widget
))
3457 m_showOnIdle
= true;
3458 gtk_widget_hide( m_widget
);
3461 /* insert GTK representation */
3462 (*(newParent
->m_insertCallback
))(newParent
, this);
3465 /* reverse: prevent GTK from deleting the widget arbitrarily */
3466 gtk_widget_unref( m_widget
);
3471 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3473 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3475 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3477 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3482 /* insert GTK representation */
3483 (*m_insertCallback
)(this, child
);
3486 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3488 wxWindowBase::AddChild(child
);
3489 m_dirtyTabOrder
= true;
3491 wxapp_install_idle_handler();
3494 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3496 wxWindowBase::RemoveChild(child
);
3497 m_dirtyTabOrder
= true;
3499 wxapp_install_idle_handler();
3502 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3504 wxWindowBase::DoMoveInTabOrder(win
, move
);
3505 m_dirtyTabOrder
= true;
3507 wxapp_install_idle_handler();
3510 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3512 // none needed by default
3516 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3518 // nothing to do by default since none is needed
3521 void wxWindowGTK::RealizeTabOrder()
3525 if ( !m_children
.empty() )
3527 // we don't only construct the correct focus chain but also use
3528 // this opportunity to update the mnemonic widgets for the widgets
3531 GList
*chain
= NULL
;
3532 wxWindowGTK
* mnemonicWindow
= NULL
;
3534 for ( wxWindowList::const_iterator i
= m_children
.begin();
3535 i
!= m_children
.end();
3538 wxWindowGTK
*win
= *i
;
3540 if ( mnemonicWindow
)
3542 if ( win
->AcceptsFocusFromKeyboard() )
3544 // wxComboBox et al. needs to focus on on a different
3545 // widget than m_widget, so if the main widget isn't
3546 // focusable try the connect widget
3547 GtkWidget
* w
= win
->m_widget
;
3548 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3550 w
= win
->GetConnectWidget();
3551 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3557 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3558 mnemonicWindow
= NULL
;
3562 else if ( win
->GTKWidgetNeedsMnemonic() )
3564 mnemonicWindow
= win
;
3567 chain
= g_list_prepend(chain
, win
->m_widget
);
3570 chain
= g_list_reverse(chain
);
3572 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3577 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3582 void wxWindowGTK::Raise()
3584 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3586 if (m_wxwindow
&& m_wxwindow
->window
)
3588 gdk_window_raise( m_wxwindow
->window
);
3590 else if (m_widget
->window
)
3592 gdk_window_raise( m_widget
->window
);
3596 void wxWindowGTK::Lower()
3598 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3600 if (m_wxwindow
&& m_wxwindow
->window
)
3602 gdk_window_lower( m_wxwindow
->window
);
3604 else if (m_widget
->window
)
3606 gdk_window_lower( m_widget
->window
);
3610 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3612 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3614 if (cursor
== m_cursor
)
3618 wxapp_install_idle_handler();
3620 if (cursor
== wxNullCursor
)
3621 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3623 return wxWindowBase::SetCursor( cursor
);
3626 void wxWindowGTK::WarpPointer( int x
, int y
)
3628 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3630 // We provide this function ourselves as it is
3631 // missing in GDK (top of this file).
3633 GdkWindow
*window
= (GdkWindow
*) NULL
;
3635 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3637 window
= GetConnectWidget()->window
;
3640 gdk_window_warp_pointer( window
, x
, y
);
3643 wxWindowGTK::ScrollDir
wxWindowGTK::ScrollDirFromRange(GtkRange
*range
) const
3645 // find the scrollbar which generated the event
3646 for ( int dir
= 0; dir
< ScrollDir_Max
; dir
++ )
3648 if ( range
== m_scrollBar
[dir
] )
3649 return (ScrollDir
)dir
;
3652 wxFAIL_MSG( _T("event from unknown scrollbar received") );
3654 return ScrollDir_Max
;
3657 bool wxWindowGTK::DoScrollByUnits(ScrollDir dir
, ScrollUnit unit
, int units
)
3659 bool changed
= false;
3660 GtkRange
* range
= m_scrollBar
[dir
];
3661 if ( range
&& units
)
3663 GtkAdjustment
* adj
= range
->adjustment
;
3664 gdouble inc
= unit
== ScrollUnit_Line
? adj
->step_increment
3665 : adj
->page_increment
;
3667 const int posOld
= int(adj
->value
+ 0.5);
3668 gtk_range_set_value(range
, posOld
+ units
*inc
);
3670 changed
= int(adj
->value
+ 0.5) != posOld
;
3676 bool wxWindowGTK::ScrollLines(int lines
)
3678 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Line
, lines
);
3681 bool wxWindowGTK::ScrollPages(int pages
)
3683 return DoScrollByUnits(ScrollDir_Vert
, ScrollUnit_Page
, pages
);
3686 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3690 if (!m_widget
->window
)
3695 if (!GTK_PIZZA(m_wxwindow
)->bin_window
) return;
3697 GdkRectangle gdk_rect
,
3701 gdk_rect
.x
= rect
->x
;
3702 gdk_rect
.y
= rect
->y
;
3703 gdk_rect
.width
= rect
->width
;
3704 gdk_rect
.height
= rect
->height
;
3707 else // invalidate everything
3712 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3716 void wxWindowGTK::Update()
3720 // when we call Update() we really want to update the window immediately on
3721 // screen, even if it means flushing the entire queue and hence slowing down
3722 // everything -- but it should still be done, it's just that Update() should
3723 // be called very rarely
3727 void wxWindowGTK::GtkUpdate()
3729 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3730 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3731 if (m_widget
&& m_widget
->window
)
3732 gdk_window_process_updates( m_widget
->window
, FALSE
);
3734 // for consistency with other platforms (and also because it's convenient
3735 // to be able to update an entire TLW by calling Update() only once), we
3736 // should also update all our children here
3737 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3739 node
= node
->GetNext() )
3741 node
->GetData()->GtkUpdate();
3745 void wxWindowGTK::GtkSendPaintEvents()
3749 m_updateRegion
.Clear();
3753 // Clip to paint region in wxClientDC
3754 m_clipPaintRegion
= true;
3756 // widget to draw on
3757 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3759 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3761 // find ancestor from which to steal background
3762 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3764 parent
= (wxWindow
*)this;
3766 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3768 wxRegionIterator
upd( m_updateRegion
);
3772 rect
.x
= upd
.GetX();
3773 rect
.y
= upd
.GetY();
3774 rect
.width
= upd
.GetWidth();
3775 rect
.height
= upd
.GetHeight();
3777 gtk_paint_flat_box( parent
->m_widget
->style
,
3779 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3793 wxWindowDC
dc( (wxWindow
*)this );
3794 dc
.SetClippingRegion( m_updateRegion
);
3796 wxEraseEvent
erase_event( GetId(), &dc
);
3797 erase_event
.SetEventObject( this );
3799 GetEventHandler()->ProcessEvent(erase_event
);
3802 wxNcPaintEvent
nc_paint_event( GetId() );
3803 nc_paint_event
.SetEventObject( this );
3804 GetEventHandler()->ProcessEvent( nc_paint_event
);
3806 wxPaintEvent
paint_event( GetId() );
3807 paint_event
.SetEventObject( this );
3808 GetEventHandler()->ProcessEvent( paint_event
);
3810 m_clipPaintRegion
= false;
3812 m_updateRegion
.Clear();
3815 void wxWindowGTK::SetDoubleBuffered( bool on
)
3817 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3820 gtk_widget_set_double_buffered( m_wxwindow
, on
);
3823 void wxWindowGTK::ClearBackground()
3825 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3829 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3831 wxWindowBase::DoSetToolTip(tip
);
3834 m_tooltip
->Apply( (wxWindow
*)this );
3837 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3839 wxString
tmp( tip
);
3840 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3842 #endif // wxUSE_TOOLTIPS
3844 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3846 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3848 if (!wxWindowBase::SetBackgroundColour(colour
))
3853 // We need the pixel value e.g. for background clearing.
3854 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3857 // apply style change (forceStyle=true so that new style is applied
3858 // even if the bg colour changed from valid to wxNullColour)
3859 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3860 ApplyWidgetStyle(true);
3865 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3867 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3869 if (!wxWindowBase::SetForegroundColour(colour
))
3876 // We need the pixel value e.g. for background clearing.
3877 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3880 // apply style change (forceStyle=true so that new style is applied
3881 // even if the bg colour changed from valid to wxNullColour):
3882 ApplyWidgetStyle(true);
3887 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3889 return gtk_widget_get_pango_context( m_widget
);
3892 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3894 // do we need to apply any changes at all?
3897 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3902 GtkRcStyle
*style
= gtk_rc_style_new();
3907 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3910 if ( m_foregroundColour
.Ok() )
3912 const GdkColor
*fg
= m_foregroundColour
.GetColor();
3914 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3915 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3917 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3918 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3920 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3921 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3924 if ( m_backgroundColour
.Ok() )
3926 const GdkColor
*bg
= m_backgroundColour
.GetColor();
3928 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3929 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3930 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3931 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3933 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3934 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3935 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3936 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3938 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3939 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3940 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3941 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3943 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3944 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3945 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3946 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3952 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3954 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3957 DoApplyWidgetStyle(style
);
3958 gtk_rc_style_unref(style
);
3961 // Style change may affect GTK+'s size calculation:
3962 InvalidateBestSize();
3965 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3968 gtk_widget_modify_style(m_wxwindow
, style
);
3970 gtk_widget_modify_style(m_widget
, style
);
3973 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3975 wxWindowBase::SetBackgroundStyle(style
);
3977 if (style
== wxBG_STYLE_CUSTOM
)
3979 GdkWindow
*window
= (GdkWindow
*) NULL
;
3981 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3983 window
= GetConnectWidget()->window
;
3987 // Make sure GDK/X11 doesn't refresh the window
3989 gdk_window_set_back_pixmap( window
, None
, False
);
3991 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3994 m_needsStyleChange
= false;
3997 // Do in OnIdle, because the window is not yet available
3998 m_needsStyleChange
= true;
4000 // Don't apply widget style, or we get a grey background
4004 // apply style change (forceStyle=true so that new style is applied
4005 // even if the bg colour changed from valid to wxNullColour):
4006 ApplyWidgetStyle(true);
4011 #if wxUSE_DRAG_AND_DROP
4013 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4015 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4017 GtkWidget
*dnd_widget
= GetConnectWidget();
4019 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4021 if (m_dropTarget
) delete m_dropTarget
;
4022 m_dropTarget
= dropTarget
;
4024 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4027 #endif // wxUSE_DRAG_AND_DROP
4029 GtkWidget
* wxWindowGTK::GetConnectWidget()
4031 GtkWidget
*connect_widget
= m_widget
;
4032 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4034 return connect_widget
;
4037 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4040 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4042 return (window
== m_widget
->window
);
4045 bool wxWindowGTK::SetFont( const wxFont
&font
)
4047 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4049 if (!wxWindowBase::SetFont(font
))
4052 // apply style change (forceStyle=true so that new style is applied
4053 // even if the font changed from valid to wxNullFont):
4054 ApplyWidgetStyle(true);
4059 void wxWindowGTK::DoCaptureMouse()
4061 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4063 GdkWindow
*window
= (GdkWindow
*) NULL
;
4065 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4067 window
= GetConnectWidget()->window
;
4069 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4071 const wxCursor
* cursor
= &m_cursor
;
4073 cursor
= wxSTANDARD_CURSOR
;
4075 gdk_pointer_grab( window
, FALSE
,
4077 (GDK_BUTTON_PRESS_MASK
|
4078 GDK_BUTTON_RELEASE_MASK
|
4079 GDK_POINTER_MOTION_HINT_MASK
|
4080 GDK_POINTER_MOTION_MASK
),
4082 cursor
->GetCursor(),
4083 (guint32
)GDK_CURRENT_TIME
);
4084 g_captureWindow
= this;
4085 g_captureWindowHasMouse
= true;
4088 void wxWindowGTK::DoReleaseMouse()
4090 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4092 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4094 g_captureWindow
= (wxWindowGTK
*) NULL
;
4096 GdkWindow
*window
= (GdkWindow
*) NULL
;
4098 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4100 window
= GetConnectWidget()->window
;
4105 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4109 wxWindow
*wxWindowBase::GetCapture()
4111 return (wxWindow
*)g_captureWindow
;
4114 bool wxWindowGTK::IsRetained() const
4119 void wxWindowGTK::BlockScrollEvent()
4121 wxASSERT(!m_blockScrollEvent
);
4122 m_blockScrollEvent
= true;
4125 void wxWindowGTK::UnblockScrollEvent()
4127 wxASSERT(m_blockScrollEvent
);
4128 m_blockScrollEvent
= false;
4131 void wxWindowGTK::SetScrollbar(int orient
,
4135 bool WXUNUSED(update
))
4137 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4138 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4142 m_hasScrolling
= true;
4146 // GtkRange requires upper > lower
4151 if (pos
> range
- thumbVisible
)
4152 pos
= range
- thumbVisible
;
4155 GtkAdjustment
* adj
= m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
;
4156 adj
->step_increment
= 1;
4157 adj
->page_increment
=
4158 adj
->page_size
= thumbVisible
;
4160 SetScrollPos(orient
, pos
);
4161 gtk_adjustment_changed(adj
);
4164 void wxWindowGTK::SetScrollPos(int orient
, int pos
, bool WXUNUSED(refresh
))
4166 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4167 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4169 // This check is more than an optimization. Without it, the slider
4170 // will not move smoothly while tracking when using wxScrollHelper.
4171 if (GetScrollPos(orient
) != pos
)
4173 const int dir
= ScrollDirFromOrient(orient
);
4174 GtkAdjustment
* adj
= m_scrollBar
[dir
]->adjustment
;
4175 const int max
= int(adj
->upper
- adj
->page_size
);
4182 // If a "value_changed" signal emission is not already in progress
4183 if (!m_blockValueChanged
[dir
])
4185 gtk_adjustment_value_changed(adj
);
4190 int wxWindowGTK::GetScrollThumb(int orient
) const
4192 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4193 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4195 return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->page_size
);
4198 int wxWindowGTK::GetScrollPos( int orient
) const
4200 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4201 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4203 return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->value
+ 0.5);
4206 int wxWindowGTK::GetScrollRange( int orient
) const
4208 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4209 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4211 return int(m_scrollBar
[ScrollDirFromOrient(orient
)]->adjustment
->upper
);
4214 // Determine if increment is the same as +/-x, allowing for some small
4215 // difference due to possible inexactness in floating point arithmetic
4216 static inline bool IsScrollIncrement(double increment
, double x
)
4218 wxASSERT(increment
> 0);
4219 const double tolerance
= 1.0 / 1024;
4220 return fabs(increment
- fabs(x
)) < tolerance
;
4223 wxEventType
wxWindowGTK::GetScrollEventType(GtkRange
* range
)
4228 wxapp_install_idle_handler();
4230 wxASSERT(range
== m_scrollBar
[0] || range
== m_scrollBar
[1]);
4232 const int barIndex
= range
== m_scrollBar
[1];
4233 GtkAdjustment
* adj
= range
->adjustment
;
4234 const int value
= int(adj
->value
+ 0.5);
4235 // save previous position
4236 const double oldPos
= m_scrollPos
[barIndex
];
4237 // update current position
4238 m_scrollPos
[barIndex
] = adj
->value
;
4239 // If event should be ignored, or integral position has not changed
4240 if (!m_hasVMT
|| g_blockEventsOnDrag
|| value
== int(oldPos
+ 0.5))
4245 wxEventType eventType
= wxEVT_SCROLL_THUMBTRACK
;
4248 // Difference from last change event
4249 const double diff
= adj
->value
- oldPos
;
4250 const bool isDown
= diff
> 0;
4252 if (IsScrollIncrement(adj
->step_increment
, diff
))
4254 eventType
= isDown
? wxEVT_SCROLL_LINEDOWN
: wxEVT_SCROLL_LINEUP
;
4256 else if (IsScrollIncrement(adj
->page_increment
, diff
))
4258 eventType
= isDown
? wxEVT_SCROLL_PAGEDOWN
: wxEVT_SCROLL_PAGEUP
;
4260 else if (m_mouseButtonDown
)
4262 // Assume track event
4263 m_isScrolling
= true;
4269 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4271 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4273 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4275 // No scrolling requested.
4276 if ((dx
== 0) && (dy
== 0)) return;
4278 m_clipPaintRegion
= true;
4280 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4282 m_clipPaintRegion
= false;
4285 void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget
* w
, int wxstyle
)
4287 //RN: Note that static controls usually have no border on gtk, so maybe
4288 //it makes sense to treat that as simply no border at the wx level
4290 if (!(wxstyle
& wxNO_BORDER
) && !(wxstyle
& wxBORDER_STATIC
))
4292 GtkShadowType gtkstyle
;
4294 if(wxstyle
& wxBORDER_RAISED
)
4295 gtkstyle
= GTK_SHADOW_OUT
;
4296 else if (wxstyle
& wxBORDER_SUNKEN
)
4297 gtkstyle
= GTK_SHADOW_IN
;
4298 else if (wxstyle
& wxBORDER_DOUBLE
)
4299 gtkstyle
= GTK_SHADOW_ETCHED_IN
;
4301 gtkstyle
= GTK_SHADOW_IN
;
4303 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w
),
4308 void wxWindowGTK::SetWindowStyleFlag( long style
)
4310 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4311 wxWindowBase::SetWindowStyleFlag(style
);
4314 // Find the wxWindow at the current mouse position, also returning the mouse
4316 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4318 pt
= wxGetMousePosition();
4319 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4323 // Get the current mouse position.
4324 wxPoint
wxGetMousePosition()
4326 /* This crashes when used within wxHelpContext,
4327 so we have to use the X-specific implementation below.
4329 GdkModifierType *mask;
4330 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4332 return wxPoint(x, y);
4336 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4338 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4339 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4340 Window rootReturn
, childReturn
;
4341 int rootX
, rootY
, winX
, winY
;
4342 unsigned int maskReturn
;
4344 XQueryPointer (display
,
4348 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4349 return wxPoint(rootX
, rootY
);
4353 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4354 void wxAddGrab(wxWindow
* window
)
4356 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4359 void wxRemoveGrab(wxWindow
* window
)
4361 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4364 // ----------------------------------------------------------------------------
4366 // ----------------------------------------------------------------------------
4368 class wxWinModule
: public wxModule
4375 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4378 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4380 bool wxWinModule::OnInit()
4382 // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() );
4383 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4388 void wxWinModule::OnExit()
4391 g_object_unref (g_eraseGC
);