1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
18 #include "wx/dcclient.h"
21 #include "wx/layout.h"
23 #include "wx/dialog.h"
24 #include "wx/msgdlg.h"
25 #include "wx/module.h"
26 #include "wx/combobox.h"
27 #if wxUSE_TOOLBAR_NATIVE
28 #include "wx/toolbar.h"
31 #if wxUSE_DRAG_AND_DROP
36 #include "wx/tooltip.h"
44 #include "wx/textctrl.h"
48 #include "wx/statusbr.h"
50 #include "wx/settings.h"
52 #include "wx/fontutil.h"
55 #include "wx/thread.h"
61 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
62 #include <gtk/gtkversion.h>
63 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
64 #undef GTK_DISABLE_DEPRECATED
67 #include "wx/gtk/private.h"
68 #include <gdk/gdkprivate.h>
69 #include <gdk/gdkkeysyms.h>
73 #include <gtk/gtkprivate.h>
75 #include "wx/gtk/win_gtk.h"
77 #include <pango/pangox.h>
83 extern GtkContainerClass
*pizza_parent_class
;
85 //-----------------------------------------------------------------------------
86 // documentation on internals
87 //-----------------------------------------------------------------------------
90 I have been asked several times about writing some documentation about
91 the GTK port of wxWidgets, especially its internal structures. Obviously,
92 you cannot understand wxGTK without knowing a little about the GTK, but
93 some more information about what the wxWindow, which is the base class
94 for all other window classes, does seems required as well.
98 What does wxWindow do? It contains the common interface for the following
99 jobs of its descendants:
101 1) Define the rudimentary behaviour common to all window classes, such as
102 resizing, intercepting user input (so as to make it possible to use these
103 events for special purposes in a derived class), window names etc.
105 2) Provide the possibility to contain and manage children, if the derived
106 class is allowed to contain children, which holds true for those window
107 classes which do not display a native GTK widget. To name them, these
108 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
109 work classes are a special case and are handled a bit differently from
110 the rest. The same holds true for the wxNotebook class.
112 3) Provide the possibility to draw into a client area of a window. This,
113 too, only holds true for classes that do not display a native GTK widget
116 4) Provide the entire mechanism for scrolling widgets. This actual inter-
117 face for this is usually in wxScrolledWindow, but the GTK implementation
120 5) A multitude of helper or extra methods for special purposes, such as
121 Drag'n'Drop, managing validators etc.
123 6) Display a border (sunken, raised, simple or none).
125 Normally one might expect, that one wxWidgets window would always correspond
126 to one GTK widget. Under GTK, there is no such allround widget that has all
127 the functionality. Moreover, the GTK defines a client area as a different
128 widget from the actual widget you are handling. Last but not least some
129 special classes (e.g. wxFrame) handle different categories of widgets and
130 still have the possibility to draw something in the client area.
131 It was therefore required to write a special purpose GTK widget, that would
132 represent a client area in the sense of wxWidgets capable to do the jobs
133 2), 3) and 4). I have written this class and it resides in win_gtk.c of
136 All windows must have a widget, with which they interact with other under-
137 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
138 the wxWindow class has a member variable called m_widget which holds a
139 pointer to this widget. When the window class represents a GTK native widget,
140 this is (in most cases) the only GTK widget the class manages. E.g. the
141 wxStaticText class handles only a GtkLabel widget a pointer to which you
142 can find in m_widget (defined in wxWindow)
144 When the class has a client area for drawing into and for containing children
145 it has to handle the client area widget (of the type GtkPizza, defined in
146 win_gtk.c), but there could be any number of widgets, handled by a class
147 The common rule for all windows is only, that the widget that interacts with
148 the rest of GTK must be referenced in m_widget and all other widgets must be
149 children of this widget on the GTK level. The top-most widget, which also
150 represents the client area, must be in the m_wxwindow field and must be of
153 As I said, the window classes that display a GTK native widget only have
154 one widget, so in the case of e.g. the wxButton class m_widget holds a
155 pointer to a GtkButton widget. But windows with client areas (for drawing
156 and children) have a m_widget field that is a pointer to a GtkScrolled-
157 Window and a m_wxwindow field that is pointer to a GtkPizza and this
158 one is (in the GTK sense) a child of the GtkScrolledWindow.
160 If the m_wxwindow field is set, then all input to this widget is inter-
161 cepted and sent to the wxWidgets class. If not, all input to the widget
162 that gets pointed to by m_widget gets intercepted and sent to the class.
166 The design of scrolling in wxWidgets is markedly different from that offered
167 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
168 clicking on a scrollbar belonging to scrolled window will inevitably move
169 the window. In wxWidgets, the scrollbar will only emit an event, send this
170 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
171 which actually moves the window and its subchildren. Note that GtkPizza
172 memorizes how much it has been scrolled but that wxWidgets forgets this
173 so that the two coordinates systems have to be kept in synch. This is done
174 in various places using the pizza->xoffset and pizza->yoffset values.
178 Singularily the most broken code in GTK is the code that is supposed to
179 inform subwindows (child windows) about new positions. Very often, duplicate
180 events are sent without changes in size or position, equally often no
181 events are sent at all (All this is due to a bug in the GtkContainer code
182 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
183 GTK's own system and it simply waits for size events for toplevel windows
184 and then iterates down the respective size events to all window. This has
185 the disadvantage that windows might get size events before the GTK widget
186 actually has the reported size. This doesn't normally pose any problem, but
187 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
188 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
189 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
190 window that is used for OpenGL output really has that size (as reported by
195 If someone at some point of time feels the immense desire to have a look at,
196 change or attempt to optimise the Refresh() logic, this person will need an
197 intimate understanding of what "draw" and "expose" events are and what
198 they are used for, in particular when used in connection with GTK's
199 own windowless widgets. Beware.
203 Cursors, too, have been a constant source of pleasure. The main difficulty
204 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
205 for the parent. To prevent this from doing too much harm, I use idle time
206 to set the cursor over and over again, starting from the toplevel windows
207 and ending with the youngest generation (speaking of parent and child windows).
208 Also don't forget that cursors (like much else) are connected to GdkWindows,
209 not GtkWidgets and that the "window" field of a GtkWidget might very well
210 point to the GdkWindow of the parent widget (-> "window-less widget") and
211 that the two obviously have very different meanings.
215 //-----------------------------------------------------------------------------
217 //-----------------------------------------------------------------------------
219 extern wxList wxPendingDelete
;
220 extern bool g_blockEventsOnDrag
;
221 extern bool g_blockEventsOnScroll
;
222 extern wxCursor g_globalCursor
;
224 static GdkGC
*g_eraseGC
= NULL
;
226 // mouse capture state: the window which has it and if the mouse is currently
228 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
229 static bool g_captureWindowHasMouse
= false;
231 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
233 // the last window which had the focus - this is normally never NULL (except
234 // if we never had focus at all) as even when g_focusWindow is NULL it still
235 // keeps its previous value
236 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
238 // If a window get the focus set but has not been realized
239 // yet, defer setting the focus to idle time.
240 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
242 extern bool g_mainThreadLocked
;
244 //-----------------------------------------------------------------------------
246 //-----------------------------------------------------------------------------
251 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
253 # define DEBUG_MAIN_THREAD
256 #define DEBUG_MAIN_THREAD
259 // the trace mask used for the focus debugging messages
260 #define TRACE_FOCUS _T("focus")
262 //-----------------------------------------------------------------------------
263 // missing gdk functions
264 //-----------------------------------------------------------------------------
267 gdk_window_warp_pointer (GdkWindow
*window
,
272 window
= GDK_ROOT_PARENT();
274 if (!GDK_WINDOW_DESTROYED(window
))
276 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
277 None
, /* not source window -> move from anywhere */
278 GDK_WINDOW_XID(window
), /* dest window */
279 0, 0, 0, 0, /* not source window -> move from anywhere */
284 //-----------------------------------------------------------------------------
285 // local code (see below)
286 //-----------------------------------------------------------------------------
288 // returns the child of win which currently has focus or NULL if not found
290 // Note: can't be static, needed by textctrl.cpp.
291 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
293 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
295 return (wxWindow
*)NULL
;
297 if ( winFocus
== win
)
298 return (wxWindow
*)win
;
300 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
302 node
= node
->GetNext() )
304 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
309 return (wxWindow
*)NULL
;
312 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
314 // wxUniversal widgets draw the borders and scrollbars themselves
315 #ifndef __WXUNIVERSAL__
322 if (win
->m_hasScrolling
)
324 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
326 GtkRequisition vscroll_req
;
327 vscroll_req
.width
= 2;
328 vscroll_req
.height
= 2;
329 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
330 (scroll_window
->vscrollbar
, &vscroll_req
);
332 GtkRequisition hscroll_req
;
333 hscroll_req
.width
= 2;
334 hscroll_req
.height
= 2;
335 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
336 (scroll_window
->hscrollbar
, &hscroll_req
);
338 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
340 if (scroll_window
->vscrollbar_visible
)
342 dw
+= vscroll_req
.width
;
343 dw
+= scroll_class
->scrollbar_spacing
;
346 if (scroll_window
->hscrollbar_visible
)
348 dh
+= hscroll_req
.height
;
349 dh
+= scroll_class
->scrollbar_spacing
;
355 if (GTK_WIDGET_NO_WINDOW (widget
))
357 dx
+= widget
->allocation
.x
;
358 dy
+= widget
->allocation
.y
;
361 if (win
->HasFlag(wxRAISED_BORDER
))
363 gtk_paint_shadow (widget
->style
,
367 NULL
, NULL
, NULL
, // FIXME: No clipping?
369 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
373 if (win
->HasFlag(wxSUNKEN_BORDER
))
375 gtk_paint_shadow (widget
->style
,
379 NULL
, NULL
, NULL
, // FIXME: No clipping?
381 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
385 if (win
->HasFlag(wxSIMPLE_BORDER
))
388 gc
= gdk_gc_new( widget
->window
);
389 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
390 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
392 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
396 #endif // __WXUNIVERSAL__
399 //-----------------------------------------------------------------------------
400 // "expose_event" of m_widget
401 //-----------------------------------------------------------------------------
405 gtk_window_own_expose_callback( GtkWidget
*widget
,
406 GdkEventExpose
*gdk_event
,
409 if (gdk_event
->count
> 0) return FALSE
;
411 draw_frame( widget
, win
);
413 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
419 //-----------------------------------------------------------------------------
420 // "size_request" of m_widget
421 //-----------------------------------------------------------------------------
423 // make it extern because wxStaticText needs to disconnect this one
425 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
426 GtkRequisition
*requisition
,
430 win
->GetSize( &w
, &h
);
436 requisition
->height
= h
;
437 requisition
->width
= w
;
443 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
444 GtkRequisition
*requisition
,
447 // This callback is actually hooked into the text entry
448 // of the combo box, not the GtkHBox.
451 win
->GetSize( &w
, &h
);
457 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
459 GtkRequisition entry_req
;
461 entry_req
.height
= 2;
462 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
463 (gcombo
->button
, &entry_req
);
465 requisition
->width
= w
- entry_req
.width
;
466 requisition
->height
= entry_req
.height
;
470 //-----------------------------------------------------------------------------
471 // "expose_event" of m_wxwindow
472 //-----------------------------------------------------------------------------
476 gtk_window_expose_callback( GtkWidget
*widget
,
477 GdkEventExpose
*gdk_event
,
483 wxapp_install_idle_handler();
485 // This callback gets called in drawing-idle time under
486 // GTK 2.0, so we don't need to defer anything to idle
489 GtkPizza
*pizza
= GTK_PIZZA( widget
);
490 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
495 wxPrintf( wxT("OnExpose from ") );
496 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
497 wxPrintf( win
->GetClassInfo()->GetClassName() );
498 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
499 (int)gdk_event
->area
.y
,
500 (int)gdk_event
->area
.width
,
501 (int)gdk_event
->area
.height
);
506 win
->m_wxwindow
->style
,
510 (GdkRectangle
*) NULL
,
512 (char *)"button", // const_cast
517 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
519 win
->GtkSendPaintEvents();
522 // Let parent window draw window-less widgets
523 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
529 //-----------------------------------------------------------------------------
530 // "key_press_event" from any window
531 //-----------------------------------------------------------------------------
533 // set WXTRACE to this to see the key event codes on the console
534 #define TRACE_KEYS _T("keyevent")
536 // translates an X key symbol to WXK_XXX value
538 // if isChar is true it means that the value returned will be used for EVT_CHAR
539 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
540 // for example, while if it is false it means that the value is going to be
541 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
543 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
549 // Shift, Control and Alt don't generate the CHAR events at all
552 key_code
= isChar
? 0 : WXK_SHIFT
;
556 key_code
= isChar
? 0 : WXK_CONTROL
;
564 key_code
= isChar
? 0 : WXK_ALT
;
567 // neither do the toggle modifies
568 case GDK_Scroll_Lock
:
569 key_code
= isChar
? 0 : WXK_SCROLL
;
573 key_code
= isChar
? 0 : WXK_CAPITAL
;
577 key_code
= isChar
? 0 : WXK_NUMLOCK
;
581 // various other special keys
594 case GDK_ISO_Left_Tab
:
601 key_code
= WXK_RETURN
;
605 key_code
= WXK_CLEAR
;
609 key_code
= WXK_PAUSE
;
613 key_code
= WXK_SELECT
;
617 key_code
= WXK_PRINT
;
621 key_code
= WXK_EXECUTE
;
625 key_code
= WXK_ESCAPE
;
628 // cursor and other extended keyboard keys
630 key_code
= WXK_DELETE
;
646 key_code
= WXK_RIGHT
;
653 case GDK_Prior
: // == GDK_Page_Up
654 key_code
= WXK_PRIOR
;
657 case GDK_Next
: // == GDK_Page_Down
670 key_code
= WXK_INSERT
;
685 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
689 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
693 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
697 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
701 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
705 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
709 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
713 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
717 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
721 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
725 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
729 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
733 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
736 case GDK_KP_Prior
: // == GDK_KP_Page_Up
737 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
740 case GDK_KP_Next
: // == GDK_KP_Page_Down
741 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
745 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
749 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
753 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
757 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
761 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
764 case GDK_KP_Multiply
:
765 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
769 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
772 case GDK_KP_Separator
:
773 // FIXME: what is this?
774 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
777 case GDK_KP_Subtract
:
778 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
782 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
786 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
803 key_code
= WXK_F1
+ keysym
- GDK_F1
;
813 static inline bool wxIsAsciiKeysym(KeySym ks
)
818 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
820 GdkEventKey
*gdk_event
)
824 GdkModifierType state
;
825 if (gdk_event
->window
)
826 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
828 event
.SetTimestamp( gdk_event
->time
);
829 event
.SetId(win
->GetId());
830 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
831 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
832 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
833 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
834 event
.m_scanCode
= gdk_event
->keyval
;
835 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
836 event
.m_rawFlags
= 0;
838 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
840 wxGetMousePosition( &x
, &y
);
841 win
->ScreenToClient( &x
, &y
);
844 event
.SetEventObject( win
);
849 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
851 GdkEventKey
*gdk_event
)
853 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
854 // but only event->keyval which is quite useless to us, so remember
855 // the last character from GDK_KEY_PRESS and reuse it as last resort
857 // NB: should be MT-safe as we're always called from the main thread only
862 } s_lastKeyPress
= { 0, 0 };
864 KeySym keysym
= gdk_event
->keyval
;
866 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
867 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
871 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
875 // do we have the translation or is it a plain ASCII character?
876 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
878 // we should use keysym if it is ASCII as X does some translations
879 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
880 // which we don't want here (but which we do use for OnChar())
881 if ( !wxIsAsciiKeysym(keysym
) )
883 keysym
= (KeySym
)gdk_event
->string
[0];
886 // we want to always get the same key code when the same key is
887 // pressed regardless of the state of the modifiers, i.e. on a
888 // standard US keyboard pressing '5' or '%' ('5' key with
889 // Shift) should result in the same key code in OnKeyDown():
890 // '5' (although OnChar() will get either '5' or '%').
892 // to do it we first translate keysym to keycode (== scan code)
893 // and then back but always using the lower register
894 Display
*dpy
= (Display
*)wxGetDisplay();
895 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
897 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
899 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
901 // use the normalized, i.e. lower register, keysym if we've
903 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
905 // as explained above, we want to have lower register key codes
906 // normally but for the letter keys we want to have the upper ones
908 // NB: don't use XConvertCase() here, we want to do it for letters
910 key_code
= toupper(key_code
);
912 else // non ASCII key, what to do?
914 // by default, ignore it
917 // but if we have cached information from the last KEY_PRESS
918 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
921 if ( keysym
== s_lastKeyPress
.keysym
)
923 key_code
= s_lastKeyPress
.keycode
;
928 if ( gdk_event
->type
== GDK_KEY_PRESS
)
930 // remember it to be reused for KEY_UP event later
931 s_lastKeyPress
.keysym
= keysym
;
932 s_lastKeyPress
.keycode
= key_code
;
936 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
938 // sending unknown key events doesn't really make sense
942 // now fill all the other fields
943 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
945 event
.m_keyCode
= key_code
;
947 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
949 event
.m_uniChar
= key_code
;
959 GtkIMContext
*context
;
960 GdkEventKey
*lastKeyEvent
;
964 context
= gtk_im_multicontext_new();
969 g_object_unref(context
);
975 gtk_window_key_press_callback( GtkWidget
*widget
,
976 GdkEventKey
*gdk_event
,
982 wxapp_install_idle_handler();
986 if (g_blockEventsOnDrag
)
990 wxKeyEvent
event( wxEVT_KEY_DOWN
);
992 bool return_after_IM
= false;
994 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
996 // Emit KEY_DOWN event
997 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1001 // Return after IM processing as we cannot do
1002 // anything with it anyhow.
1003 return_after_IM
= true;
1006 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1007 // When we get a key_press event here, it could be originate
1008 // from the current widget or its child widgets. However, only the widget
1009 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1010 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1011 // originated from its child widgets and shouldn't be passed to IM context.
1012 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1013 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1014 // widgets has both IM context and input focus, the event should be filtered
1015 // by gtk_im_context_filter_keypress().
1016 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1017 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1019 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1020 // docs, if IM filter returns true, no further processing should be done.
1021 // we should send the key_down event anyway.
1022 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1023 win
->m_imData
->lastKeyEvent
= NULL
;
1024 if (intercepted_by_IM
)
1026 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1031 if (return_after_IM
)
1037 wxWindowGTK
*ancestor
= win
;
1040 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1043 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1044 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1047 if (ancestor
->IsTopLevel())
1049 ancestor
= ancestor
->GetParent();
1052 #endif // wxUSE_ACCEL
1054 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1055 // will only be sent if it is not in an accelerator table.
1059 KeySym keysym
= gdk_event
->keyval
;
1060 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1061 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1064 if ( wxIsAsciiKeysym(keysym
) )
1067 key_code
= (unsigned char)keysym
;
1069 // gdk_event->string is actually deprecated
1070 else if ( gdk_event
->length
== 1 )
1072 key_code
= (unsigned char)gdk_event
->string
[0];
1078 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1080 event
.m_keyCode
= key_code
;
1082 // To conform to the docs we need to translate Ctrl-alpha
1083 // characters to values in the range 1-26.
1084 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1086 event
.m_keyCode
= key_code
- 'a' + 1;
1088 event
.m_uniChar
= event
.m_keyCode
;
1092 // Implement OnCharHook by checking ancestor top level windows
1093 wxWindow
*parent
= win
;
1094 while (parent
&& !parent
->IsTopLevel())
1095 parent
= parent
->GetParent();
1098 event
.SetEventType( wxEVT_CHAR_HOOK
);
1099 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1104 event
.SetEventType(wxEVT_CHAR
);
1105 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1114 // win is a control: tab can be propagated up
1116 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1117 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1118 // have this style, yet choose not to process this particular TAB in which
1119 // case TAB must still work as a navigational character
1120 // JS: enabling again to make consistent with other platforms
1121 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1122 // navigation behaviour)
1124 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1126 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1128 wxNavigationKeyEvent new_event
;
1129 new_event
.SetEventObject( win
->GetParent() );
1130 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1131 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1132 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1133 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1134 new_event
.SetCurrentFocus( win
);
1135 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1138 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1140 (gdk_event
->keyval
== GDK_Escape
) )
1142 // however only do it if we have a Cancel button in the dialog,
1143 // otherwise the user code may get confused by the events from a
1144 // non-existing button and, worse, a wxButton might get button event
1145 // from another button which is not really expected
1146 wxWindow
*winForCancel
= win
,
1148 while ( winForCancel
)
1150 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1153 // found a cancel button
1157 if ( winForCancel
->IsTopLevel() )
1159 // no need to look further
1163 // maybe our parent has a cancel button?
1164 winForCancel
= winForCancel
->GetParent();
1169 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1170 eventClick
.SetEventObject(btnCancel
);
1171 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1177 g_signal_stop_emission_by_name (widget
, "key_press_event");
1187 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1191 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1193 // take modifiers, cursor position, timestamp etc. from the last
1194 // key_press_event that was fed into Input Method:
1195 if (window
->m_imData
->lastKeyEvent
)
1197 wxFillOtherKeyEventFields(event
,
1198 window
, window
->m_imData
->lastKeyEvent
);
1202 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1204 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1205 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1206 #endif // wxUSE_UNICODE
1207 if( !(const wxChar
*)data
)
1212 // Implement OnCharHook by checking ancestor top level windows
1213 wxWindow
*parent
= window
;
1214 while (parent
&& !parent
->IsTopLevel())
1215 parent
= parent
->GetParent();
1217 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1220 event
.m_uniChar
= *pstr
;
1221 // Backward compatible for ISO-8859-1
1222 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1223 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1225 event
.m_keyCode
= *pstr
;
1226 #endif // wxUSE_UNICODE
1228 // To conform to the docs we need to translate Ctrl-alpha
1229 // characters to values in the range 1-26.
1230 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1232 event
.m_keyCode
= *pstr
- 'a' + 1;
1234 event
.m_uniChar
= event
.m_keyCode
;
1240 event
.SetEventType( wxEVT_CHAR_HOOK
);
1241 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1246 event
.SetEventType(wxEVT_CHAR
);
1247 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1254 //-----------------------------------------------------------------------------
1255 // "key_release_event" from any window
1256 //-----------------------------------------------------------------------------
1260 gtk_window_key_release_callback( GtkWidget
*widget
,
1261 GdkEventKey
*gdk_event
,
1267 wxapp_install_idle_handler();
1272 if (g_blockEventsOnDrag
)
1275 wxKeyEvent
event( wxEVT_KEY_UP
);
1276 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1278 // unknown key pressed, ignore (the event would be useless anyhow)
1282 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1285 g_signal_stop_emission_by_name (widget
, "key_release_event");
1290 // ============================================================================
1292 // ============================================================================
1294 // ----------------------------------------------------------------------------
1295 // mouse event processing helpers
1296 // ----------------------------------------------------------------------------
1298 // init wxMouseEvent with the info from GdkEventXXX struct
1299 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1300 wxMouseEvent
& event
,
1303 event
.SetTimestamp( gdk_event
->time
);
1304 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1305 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1306 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1307 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1308 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1309 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1310 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1311 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1313 event
.m_linesPerAction
= 3;
1314 event
.m_wheelDelta
= 120;
1315 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1316 event
.m_wheelRotation
= 120;
1317 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1318 event
.m_wheelRotation
= -120;
1321 wxPoint pt
= win
->GetClientAreaOrigin();
1322 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1323 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1325 event
.SetEventObject( win
);
1326 event
.SetId( win
->GetId() );
1327 event
.SetTimestamp( gdk_event
->time
);
1330 static void AdjustEventButtonState(wxMouseEvent
& event
)
1332 // GDK reports the old state of the button for a button press event, but
1333 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1334 // for a LEFT_DOWN event, not FALSE, so we will invert
1335 // left/right/middleDown for the corresponding click events
1337 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1338 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1339 (event
.GetEventType() == wxEVT_LEFT_UP
))
1341 event
.m_leftDown
= !event
.m_leftDown
;
1345 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1346 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1347 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1349 event
.m_middleDown
= !event
.m_middleDown
;
1353 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1354 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1355 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1357 event
.m_rightDown
= !event
.m_rightDown
;
1362 // find the window to send the mouse event too
1364 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1369 if (win
->m_wxwindow
)
1371 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1372 xx
+= pizza
->xoffset
;
1373 yy
+= pizza
->yoffset
;
1376 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1379 wxWindowGTK
*child
= node
->GetData();
1381 node
= node
->GetNext();
1382 if (!child
->IsShown())
1385 if (child
->IsTransparentForMouse())
1387 // wxStaticBox is transparent in the box itself
1388 int xx1
= child
->m_x
;
1389 int yy1
= child
->m_y
;
1390 int xx2
= child
->m_x
+ child
->m_width
;
1391 int yy2
= child
->m_y
+ child
->m_height
;
1394 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1396 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1398 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1400 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1411 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1412 (child
->m_x
<= xx
) &&
1413 (child
->m_y
<= yy
) &&
1414 (child
->m_x
+child
->m_width
>= xx
) &&
1415 (child
->m_y
+child
->m_height
>= yy
))
1428 //-----------------------------------------------------------------------------
1429 // "button_press_event"
1430 //-----------------------------------------------------------------------------
1434 gtk_window_button_press_callback( GtkWidget
*widget
,
1435 GdkEventButton
*gdk_event
,
1441 wxapp_install_idle_handler();
1444 wxPrintf( wxT("1) OnButtonPress from ") );
1445 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1446 wxPrintf( win->GetClassInfo()->GetClassName() );
1447 wxPrintf( wxT(".\n") );
1449 if (!win
->m_hasVMT
) return FALSE
;
1450 if (g_blockEventsOnDrag
) return TRUE
;
1451 if (g_blockEventsOnScroll
) return TRUE
;
1453 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1455 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1457 gtk_widget_grab_focus( win
->m_wxwindow
);
1459 wxPrintf( wxT("GrabFocus from ") );
1460 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1461 wxPrintf( win->GetClassInfo()->GetClassName() );
1462 wxPrintf( wxT(".\n") );
1466 // GDK sends surplus button down events
1467 // before a double click event. We
1468 // need to filter these out.
1469 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1471 GdkEvent
*peek_event
= gdk_event_peek();
1474 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1475 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1477 gdk_event_free( peek_event
);
1482 gdk_event_free( peek_event
);
1487 wxEventType event_type
= wxEVT_NULL
;
1489 // GdkDisplay is a GTK+ 2.2.0 thing
1490 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1491 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1492 !gtk_check_version(2,2,0) &&
1493 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1495 // Reset GDK internal timestamp variables in order to disable GDK
1496 // triple click events. GDK will then next time believe no button has
1497 // been clicked just before, and send a normal button click event.
1498 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1499 display
->button_click_time
[1] = 0;
1500 display
->button_click_time
[0] = 0;
1504 if (gdk_event
->button
== 1)
1506 // note that GDK generates triple click events which are not supported
1507 // by wxWidgets but still have to be passed to the app as otherwise
1508 // clicks would simply go missing
1509 switch (gdk_event
->type
)
1511 // we shouldn't get triple clicks at all for GTK2 because we
1512 // suppress them artificially using the code above but we still
1513 // should map them to something for GTK1 and not just ignore them
1514 // as this would lose clicks
1515 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1516 case GDK_BUTTON_PRESS
:
1517 event_type
= wxEVT_LEFT_DOWN
;
1520 case GDK_2BUTTON_PRESS
:
1521 event_type
= wxEVT_LEFT_DCLICK
;
1525 // just to silence gcc warnings
1529 else if (gdk_event
->button
== 2)
1531 switch (gdk_event
->type
)
1533 case GDK_3BUTTON_PRESS
:
1534 case GDK_BUTTON_PRESS
:
1535 event_type
= wxEVT_MIDDLE_DOWN
;
1538 case GDK_2BUTTON_PRESS
:
1539 event_type
= wxEVT_MIDDLE_DCLICK
;
1546 else if (gdk_event
->button
== 3)
1548 switch (gdk_event
->type
)
1550 case GDK_3BUTTON_PRESS
:
1551 case GDK_BUTTON_PRESS
:
1552 event_type
= wxEVT_RIGHT_DOWN
;
1555 case GDK_2BUTTON_PRESS
:
1556 event_type
= wxEVT_RIGHT_DCLICK
;
1563 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1565 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1567 event_type
= wxEVT_MOUSEWHEEL
;
1571 if ( event_type
== wxEVT_NULL
)
1573 // unknown mouse button or click type
1577 wxMouseEvent
event( event_type
);
1578 InitMouseEvent( win
, event
, gdk_event
);
1580 AdjustEventButtonState(event
);
1582 // wxListBox actually gets mouse events from the item, so we need to give it
1583 // a chance to correct this
1584 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1586 // find the correct window to send the event to: it may be a different one
1587 // from the one which got it at GTK+ level because some controls don't have
1588 // their own X window and thus cannot get any events.
1589 if ( !g_captureWindow
)
1590 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1592 if (win
->GetEventHandler()->ProcessEvent( event
))
1594 g_signal_stop_emission_by_name (widget
, "button_press_event");
1598 if (event_type
== wxEVT_RIGHT_DOWN
)
1600 // generate a "context menu" event: this is similar to right mouse
1601 // click under many GUIs except that it is generated differently
1602 // (right up under MSW, ctrl-click under Mac, right down here) and
1604 // (a) it's a command event and so is propagated to the parent
1605 // (b) under some ports it can be generated from kbd too
1606 // (c) it uses screen coords (because of (a))
1607 wxContextMenuEvent
evtCtx(
1610 win
->ClientToScreen(event
.GetPosition()));
1611 evtCtx
.SetEventObject(win
);
1612 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1619 //-----------------------------------------------------------------------------
1620 // "button_release_event"
1621 //-----------------------------------------------------------------------------
1625 gtk_window_button_release_callback( GtkWidget
*widget
,
1626 GdkEventButton
*gdk_event
,
1632 wxapp_install_idle_handler();
1634 if (!win
->m_hasVMT
) return FALSE
;
1635 if (g_blockEventsOnDrag
) return FALSE
;
1636 if (g_blockEventsOnScroll
) return FALSE
;
1638 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1640 wxEventType event_type
= wxEVT_NULL
;
1642 switch (gdk_event
->button
)
1645 event_type
= wxEVT_LEFT_UP
;
1649 event_type
= wxEVT_MIDDLE_UP
;
1653 event_type
= wxEVT_RIGHT_UP
;
1657 // unknwon button, don't process
1661 wxMouseEvent
event( event_type
);
1662 InitMouseEvent( win
, event
, gdk_event
);
1664 AdjustEventButtonState(event
);
1666 // same wxListBox hack as above
1667 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1669 if ( !g_captureWindow
)
1670 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1672 if (win
->GetEventHandler()->ProcessEvent( event
))
1674 g_signal_stop_emission_by_name (widget
, "button_release_event");
1682 //-----------------------------------------------------------------------------
1683 // "motion_notify_event"
1684 //-----------------------------------------------------------------------------
1688 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1689 GdkEventMotion
*gdk_event
,
1695 wxapp_install_idle_handler();
1697 if (!win
->m_hasVMT
) return FALSE
;
1698 if (g_blockEventsOnDrag
) return FALSE
;
1699 if (g_blockEventsOnScroll
) return FALSE
;
1701 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1703 if (gdk_event
->is_hint
)
1707 GdkModifierType state
;
1708 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1714 printf( "OnMotion from " );
1715 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1716 printf( win->GetClassInfo()->GetClassName() );
1720 wxMouseEvent
event( wxEVT_MOTION
);
1721 InitMouseEvent(win
, event
, gdk_event
);
1723 if ( g_captureWindow
)
1725 // synthetize a mouse enter or leave event if needed
1726 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1727 // This seems to be necessary and actually been added to
1728 // GDK itself in version 2.0.X
1731 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1732 if ( hasMouse
!= g_captureWindowHasMouse
)
1734 // the mouse changed window
1735 g_captureWindowHasMouse
= hasMouse
;
1737 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1738 : wxEVT_LEAVE_WINDOW
);
1739 InitMouseEvent(win
, eventM
, gdk_event
);
1740 eventM
.SetEventObject(win
);
1741 win
->GetEventHandler()->ProcessEvent(eventM
);
1746 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1749 if ( !g_captureWindow
)
1751 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1752 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1754 // Rewrite cursor handling here (away from idle).
1758 if (win
->GetEventHandler()->ProcessEvent( event
))
1760 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1768 //-----------------------------------------------------------------------------
1769 // "mouse_wheel_event"
1770 //-----------------------------------------------------------------------------
1774 gtk_window_wheel_callback (GtkWidget
* widget
,
1775 GdkEventScroll
* gdk_event
,
1781 wxapp_install_idle_handler();
1783 wxEventType event_type
= wxEVT_NULL
;
1784 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1785 event_type
= wxEVT_MOUSEWHEEL
;
1786 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1787 event_type
= wxEVT_MOUSEWHEEL
;
1791 wxMouseEvent
event( event_type
);
1792 // Can't use InitMouse macro because scroll events don't have button
1793 event
.SetTimestamp( gdk_event
->time
);
1794 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1795 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1796 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1797 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1798 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1799 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1800 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1801 event
.m_linesPerAction
= 3;
1802 event
.m_wheelDelta
= 120;
1803 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1804 event
.m_wheelRotation
= 120;
1806 event
.m_wheelRotation
= -120;
1808 wxPoint pt
= win
->GetClientAreaOrigin();
1809 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1810 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1812 event
.SetEventObject( win
);
1813 event
.SetId( win
->GetId() );
1814 event
.SetTimestamp( gdk_event
->time
);
1816 if (win
->GetEventHandler()->ProcessEvent( event
))
1818 g_signal_stop_emission_by_name (widget
, "scroll_event");
1826 //-----------------------------------------------------------------------------
1828 //-----------------------------------------------------------------------------
1830 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1832 wxContextMenuEvent
event(
1836 event
.SetEventObject(win
);
1837 return win
->GetEventHandler()->ProcessEvent(event
);
1841 //-----------------------------------------------------------------------------
1843 //-----------------------------------------------------------------------------
1845 // send the wxChildFocusEvent and wxFocusEvent, common code of
1846 // gtk_window_focus_in_callback() and SetFocus()
1847 static bool DoSendFocusEvents(wxWindow
*win
)
1849 // Notify the parent keeping track of focus for the kbd navigation
1850 // purposes that we got it.
1851 wxChildFocusEvent
eventChildFocus(win
);
1852 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1854 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1855 eventFocus
.SetEventObject(win
);
1857 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1862 gtk_window_focus_in_callback( GtkWidget
*widget
,
1863 GdkEventFocus
*WXUNUSED(event
),
1869 wxapp_install_idle_handler();
1872 gtk_im_context_focus_in(win
->m_imData
->context
);
1875 g_focusWindow
= win
;
1877 wxLogTrace(TRACE_FOCUS
,
1878 _T("%s: focus in"), win
->GetName().c_str());
1882 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1886 // caret needs to be informed about focus change
1887 wxCaret
*caret
= win
->GetCaret();
1890 caret
->OnSetFocus();
1892 #endif // wxUSE_CARET
1894 gboolean ret
= FALSE
;
1896 // does the window itself think that it has the focus?
1897 if ( !win
->m_hasFocus
)
1899 // not yet, notify it
1900 win
->m_hasFocus
= true;
1902 (void)DoSendFocusEvents(win
);
1907 // Disable default focus handling for custom windows
1908 // since the default GTK+ handler issues a repaint
1909 if (win
->m_wxwindow
)
1916 //-----------------------------------------------------------------------------
1917 // "focus_out_event"
1918 //-----------------------------------------------------------------------------
1922 gtk_window_focus_out_callback( GtkWidget
*widget
,
1923 GdkEventFocus
*gdk_event
,
1929 wxapp_install_idle_handler();
1932 gtk_im_context_focus_out(win
->m_imData
->context
);
1934 wxLogTrace( TRACE_FOCUS
,
1935 _T("%s: focus out"), win
->GetName().c_str() );
1938 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1942 g_focusWindow
= (wxWindowGTK
*)NULL
;
1950 // caret needs to be informed about focus change
1951 wxCaret
*caret
= win
->GetCaret();
1954 caret
->OnKillFocus();
1956 #endif // wxUSE_CARET
1958 gboolean ret
= FALSE
;
1960 // don't send the window a kill focus event if it thinks that it doesn't
1961 // have focus already
1962 if ( win
->m_hasFocus
)
1964 win
->m_hasFocus
= false;
1966 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1967 event
.SetEventObject( win
);
1969 (void)win
->GetEventHandler()->ProcessEvent( event
);
1974 // Disable default focus handling for custom windows
1975 // since the default GTK+ handler issues a repaint
1976 if (win
->m_wxwindow
)
1983 //-----------------------------------------------------------------------------
1984 // "enter_notify_event"
1985 //-----------------------------------------------------------------------------
1989 gtk_window_enter_callback( GtkWidget
*widget
,
1990 GdkEventCrossing
*gdk_event
,
1996 wxapp_install_idle_handler();
1998 if (!win
->m_hasVMT
) return FALSE
;
1999 if (g_blockEventsOnDrag
) return FALSE
;
2001 // Event was emitted after a grab
2002 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2004 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2008 GdkModifierType state
= (GdkModifierType
)0;
2010 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2012 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2013 InitMouseEvent(win
, event
, gdk_event
);
2014 wxPoint pt
= win
->GetClientAreaOrigin();
2015 event
.m_x
= x
+ pt
.x
;
2016 event
.m_y
= y
+ pt
.y
;
2018 if ( !g_captureWindow
)
2020 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2021 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2023 // Rewrite cursor handling here (away from idle).
2027 if (win
->GetEventHandler()->ProcessEvent( event
))
2029 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2037 //-----------------------------------------------------------------------------
2038 // "leave_notify_event"
2039 //-----------------------------------------------------------------------------
2043 gtk_window_leave_callback( GtkWidget
*widget
,
2044 GdkEventCrossing
*gdk_event
,
2050 wxapp_install_idle_handler();
2052 if (!win
->m_hasVMT
) return FALSE
;
2053 if (g_blockEventsOnDrag
) return FALSE
;
2055 // Event was emitted after an ungrab
2056 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2058 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2060 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2061 event
.SetTimestamp( gdk_event
->time
);
2062 event
.SetEventObject( win
);
2066 GdkModifierType state
= (GdkModifierType
)0;
2068 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2070 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2071 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2072 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2073 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2074 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2075 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2076 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2078 wxPoint pt
= win
->GetClientAreaOrigin();
2079 event
.m_x
= x
+ pt
.x
;
2080 event
.m_y
= y
+ pt
.y
;
2082 if (win
->GetEventHandler()->ProcessEvent( event
))
2084 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2092 //-----------------------------------------------------------------------------
2093 // "value_changed" from m_vAdjust
2094 //-----------------------------------------------------------------------------
2097 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2103 wxapp_install_idle_handler();
2105 if (g_blockEventsOnDrag
) return;
2107 if (!win
->m_hasVMT
) return;
2109 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2110 if (fabs(diff
) < 0.2) return;
2112 win
->m_oldVerticalPos
= adjust
->value
;
2114 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2116 int value
= (int)(adjust
->value
+0.5);
2118 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2119 event
.SetEventObject( win
);
2120 win
->GetEventHandler()->ProcessEvent( event
);
2124 //-----------------------------------------------------------------------------
2125 // "value_changed" from m_hAdjust
2126 //-----------------------------------------------------------------------------
2129 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2135 wxapp_install_idle_handler();
2137 if (g_blockEventsOnDrag
) return;
2138 if (!win
->m_hasVMT
) return;
2140 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2141 if (fabs(diff
) < 0.2) return;
2143 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2145 win
->m_oldHorizontalPos
= adjust
->value
;
2147 int value
= (int)(adjust
->value
+0.5);
2149 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2150 event
.SetEventObject( win
);
2151 win
->GetEventHandler()->ProcessEvent( event
);
2155 //-----------------------------------------------------------------------------
2156 // "button_press_event" from scrollbar
2157 //-----------------------------------------------------------------------------
2161 gtk_scrollbar_button_press_callback( GtkWidget
*widget
,
2162 GdkEventButton
*gdk_event
,
2168 wxapp_install_idle_handler();
2171 g_blockEventsOnScroll
= true;
2173 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2175 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2182 //-----------------------------------------------------------------------------
2183 // "button_release_event" from scrollbar
2184 //-----------------------------------------------------------------------------
2188 gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2189 GdkEventButton
*WXUNUSED(gdk_event
),
2194 // don't test here as we can release the mouse while being over
2195 // a different window than the slider
2197 // if (gdk_event->window != widget->slider) return FALSE;
2199 g_blockEventsOnScroll
= false;
2201 if (win
->m_isScrolling
)
2203 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2207 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2208 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2210 value
= (int)(win
->m_hAdjust
->value
+0.5);
2213 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2215 value
= (int)(win
->m_vAdjust
->value
+0.5);
2219 wxScrollWinEvent
event( command
, value
, dir
);
2220 event
.SetEventObject( win
);
2221 win
->GetEventHandler()->ProcessEvent( event
);
2224 win
->m_isScrolling
= false;
2230 // ----------------------------------------------------------------------------
2231 // this wxWindowBase function is implemented here (in platform-specific file)
2232 // because it is static and so couldn't be made virtual
2233 // ----------------------------------------------------------------------------
2235 wxWindow
*wxWindowBase::DoFindFocus()
2237 // the cast is necessary when we compile in wxUniversal mode
2238 return (wxWindow
*)g_focusWindow
;
2241 //-----------------------------------------------------------------------------
2242 // "realize" from m_widget
2243 //-----------------------------------------------------------------------------
2245 /* We cannot set colours and fonts before the widget has
2246 been realized, so we do this directly after realization. */
2250 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2255 wxapp_install_idle_handler();
2259 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2260 gtk_im_context_set_client_window( win
->m_imData
->context
,
2261 pizza
->bin_window
);
2264 wxWindowCreateEvent
event( win
);
2265 event
.SetEventObject( win
);
2266 win
->GetEventHandler()->ProcessEvent( event
);
2270 //-----------------------------------------------------------------------------
2272 //-----------------------------------------------------------------------------
2276 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2277 GtkAllocation
*WXUNUSED(alloc
),
2281 wxapp_install_idle_handler();
2283 if (!win
->m_hasScrolling
) return;
2285 int client_width
= 0;
2286 int client_height
= 0;
2287 win
->GetClientSize( &client_width
, &client_height
);
2288 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2291 win
->m_oldClientWidth
= client_width
;
2292 win
->m_oldClientHeight
= client_height
;
2294 if (!win
->m_nativeSizeEvent
)
2296 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2297 event
.SetEventObject( win
);
2298 win
->GetEventHandler()->ProcessEvent( event
);
2305 #define WXUNUSED_UNLESS_XIM(param) param
2307 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2310 /* Resize XIM window */
2314 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2315 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2316 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2319 wxapp_install_idle_handler();
2325 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2329 gdk_window_get_size (widget
->window
, &width
, &height
);
2330 win
->m_icattr
->preedit_area
.width
= width
;
2331 win
->m_icattr
->preedit_area
.height
= height
;
2332 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2338 //-----------------------------------------------------------------------------
2339 // "realize" from m_wxwindow
2340 //-----------------------------------------------------------------------------
2342 /* Initialize XIM support */
2346 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2347 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2350 wxapp_install_idle_handler();
2353 if (win
->m_ic
) return;
2354 if (!widget
) return;
2355 if (!gdk_im_ready()) return;
2357 win
->m_icattr
= gdk_ic_attr_new();
2358 if (!win
->m_icattr
) return;
2362 GdkColormap
*colormap
;
2363 GdkICAttr
*attr
= win
->m_icattr
;
2364 unsigned attrmask
= GDK_IC_ALL_REQ
;
2366 GdkIMStyle supported_style
= (GdkIMStyle
)
2367 (GDK_IM_PREEDIT_NONE
|
2368 GDK_IM_PREEDIT_NOTHING
|
2369 GDK_IM_PREEDIT_POSITION
|
2370 GDK_IM_STATUS_NONE
|
2371 GDK_IM_STATUS_NOTHING
);
2373 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2374 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2376 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2377 attr
->client_window
= widget
->window
;
2379 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2380 gtk_widget_get_default_colormap ())
2382 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2383 attr
->preedit_colormap
= colormap
;
2386 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2387 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2388 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2389 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2391 switch (style
& GDK_IM_PREEDIT_MASK
)
2393 case GDK_IM_PREEDIT_POSITION
:
2394 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2396 g_warning ("over-the-spot style requires fontset");
2400 gdk_window_get_size (widget
->window
, &width
, &height
);
2402 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2403 attr
->spot_location
.x
= 0;
2404 attr
->spot_location
.y
= height
;
2405 attr
->preedit_area
.x
= 0;
2406 attr
->preedit_area
.y
= 0;
2407 attr
->preedit_area
.width
= width
;
2408 attr
->preedit_area
.height
= height
;
2409 attr
->preedit_fontset
= widget
->style
->font
;
2414 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2416 if (win
->m_ic
== NULL
)
2417 g_warning ("Can't create input context.");
2420 mask
= gdk_window_get_events (widget
->window
);
2421 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2422 gdk_window_set_events (widget
->window
, mask
);
2424 if (GTK_WIDGET_HAS_FOCUS(widget
))
2425 gdk_im_begin (win
->m_ic
, widget
->window
);
2431 //-----------------------------------------------------------------------------
2432 // InsertChild for wxWindowGTK.
2433 //-----------------------------------------------------------------------------
2435 /* Callback for wxWindowGTK. This very strange beast has to be used because
2436 * C++ has no virtual methods in a constructor. We have to emulate a
2437 * virtual function here as wxNotebook requires a different way to insert
2438 * a child in it. I had opted for creating a wxNotebookPage window class
2439 * which would have made this superfluous (such in the MDI window system),
2440 * but no-one was listening to me... */
2442 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2444 /* the window might have been scrolled already, do we
2445 have to adapt the position */
2446 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2447 child
->m_x
+= pizza
->xoffset
;
2448 child
->m_y
+= pizza
->yoffset
;
2450 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2451 GTK_WIDGET(child
->m_widget
),
2458 //-----------------------------------------------------------------------------
2460 //-----------------------------------------------------------------------------
2462 wxWindow
*wxGetActiveWindow()
2464 return wxWindow::FindFocus();
2468 wxMouseState
wxGetMouseState()
2474 GdkModifierType mask
;
2476 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2480 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2481 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2482 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2484 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2485 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2486 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2487 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2492 //-----------------------------------------------------------------------------
2494 //-----------------------------------------------------------------------------
2496 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2498 #ifdef __WXUNIVERSAL__
2499 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2501 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2502 #endif // __WXUNIVERSAL__/__WXGTK__
2504 void wxWindowGTK::Init()
2507 m_widget
= (GtkWidget
*) NULL
;
2508 m_wxwindow
= (GtkWidget
*) NULL
;
2509 m_focusWidget
= (GtkWidget
*) NULL
;
2519 m_needParent
= true;
2520 m_isBeingDeleted
= false;
2523 m_nativeSizeEvent
= false;
2525 m_hasScrolling
= false;
2526 m_isScrolling
= false;
2528 m_hAdjust
= (GtkAdjustment
*) NULL
;
2529 m_vAdjust
= (GtkAdjustment
*) NULL
;
2530 m_oldHorizontalPos
=
2531 m_oldVerticalPos
= 0.0;
2533 m_oldClientHeight
= 0;
2537 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2539 m_acceptsFocus
= false;
2542 m_clipPaintRegion
= false;
2544 m_needsStyleChange
= false;
2546 m_cursor
= *wxSTANDARD_CURSOR
;
2549 m_dirtyTabOrder
= false;
2552 wxWindowGTK::wxWindowGTK()
2557 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2562 const wxString
&name
)
2566 Create( parent
, id
, pos
, size
, style
, name
);
2569 bool wxWindowGTK::Create( wxWindow
*parent
,
2574 const wxString
&name
)
2576 if (!PreCreation( parent
, pos
, size
) ||
2577 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2579 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2583 m_insertCallback
= wxInsertChildInWindow
;
2585 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2586 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2588 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2590 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2591 scroll_class
->scrollbar_spacing
= 0;
2593 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2595 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2596 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2598 m_wxwindow
= gtk_pizza_new();
2600 #ifndef __WXUNIVERSAL__
2601 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2603 if (HasFlag(wxRAISED_BORDER
))
2605 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2607 else if (HasFlag(wxSUNKEN_BORDER
))
2609 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2611 else if (HasFlag(wxSIMPLE_BORDER
))
2613 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2617 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2619 #endif // __WXUNIVERSAL__
2621 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2623 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2624 m_acceptsFocus
= true;
2626 // I _really_ don't want scrollbars in the beginning
2627 m_vAdjust
->lower
= 0.0;
2628 m_vAdjust
->upper
= 1.0;
2629 m_vAdjust
->value
= 0.0;
2630 m_vAdjust
->step_increment
= 1.0;
2631 m_vAdjust
->page_increment
= 1.0;
2632 m_vAdjust
->page_size
= 5.0;
2633 g_signal_emit_by_name (m_vAdjust
, "changed");
2634 m_hAdjust
->lower
= 0.0;
2635 m_hAdjust
->upper
= 1.0;
2636 m_hAdjust
->value
= 0.0;
2637 m_hAdjust
->step_increment
= 1.0;
2638 m_hAdjust
->page_increment
= 1.0;
2639 m_hAdjust
->page_size
= 5.0;
2640 g_signal_emit_by_name (m_hAdjust
, "changed");
2642 // these handlers block mouse events to any window during scrolling such as
2643 // motion events and prevent GTK and wxWidgets from fighting over where the
2645 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2646 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2647 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2648 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2649 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2650 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2651 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2652 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2654 // these handlers get notified when screen updates are required either when
2655 // scrolling or when the window size (and therefore scrollbar configuration)
2658 g_signal_connect (m_hAdjust
, "value_changed",
2659 G_CALLBACK (gtk_window_hscroll_callback
), this);
2660 g_signal_connect (m_vAdjust
, "value_changed",
2661 G_CALLBACK (gtk_window_vscroll_callback
), this);
2663 gtk_widget_show( m_wxwindow
);
2666 m_parent
->DoAddChild( this );
2668 m_focusWidget
= m_wxwindow
;
2675 wxWindowGTK::~wxWindowGTK()
2679 if (g_focusWindow
== this)
2680 g_focusWindow
= NULL
;
2682 if ( g_delayedFocus
== this )
2683 g_delayedFocus
= NULL
;
2685 m_isBeingDeleted
= true;
2688 // destroy children before destroying this window itself
2691 // unhook focus handlers to prevent stray events being
2692 // propagated to this (soon to be) dead object
2693 if (m_focusWidget
!= NULL
)
2695 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2696 (gpointer
) gtk_window_focus_in_callback
,
2698 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2699 (gpointer
) gtk_window_focus_out_callback
,
2708 gdk_ic_destroy (m_ic
);
2710 gdk_ic_attr_destroy (m_icattr
);
2713 // delete before the widgets to avoid a crash on solaris
2718 gtk_widget_destroy( m_wxwindow
);
2719 m_wxwindow
= (GtkWidget
*) NULL
;
2724 gtk_widget_destroy( m_widget
);
2725 m_widget
= (GtkWidget
*) NULL
;
2729 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2731 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2733 // Use either the given size, or the default if -1 is given.
2734 // See wxWindowBase for these functions.
2735 m_width
= WidthDefault(size
.x
) ;
2736 m_height
= HeightDefault(size
.y
);
2744 void wxWindowGTK::PostCreation()
2746 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2752 // these get reported to wxWidgets -> wxPaintEvent
2754 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2756 g_signal_connect (m_wxwindow
, "expose_event",
2757 G_CALLBACK (gtk_window_expose_callback
), this);
2759 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2762 // Create input method handler
2763 m_imData
= new wxGtkIMData
;
2765 // Cannot handle drawing preedited text yet
2766 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2768 g_signal_connect (m_imData
->context
, "commit",
2769 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2771 // these are called when the "sunken" or "raised" borders are drawn
2772 g_signal_connect (m_widget
, "expose_event",
2773 G_CALLBACK (gtk_window_own_expose_callback
), this);
2778 if (!GTK_IS_WINDOW(m_widget
))
2780 if (m_focusWidget
== NULL
)
2781 m_focusWidget
= m_widget
;
2785 g_signal_connect (m_focusWidget
, "focus_in_event",
2786 G_CALLBACK (gtk_window_focus_in_callback
), this);
2787 g_signal_connect (m_focusWidget
, "focus_out_event",
2788 G_CALLBACK (gtk_window_focus_out_callback
), this);
2792 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2793 G_CALLBACK (gtk_window_focus_in_callback
), this);
2794 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2795 G_CALLBACK (gtk_window_focus_out_callback
), this);
2799 // connect to the various key and mouse handlers
2801 GtkWidget
*connect_widget
= GetConnectWidget();
2803 ConnectWidget( connect_widget
);
2805 /* We cannot set colours, fonts and cursors before the widget has
2806 been realized, so we do this directly after realization */
2807 g_signal_connect (connect_widget
, "realize",
2808 G_CALLBACK (gtk_window_realized_callback
), this);
2812 // Catch native resize events
2813 g_signal_connect (m_wxwindow
, "size_allocate",
2814 G_CALLBACK (gtk_window_size_callback
), this);
2816 // Initialize XIM support
2817 g_signal_connect (m_wxwindow
, "realize",
2818 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2820 // And resize XIM window
2821 g_signal_connect (m_wxwindow
, "size_allocate",
2822 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2825 if (GTK_IS_COMBO(m_widget
))
2827 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2829 g_signal_connect (gcombo
->entry
, "size_request",
2830 G_CALLBACK (wxgtk_combo_size_request_callback
),
2835 // This is needed if we want to add our windows into native
2836 // GTK controls, such as the toolbar. With this callback, the
2837 // toolbar gets to know the correct size (the one set by the
2838 // programmer). Sadly, it misbehaves for wxComboBox.
2839 g_signal_connect (m_widget
, "size_request",
2840 G_CALLBACK (wxgtk_window_size_request_callback
),
2844 InheritAttributes();
2848 // unless the window was created initially hidden (i.e. Hide() had been
2849 // called before Create()), we should show it at GTK+ level as well
2851 gtk_widget_show( m_widget
);
2854 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2856 g_signal_connect (widget
, "key_press_event",
2857 G_CALLBACK (gtk_window_key_press_callback
), this);
2858 g_signal_connect (widget
, "key_release_event",
2859 G_CALLBACK (gtk_window_key_release_callback
), this);
2860 g_signal_connect (widget
, "button_press_event",
2861 G_CALLBACK (gtk_window_button_press_callback
), this);
2862 g_signal_connect (widget
, "button_release_event",
2863 G_CALLBACK (gtk_window_button_release_callback
), this);
2864 g_signal_connect (widget
, "motion_notify_event",
2865 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2866 g_signal_connect (widget
, "scroll_event",
2867 G_CALLBACK (gtk_window_wheel_callback
), this);
2868 g_signal_connect (widget
, "popup_menu",
2869 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2870 g_signal_connect (widget
, "enter_notify_event",
2871 G_CALLBACK (gtk_window_enter_callback
), this);
2872 g_signal_connect (widget
, "leave_notify_event",
2873 G_CALLBACK (gtk_window_leave_callback
), this);
2876 bool wxWindowGTK::Destroy()
2878 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2882 return wxWindowBase::Destroy();
2885 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2887 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2890 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2892 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2893 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2896 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2899 if (m_resizing
) return; /* I don't like recursions */
2902 int currentX
, currentY
;
2903 GetPosition(¤tX
, ¤tY
);
2904 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2906 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2908 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2910 // calculate the best size if we should auto size the window
2911 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2912 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2914 const wxSize sizeBest
= GetBestSize();
2915 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2917 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2918 height
= sizeBest
.y
;
2926 int minWidth
= GetMinWidth(),
2927 minHeight
= GetMinHeight(),
2928 maxWidth
= GetMaxWidth(),
2929 maxHeight
= GetMaxHeight();
2931 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2932 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2933 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2934 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2936 #if wxUSE_TOOLBAR_NATIVE
2937 if (wxDynamicCast(GetParent(), wxToolBar
))
2939 // don't take the x,y values, they're wrong because toolbar sets them
2940 GtkWidget
*widget
= GTK_WIDGET(m_widget
);
2941 gtk_widget_set_size_request (widget
, m_width
, m_height
);
2942 if (GTK_WIDGET_VISIBLE (widget
))
2943 gtk_widget_queue_resize (widget
);
2947 if (m_parent
->m_wxwindow
== NULL
) // i.e. wxNotebook
2949 // don't set the size for children of wxNotebook, just take the values.
2957 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2958 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2960 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2961 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2965 m_x
= x
+ pizza
->xoffset
;
2966 m_y
= y
+ pizza
->yoffset
;
2969 int left_border
= 0;
2970 int right_border
= 0;
2972 int bottom_border
= 0;
2974 /* the default button has a border around it */
2975 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2977 GtkBorder
*default_border
= NULL
;
2978 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2981 left_border
+= default_border
->left
;
2982 right_border
+= default_border
->right
;
2983 top_border
+= default_border
->top
;
2984 bottom_border
+= default_border
->bottom
;
2985 g_free( default_border
);
2989 DoMoveWindow( m_x
-top_border
,
2991 m_width
+left_border
+right_border
,
2992 m_height
+top_border
+bottom_border
);
2997 /* Sometimes the client area changes size without the
2998 whole windows's size changing, but if the whole
2999 windows's size doesn't change, no wxSizeEvent will
3000 normally be sent. Here we add an extra test if
3001 the client test has been changed and this will
3003 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3007 wxPrintf( "OnSize sent from " );
3008 if (GetClassInfo() && GetClassInfo()->GetClassName())
3009 wxPrintf( GetClassInfo()->GetClassName() );
3010 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3013 if (!m_nativeSizeEvent
)
3015 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3016 event
.SetEventObject( this );
3017 GetEventHandler()->ProcessEvent( event
);
3023 void wxWindowGTK::OnInternalIdle()
3025 if ( m_dirtyTabOrder
)
3027 m_dirtyTabOrder
= false;
3031 // Update style if the window was not yet realized
3032 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3033 if (m_needsStyleChange
)
3035 SetBackgroundStyle(GetBackgroundStyle());
3036 m_needsStyleChange
= false;
3039 // Update invalidated regions.
3042 wxCursor cursor
= m_cursor
;
3043 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3047 /* I now set the cursor anew in every OnInternalIdle call
3048 as setting the cursor in a parent window also effects the
3049 windows above so that checking for the current cursor is
3054 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3056 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3058 if (!g_globalCursor
.Ok())
3059 cursor
= *wxSTANDARD_CURSOR
;
3061 window
= m_widget
->window
;
3062 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3063 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3069 GdkWindow
*window
= m_widget
->window
;
3070 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3071 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3076 if (wxUpdateUIEvent::CanUpdate(this))
3077 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3080 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3082 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3084 if (width
) (*width
) = m_width
;
3085 if (height
) (*height
) = m_height
;
3088 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3090 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3094 SetSize( width
, height
);
3101 #ifndef __WXUNIVERSAL__
3102 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3104 /* when using GTK 1.2 we set the shadow border size to 2 */
3108 if (HasFlag(wxSIMPLE_BORDER
))
3110 /* when using GTK 1.2 we set the simple border size to 1 */
3114 #endif // __WXUNIVERSAL__
3118 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3120 GtkRequisition vscroll_req
;
3121 vscroll_req
.width
= 2;
3122 vscroll_req
.height
= 2;
3123 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3124 (scroll_window
->vscrollbar
, &vscroll_req
);
3126 GtkRequisition hscroll_req
;
3127 hscroll_req
.width
= 2;
3128 hscroll_req
.height
= 2;
3129 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3130 (scroll_window
->hscrollbar
, &hscroll_req
);
3132 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3134 if (scroll_window
->vscrollbar_visible
)
3136 dw
+= vscroll_req
.width
;
3137 dw
+= scroll_class
->scrollbar_spacing
;
3140 if (scroll_window
->hscrollbar_visible
)
3142 dh
+= hscroll_req
.height
;
3143 dh
+= scroll_class
->scrollbar_spacing
;
3147 SetSize( width
+dw
, height
+dh
);
3151 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3153 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3157 if (width
) (*width
) = m_width
;
3158 if (height
) (*height
) = m_height
;
3165 #ifndef __WXUNIVERSAL__
3166 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3168 /* when using GTK 1.2 we set the shadow border size to 2 */
3172 if (HasFlag(wxSIMPLE_BORDER
))
3174 /* when using GTK 1.2 we set the simple border size to 1 */
3178 #endif // __WXUNIVERSAL__
3182 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3184 GtkRequisition vscroll_req
;
3185 vscroll_req
.width
= 2;
3186 vscroll_req
.height
= 2;
3187 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3188 (scroll_window
->vscrollbar
, &vscroll_req
);
3190 GtkRequisition hscroll_req
;
3191 hscroll_req
.width
= 2;
3192 hscroll_req
.height
= 2;
3193 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3194 (scroll_window
->hscrollbar
, &hscroll_req
);
3196 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3198 if (scroll_window
->vscrollbar_visible
)
3200 dw
+= vscroll_req
.width
;
3201 dw
+= scroll_class
->scrollbar_spacing
;
3204 if (scroll_window
->hscrollbar_visible
)
3206 dh
+= hscroll_req
.height
;
3207 dh
+= scroll_class
->scrollbar_spacing
;
3211 if (width
) (*width
) = m_width
- dw
;
3212 if (height
) (*height
) = m_height
- dh
;
3216 printf( "GetClientSize, name %s ", GetName().c_str() );
3217 if (width) printf( " width = %d", (*width) );
3218 if (height) printf( " height = %d", (*height) );
3223 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3225 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3229 if (m_parent
&& m_parent
->m_wxwindow
)
3231 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3232 dx
= pizza
->xoffset
;
3233 dy
= pizza
->yoffset
;
3236 if (x
) (*x
) = m_x
- dx
;
3237 if (y
) (*y
) = m_y
- dy
;
3240 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3242 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3244 if (!m_widget
->window
) return;
3246 GdkWindow
*source
= (GdkWindow
*) NULL
;
3248 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3250 source
= m_widget
->window
;
3254 gdk_window_get_origin( source
, &org_x
, &org_y
);
3258 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3260 org_x
+= m_widget
->allocation
.x
;
3261 org_y
+= m_widget
->allocation
.y
;
3269 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3271 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3273 if (!m_widget
->window
) return;
3275 GdkWindow
*source
= (GdkWindow
*) NULL
;
3277 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3279 source
= m_widget
->window
;
3283 gdk_window_get_origin( source
, &org_x
, &org_y
);
3287 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3289 org_x
+= m_widget
->allocation
.x
;
3290 org_y
+= m_widget
->allocation
.y
;
3298 bool wxWindowGTK::Show( bool show
)
3300 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3302 if (!wxWindowBase::Show(show
))
3309 gtk_widget_show( m_widget
);
3311 gtk_widget_hide( m_widget
);
3313 wxShowEvent
eventShow(GetId(), show
);
3314 eventShow
.SetEventObject(this);
3316 GetEventHandler()->ProcessEvent(eventShow
);
3321 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3323 win
->OnParentEnable(enable
);
3325 // Recurse, so that children have the opportunity to Do The Right Thing
3326 // and reset colours that have been messed up by a parent's (really ancestor's)
3328 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3330 node
= node
->GetNext() )
3332 wxWindow
*child
= node
->GetData();
3333 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3334 wxWindowNotifyEnable(child
, enable
);
3338 bool wxWindowGTK::Enable( bool enable
)
3340 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3342 if (!wxWindowBase::Enable(enable
))
3348 gtk_widget_set_sensitive( m_widget
, enable
);
3350 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3352 wxWindowNotifyEnable(this, enable
);
3357 int wxWindowGTK::GetCharHeight() const
3359 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3361 wxFont font
= GetFont();
3362 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3364 PangoContext
*context
= NULL
;
3366 context
= gtk_widget_get_pango_context( m_widget
);
3371 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3372 PangoLayout
*layout
= pango_layout_new(context
);
3373 pango_layout_set_font_description(layout
, desc
);
3374 pango_layout_set_text(layout
, "H", 1);
3375 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3377 PangoRectangle rect
;
3378 pango_layout_line_get_extents(line
, NULL
, &rect
);
3380 g_object_unref( G_OBJECT( layout
) );
3382 return (int) PANGO_PIXELS(rect
.height
);
3385 int wxWindowGTK::GetCharWidth() const
3387 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3389 wxFont font
= GetFont();
3390 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3392 PangoContext
*context
= NULL
;
3394 context
= gtk_widget_get_pango_context( m_widget
);
3399 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3400 PangoLayout
*layout
= pango_layout_new(context
);
3401 pango_layout_set_font_description(layout
, desc
);
3402 pango_layout_set_text(layout
, "g", 1);
3403 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3405 PangoRectangle rect
;
3406 pango_layout_line_get_extents(line
, NULL
, &rect
);
3408 g_object_unref( G_OBJECT( layout
) );
3410 return (int) PANGO_PIXELS(rect
.width
);
3413 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3417 int *externalLeading
,
3418 const wxFont
*theFont
) const
3420 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3422 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3431 PangoContext
*context
= NULL
;
3433 context
= gtk_widget_get_pango_context( m_widget
);
3442 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3443 PangoLayout
*layout
= pango_layout_new(context
);
3444 pango_layout_set_font_description(layout
, desc
);
3447 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3448 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3450 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3451 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3452 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3456 PangoRectangle rect
;
3457 pango_layout_get_extents(layout
, NULL
, &rect
);
3459 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3460 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3463 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3464 int baseline
= pango_layout_iter_get_baseline(iter
);
3465 pango_layout_iter_free(iter
);
3466 *descent
= *y
- PANGO_PIXELS(baseline
);
3468 if (externalLeading
) (*externalLeading
) = 0; // ??
3470 g_object_unref( G_OBJECT( layout
) );
3473 void wxWindowGTK::SetFocus()
3475 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3478 // don't do anything if we already have focus
3484 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3486 gtk_widget_grab_focus (m_wxwindow
);
3491 if (GTK_IS_CONTAINER(m_widget
))
3493 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3496 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3499 if (!GTK_WIDGET_REALIZED(m_widget
))
3501 // we can't set the focus to the widget now so we remember that
3502 // it should be focused and will do it later, during the idle
3503 // time, as soon as we can
3504 wxLogTrace(TRACE_FOCUS
,
3505 _T("Delaying setting focus to %s(%s)"),
3506 GetClassInfo()->GetClassName(), GetLabel().c_str());
3508 g_delayedFocus
= this;
3512 wxLogTrace(TRACE_FOCUS
,
3513 _T("Setting focus to %s(%s)"),
3514 GetClassInfo()->GetClassName(), GetLabel().c_str());
3516 gtk_widget_grab_focus (m_widget
);
3521 wxLogTrace(TRACE_FOCUS
,
3522 _T("Can't set focus to %s(%s)"),
3523 GetClassInfo()->GetClassName(), GetLabel().c_str());
3528 bool wxWindowGTK::AcceptsFocus() const
3530 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3533 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3535 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3537 wxWindowGTK
*oldParent
= m_parent
,
3538 *newParent
= (wxWindowGTK
*)newParentBase
;
3540 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3542 if ( !wxWindowBase::Reparent(newParent
) )
3545 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3547 /* prevent GTK from deleting the widget arbitrarily */
3548 gtk_widget_ref( m_widget
);
3552 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3555 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3559 /* insert GTK representation */
3560 (*(newParent
->m_insertCallback
))(newParent
, this);
3563 /* reverse: prevent GTK from deleting the widget arbitrarily */
3564 gtk_widget_unref( m_widget
);
3569 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3571 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3573 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3575 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3580 /* insert GTK representation */
3581 (*m_insertCallback
)(this, child
);
3584 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3586 wxWindowBase::AddChild(child
);
3587 m_dirtyTabOrder
= true;
3589 wxapp_install_idle_handler();
3592 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3594 wxWindowBase::RemoveChild(child
);
3595 m_dirtyTabOrder
= true;
3597 wxapp_install_idle_handler();
3600 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3602 wxWindowBase::DoMoveInTabOrder(win
, move
);
3603 m_dirtyTabOrder
= true;
3605 wxapp_install_idle_handler();
3608 bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3610 // none needed by default
3614 void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget
* WXUNUSED(w
))
3616 // nothing to do by default since none is needed
3619 void wxWindowGTK::RealizeTabOrder()
3623 if ( !m_children
.empty() )
3625 // we don't only construct the correct focus chain but also use
3626 // this opportunity to update the mnemonic widgets for the widgets
3629 GList
*chain
= NULL
;
3630 wxWindowGTK
* mnemonicWindow
= NULL
;
3632 for ( wxWindowList::const_iterator i
= m_children
.begin();
3633 i
!= m_children
.end();
3636 wxWindowGTK
*win
= *i
;
3638 if ( mnemonicWindow
)
3640 if ( win
->AcceptsFocusFromKeyboard() )
3642 // wxComboBox et al. needs to focus on on a different
3643 // widget than m_widget, so if the main widget isn't
3644 // focusable try the connect widget
3645 GtkWidget
* w
= win
->m_widget
;
3646 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3648 w
= win
->GetConnectWidget();
3649 if ( !GTK_WIDGET_CAN_FOCUS(w
) )
3655 mnemonicWindow
->GTKWidgetDoSetMnemonic(w
);
3656 mnemonicWindow
= NULL
;
3660 else if ( win
->GTKWidgetNeedsMnemonic() )
3662 mnemonicWindow
= win
;
3665 chain
= g_list_prepend(chain
, win
->m_widget
);
3668 chain
= g_list_reverse(chain
);
3670 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3675 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3680 void wxWindowGTK::Raise()
3682 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3684 if (m_wxwindow
&& m_wxwindow
->window
)
3686 gdk_window_raise( m_wxwindow
->window
);
3688 else if (m_widget
->window
)
3690 gdk_window_raise( m_widget
->window
);
3694 void wxWindowGTK::Lower()
3696 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3698 if (m_wxwindow
&& m_wxwindow
->window
)
3700 gdk_window_lower( m_wxwindow
->window
);
3702 else if (m_widget
->window
)
3704 gdk_window_lower( m_widget
->window
);
3708 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3710 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3712 if (cursor
== m_cursor
)
3716 wxapp_install_idle_handler();
3718 if (cursor
== wxNullCursor
)
3719 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3721 return wxWindowBase::SetCursor( cursor
);
3724 void wxWindowGTK::WarpPointer( int x
, int y
)
3726 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3728 // We provide this function ourselves as it is
3729 // missing in GDK (top of this file).
3731 GdkWindow
*window
= (GdkWindow
*) NULL
;
3733 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3735 window
= GetConnectWidget()->window
;
3738 gdk_window_warp_pointer( window
, x
, y
);
3741 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3743 double value_start
= adj
->value
;
3744 double value
= value_start
+ change
;
3745 double upper
= adj
->upper
- adj
->page_size
;
3750 // Lower bound will be checked by gtk_adjustment_set_value
3751 gtk_adjustment_set_value(adj
, value
);
3752 return adj
->value
!= value_start
;
3755 bool wxWindowGTK::ScrollLines(int lines
)
3758 m_vAdjust
!= NULL
&&
3759 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3762 bool wxWindowGTK::ScrollPages(int pages
)
3765 m_vAdjust
!= NULL
&&
3766 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3769 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3771 wxASSERT(m_vAdjust
== NULL
);
3775 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3779 if (!m_widget
->window
)
3784 GdkRectangle gdk_rect
,
3788 gdk_rect
.x
= rect
->x
;
3789 gdk_rect
.y
= rect
->y
;
3790 gdk_rect
.width
= rect
->width
;
3791 gdk_rect
.height
= rect
->height
;
3794 else // invalidate everything
3799 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3803 void wxWindowGTK::Update()
3807 // when we call Update() we really want to update the window immediately on
3808 // screen, even if it means flushing the entire queue and hence slowing down
3809 // everything -- but it should still be done, it's just that Update() should
3810 // be called very rarely
3814 void wxWindowGTK::GtkUpdate()
3816 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3817 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3819 // for consistency with other platforms (and also because it's convenient
3820 // to be able to update an entire TLW by calling Update() only once), we
3821 // should also update all our children here
3822 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3824 node
= node
->GetNext() )
3826 node
->GetData()->GtkUpdate();
3830 void wxWindowGTK::GtkSendPaintEvents()
3834 m_updateRegion
.Clear();
3838 // Clip to paint region in wxClientDC
3839 m_clipPaintRegion
= true;
3841 // widget to draw on
3842 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3844 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3846 // find ancestor from which to steal background
3847 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3849 parent
= (wxWindow
*)this;
3851 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3853 wxRegionIterator
upd( m_updateRegion
);
3857 rect
.x
= upd
.GetX();
3858 rect
.y
= upd
.GetY();
3859 rect
.width
= upd
.GetWidth();
3860 rect
.height
= upd
.GetHeight();
3862 gtk_paint_flat_box( parent
->m_widget
->style
,
3864 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3878 wxWindowDC
dc( (wxWindow
*)this );
3879 dc
.SetClippingRegion( m_updateRegion
);
3881 wxEraseEvent
erase_event( GetId(), &dc
);
3882 erase_event
.SetEventObject( this );
3884 GetEventHandler()->ProcessEvent(erase_event
);
3887 wxNcPaintEvent
nc_paint_event( GetId() );
3888 nc_paint_event
.SetEventObject( this );
3889 GetEventHandler()->ProcessEvent( nc_paint_event
);
3891 wxPaintEvent
paint_event( GetId() );
3892 paint_event
.SetEventObject( this );
3893 GetEventHandler()->ProcessEvent( paint_event
);
3895 m_clipPaintRegion
= false;
3897 m_updateRegion
.Clear();
3900 void wxWindowGTK::ClearBackground()
3902 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3906 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3908 wxWindowBase::DoSetToolTip(tip
);
3911 m_tooltip
->Apply( (wxWindow
*)this );
3914 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3916 wxString
tmp( tip
);
3917 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3919 #endif // wxUSE_TOOLTIPS
3921 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3923 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3925 if (!wxWindowBase::SetBackgroundColour(colour
))
3930 // We need the pixel value e.g. for background clearing.
3931 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3934 // apply style change (forceStyle=true so that new style is applied
3935 // even if the bg colour changed from valid to wxNullColour)
3936 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3937 ApplyWidgetStyle(true);
3942 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3944 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3946 if (!wxWindowBase::SetForegroundColour(colour
))
3953 // We need the pixel value e.g. for background clearing.
3954 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3957 // apply style change (forceStyle=true so that new style is applied
3958 // even if the bg colour changed from valid to wxNullColour):
3959 ApplyWidgetStyle(true);
3964 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3966 return gtk_widget_get_pango_context( m_widget
);
3969 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3971 // do we need to apply any changes at all?
3974 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3979 GtkRcStyle
*style
= gtk_rc_style_new();
3984 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3987 if ( m_foregroundColour
.Ok() )
3989 GdkColor
*fg
= m_foregroundColour
.GetColor();
3991 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3992 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3994 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3995 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3997 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3998 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4001 if ( m_backgroundColour
.Ok() )
4003 GdkColor
*bg
= m_backgroundColour
.GetColor();
4005 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4006 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4007 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4008 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4010 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4011 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4012 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4013 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4015 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4016 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4017 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4018 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4020 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4021 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4022 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4023 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4029 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4031 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4034 DoApplyWidgetStyle(style
);
4035 gtk_rc_style_unref(style
);
4038 // Style change may affect GTK+'s size calculation:
4039 InvalidateBestSize();
4042 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4045 gtk_widget_modify_style(m_wxwindow
, style
);
4047 gtk_widget_modify_style(m_widget
, style
);
4050 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4052 wxWindowBase::SetBackgroundStyle(style
);
4054 if (style
== wxBG_STYLE_CUSTOM
)
4056 GdkWindow
*window
= (GdkWindow
*) NULL
;
4058 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4060 window
= GetConnectWidget()->window
;
4064 // Make sure GDK/X11 doesn't refresh the window
4066 gdk_window_set_back_pixmap( window
, None
, False
);
4068 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4071 m_needsStyleChange
= false;
4074 // Do in OnIdle, because the window is not yet available
4075 m_needsStyleChange
= true;
4077 // Don't apply widget style, or we get a grey background
4081 // apply style change (forceStyle=true so that new style is applied
4082 // even if the bg colour changed from valid to wxNullColour):
4083 ApplyWidgetStyle(true);
4088 #if wxUSE_DRAG_AND_DROP
4090 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4092 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4094 GtkWidget
*dnd_widget
= GetConnectWidget();
4096 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4098 if (m_dropTarget
) delete m_dropTarget
;
4099 m_dropTarget
= dropTarget
;
4101 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4104 #endif // wxUSE_DRAG_AND_DROP
4106 GtkWidget
* wxWindowGTK::GetConnectWidget()
4108 GtkWidget
*connect_widget
= m_widget
;
4109 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4111 return connect_widget
;
4114 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4117 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4119 return (window
== m_widget
->window
);
4122 bool wxWindowGTK::SetFont( const wxFont
&font
)
4124 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4126 if (!wxWindowBase::SetFont(font
))
4129 // apply style change (forceStyle=true so that new style is applied
4130 // even if the font changed from valid to wxNullFont):
4131 ApplyWidgetStyle(true);
4136 void wxWindowGTK::DoCaptureMouse()
4138 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4140 GdkWindow
*window
= (GdkWindow
*) NULL
;
4142 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4144 window
= GetConnectWidget()->window
;
4146 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4148 wxCursor
* cursor
= & m_cursor
;
4150 cursor
= wxSTANDARD_CURSOR
;
4152 gdk_pointer_grab( window
, FALSE
,
4154 (GDK_BUTTON_PRESS_MASK
|
4155 GDK_BUTTON_RELEASE_MASK
|
4156 GDK_POINTER_MOTION_HINT_MASK
|
4157 GDK_POINTER_MOTION_MASK
),
4159 cursor
->GetCursor(),
4160 (guint32
)GDK_CURRENT_TIME
);
4161 g_captureWindow
= this;
4162 g_captureWindowHasMouse
= true;
4165 void wxWindowGTK::DoReleaseMouse()
4167 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4169 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4171 g_captureWindow
= (wxWindowGTK
*) NULL
;
4173 GdkWindow
*window
= (GdkWindow
*) NULL
;
4175 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4177 window
= GetConnectWidget()->window
;
4182 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4186 wxWindow
*wxWindowBase::GetCapture()
4188 return (wxWindow
*)g_captureWindow
;
4191 bool wxWindowGTK::IsRetained() const
4196 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4197 int range
, bool refresh
)
4199 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4201 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4203 m_hasScrolling
= true;
4205 if (orient
== wxHORIZONTAL
)
4207 float fpos
= (float)pos
;
4208 float frange
= (float)range
;
4209 float fthumb
= (float)thumbVisible
;
4210 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4211 if (fpos
< 0.0) fpos
= 0.0;
4213 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4214 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4216 SetScrollPos( orient
, pos
, refresh
);
4220 m_oldHorizontalPos
= fpos
;
4222 m_hAdjust
->lower
= 0.0;
4223 m_hAdjust
->upper
= frange
;
4224 m_hAdjust
->value
= fpos
;
4225 m_hAdjust
->step_increment
= 1.0;
4226 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4227 m_hAdjust
->page_size
= fthumb
;
4231 float fpos
= (float)pos
;
4232 float frange
= (float)range
;
4233 float fthumb
= (float)thumbVisible
;
4234 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4235 if (fpos
< 0.0) fpos
= 0.0;
4237 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4238 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4240 SetScrollPos( orient
, pos
, refresh
);
4244 m_oldVerticalPos
= fpos
;
4246 m_vAdjust
->lower
= 0.0;
4247 m_vAdjust
->upper
= frange
;
4248 m_vAdjust
->value
= fpos
;
4249 m_vAdjust
->step_increment
= 1.0;
4250 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4251 m_vAdjust
->page_size
= fthumb
;
4254 if (orient
== wxHORIZONTAL
)
4255 g_signal_emit_by_name (m_hAdjust
, "changed");
4257 g_signal_emit_by_name (m_vAdjust
, "changed");
4260 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4262 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4263 gpointer fn
= orient
== wxHORIZONTAL
4264 ? (gpointer
) gtk_window_hscroll_callback
4265 : (gpointer
) gtk_window_vscroll_callback
;
4267 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4268 g_signal_emit_by_name (adj
, "value_changed");
4269 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4272 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4274 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4275 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4277 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4279 float fpos
= (float)pos
;
4280 if (fpos
> adj
->upper
- adj
->page_size
)
4281 fpos
= adj
->upper
- adj
->page_size
;
4284 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4286 if (fabs(fpos
-adj
->value
) < 0.2)
4290 if ( m_wxwindow
->window
)
4295 int wxWindowGTK::GetScrollThumb( int orient
) const
4297 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4299 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4301 if (orient
== wxHORIZONTAL
)
4302 return (int)(m_hAdjust
->page_size
+0.5);
4304 return (int)(m_vAdjust
->page_size
+0.5);
4307 int wxWindowGTK::GetScrollPos( int orient
) const
4309 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4311 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4313 if (orient
== wxHORIZONTAL
)
4314 return (int)(m_hAdjust
->value
+0.5);
4316 return (int)(m_vAdjust
->value
+0.5);
4319 int wxWindowGTK::GetScrollRange( int orient
) const
4321 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4323 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4325 if (orient
== wxHORIZONTAL
)
4326 return (int)(m_hAdjust
->upper
+0.5);
4328 return (int)(m_vAdjust
->upper
+0.5);
4331 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4333 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4335 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4337 // No scrolling requested.
4338 if ((dx
== 0) && (dy
== 0)) return;
4340 m_clipPaintRegion
= true;
4342 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4344 m_clipPaintRegion
= false;
4347 void wxWindowGTK::SetWindowStyleFlag( long style
)
4349 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4350 wxWindowBase::SetWindowStyleFlag(style
);
4353 // Find the wxWindow at the current mouse position, also returning the mouse
4355 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4357 pt
= wxGetMousePosition();
4358 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4362 // Get the current mouse position.
4363 wxPoint
wxGetMousePosition()
4365 /* This crashes when used within wxHelpContext,
4366 so we have to use the X-specific implementation below.
4368 GdkModifierType *mask;
4369 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4371 return wxPoint(x, y);
4375 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4377 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4378 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4379 Window rootReturn
, childReturn
;
4380 int rootX
, rootY
, winX
, winY
;
4381 unsigned int maskReturn
;
4383 XQueryPointer (display
,
4387 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4388 return wxPoint(rootX
, rootY
);
4392 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4393 void wxAddGrab(wxWindow
* window
)
4395 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4398 void wxRemoveGrab(wxWindow
* window
)
4400 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4403 // ----------------------------------------------------------------------------
4405 // ----------------------------------------------------------------------------
4407 class wxWinModule
: public wxModule
4414 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4417 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4419 bool wxWinModule::OnInit()
4421 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4422 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4427 void wxWinModule::OnExit()
4430 gdk_gc_unref( g_eraseGC
);