1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
18 #include "wx/dcclient.h"
21 #include "wx/layout.h"
23 #include "wx/dialog.h"
24 #include "wx/msgdlg.h"
25 #include "wx/module.h"
26 #include "wx/combobox.h"
28 #if wxUSE_DRAG_AND_DROP
33 #include "wx/tooltip.h"
41 #include "wx/textctrl.h"
45 #include "wx/statusbr.h"
47 #include "wx/settings.h"
49 #include "wx/fontutil.h"
50 #include "wx/stattext.h"
53 #include "wx/thread.h"
59 #include "wx/gtk/private.h"
60 #include <gdk/gdkprivate.h>
61 #include <gdk/gdkkeysyms.h>
65 #include <gtk/gtkprivate.h>
67 #include "wx/gtk/win_gtk.h"
69 #include <pango/pangox.h>
75 extern GtkContainerClass
*pizza_parent_class
;
77 //-----------------------------------------------------------------------------
78 // documentation on internals
79 //-----------------------------------------------------------------------------
82 I have been asked several times about writing some documentation about
83 the GTK port of wxWidgets, especially its internal structures. Obviously,
84 you cannot understand wxGTK without knowing a little about the GTK, but
85 some more information about what the wxWindow, which is the base class
86 for all other window classes, does seems required as well.
90 What does wxWindow do? It contains the common interface for the following
91 jobs of its descendants:
93 1) Define the rudimentary behaviour common to all window classes, such as
94 resizing, intercepting user input (so as to make it possible to use these
95 events for special purposes in a derived class), window names etc.
97 2) Provide the possibility to contain and manage children, if the derived
98 class is allowed to contain children, which holds true for those window
99 classes which do not display a native GTK widget. To name them, these
100 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
101 work classes are a special case and are handled a bit differently from
102 the rest. The same holds true for the wxNotebook class.
104 3) Provide the possibility to draw into a client area of a window. This,
105 too, only holds true for classes that do not display a native GTK widget
108 4) Provide the entire mechanism for scrolling widgets. This actual inter-
109 face for this is usually in wxScrolledWindow, but the GTK implementation
112 5) A multitude of helper or extra methods for special purposes, such as
113 Drag'n'Drop, managing validators etc.
115 6) Display a border (sunken, raised, simple or none).
117 Normally one might expect, that one wxWidgets window would always correspond
118 to one GTK widget. Under GTK, there is no such allround widget that has all
119 the functionality. Moreover, the GTK defines a client area as a different
120 widget from the actual widget you are handling. Last but not least some
121 special classes (e.g. wxFrame) handle different categories of widgets and
122 still have the possibility to draw something in the client area.
123 It was therefore required to write a special purpose GTK widget, that would
124 represent a client area in the sense of wxWidgets capable to do the jobs
125 2), 3) and 4). I have written this class and it resides in win_gtk.c of
128 All windows must have a widget, with which they interact with other under-
129 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
130 the wxWindow class has a member variable called m_widget which holds a
131 pointer to this widget. When the window class represents a GTK native widget,
132 this is (in most cases) the only GTK widget the class manages. E.g. the
133 wxStaticText class handles only a GtkLabel widget a pointer to which you
134 can find in m_widget (defined in wxWindow)
136 When the class has a client area for drawing into and for containing children
137 it has to handle the client area widget (of the type GtkPizza, defined in
138 win_gtk.c), but there could be any number of widgets, handled by a class
139 The common rule for all windows is only, that the widget that interacts with
140 the rest of GTK must be referenced in m_widget and all other widgets must be
141 children of this widget on the GTK level. The top-most widget, which also
142 represents the client area, must be in the m_wxwindow field and must be of
145 As I said, the window classes that display a GTK native widget only have
146 one widget, so in the case of e.g. the wxButton class m_widget holds a
147 pointer to a GtkButton widget. But windows with client areas (for drawing
148 and children) have a m_widget field that is a pointer to a GtkScrolled-
149 Window and a m_wxwindow field that is pointer to a GtkPizza and this
150 one is (in the GTK sense) a child of the GtkScrolledWindow.
152 If the m_wxwindow field is set, then all input to this widget is inter-
153 cepted and sent to the wxWidgets class. If not, all input to the widget
154 that gets pointed to by m_widget gets intercepted and sent to the class.
158 The design of scrolling in wxWidgets is markedly different from that offered
159 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
160 clicking on a scrollbar belonging to scrolled window will inevitably move
161 the window. In wxWidgets, the scrollbar will only emit an event, send this
162 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
163 which actually moves the window and its subchildren. Note that GtkPizza
164 memorizes how much it has been scrolled but that wxWidgets forgets this
165 so that the two coordinates systems have to be kept in synch. This is done
166 in various places using the pizza->xoffset and pizza->yoffset values.
170 Singularily the most broken code in GTK is the code that is supposed to
171 inform subwindows (child windows) about new positions. Very often, duplicate
172 events are sent without changes in size or position, equally often no
173 events are sent at all (All this is due to a bug in the GtkContainer code
174 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
175 GTK's own system and it simply waits for size events for toplevel windows
176 and then iterates down the respective size events to all window. This has
177 the disadvantage that windows might get size events before the GTK widget
178 actually has the reported size. This doesn't normally pose any problem, but
179 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
180 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
181 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
182 window that is used for OpenGL output really has that size (as reported by
187 If someone at some point of time feels the immense desire to have a look at,
188 change or attempt to optimise the Refresh() logic, this person will need an
189 intimate understanding of what "draw" and "expose" events are and what
190 they are used for, in particular when used in connection with GTK's
191 own windowless widgets. Beware.
195 Cursors, too, have been a constant source of pleasure. The main difficulty
196 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
197 for the parent. To prevent this from doing too much harm, I use idle time
198 to set the cursor over and over again, starting from the toplevel windows
199 and ending with the youngest generation (speaking of parent and child windows).
200 Also don't forget that cursors (like much else) are connected to GdkWindows,
201 not GtkWidgets and that the "window" field of a GtkWidget might very well
202 point to the GdkWindow of the parent widget (-> "window-less widget") and
203 that the two obviously have very different meanings.
207 //-----------------------------------------------------------------------------
209 //-----------------------------------------------------------------------------
211 extern wxList wxPendingDelete
;
212 extern bool g_blockEventsOnDrag
;
213 extern bool g_blockEventsOnScroll
;
214 extern wxCursor g_globalCursor
;
216 static GdkGC
*g_eraseGC
= NULL
;
218 // mouse capture state: the window which has it and if the mouse is currently
220 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
221 static bool g_captureWindowHasMouse
= false;
223 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
225 // the last window which had the focus - this is normally never NULL (except
226 // if we never had focus at all) as even when g_focusWindow is NULL it still
227 // keeps its previous value
228 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
230 // If a window get the focus set but has not been realized
231 // yet, defer setting the focus to idle time.
232 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
234 extern bool g_mainThreadLocked
;
236 //-----------------------------------------------------------------------------
238 //-----------------------------------------------------------------------------
243 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
245 # define DEBUG_MAIN_THREAD
248 #define DEBUG_MAIN_THREAD
251 // the trace mask used for the focus debugging messages
252 #define TRACE_FOCUS _T("focus")
254 //-----------------------------------------------------------------------------
255 // missing gdk functions
256 //-----------------------------------------------------------------------------
259 gdk_window_warp_pointer (GdkWindow
*window
,
264 window
= GDK_ROOT_PARENT();
266 if (!GDK_WINDOW_DESTROYED(window
))
268 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
269 None
, /* not source window -> move from anywhere */
270 GDK_WINDOW_XID(window
), /* dest window */
271 0, 0, 0, 0, /* not source window -> move from anywhere */
276 //-----------------------------------------------------------------------------
278 //-----------------------------------------------------------------------------
280 extern void wxapp_install_idle_handler();
281 extern bool g_isIdle
;
283 //-----------------------------------------------------------------------------
284 // local code (see below)
285 //-----------------------------------------------------------------------------
287 // returns the child of win which currently has focus or NULL if not found
289 // Note: can't be static, needed by textctrl.cpp.
290 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
292 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
294 return (wxWindow
*)NULL
;
296 if ( winFocus
== win
)
297 return (wxWindow
*)win
;
299 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
301 node
= node
->GetNext() )
303 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
308 return (wxWindow
*)NULL
;
311 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
313 // wxUniversal widgets draw the borders and scrollbars themselves
314 #ifndef __WXUNIVERSAL__
321 if (win
->m_hasScrolling
)
323 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
325 GtkRequisition vscroll_req
;
326 vscroll_req
.width
= 2;
327 vscroll_req
.height
= 2;
328 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
329 (scroll_window
->vscrollbar
, &vscroll_req
);
331 GtkRequisition hscroll_req
;
332 hscroll_req
.width
= 2;
333 hscroll_req
.height
= 2;
334 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
335 (scroll_window
->hscrollbar
, &hscroll_req
);
337 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
339 if (scroll_window
->vscrollbar_visible
)
341 dw
+= vscroll_req
.width
;
342 dw
+= scroll_class
->scrollbar_spacing
;
345 if (scroll_window
->hscrollbar_visible
)
347 dh
+= hscroll_req
.height
;
348 dh
+= scroll_class
->scrollbar_spacing
;
354 if (GTK_WIDGET_NO_WINDOW (widget
))
356 dx
+= widget
->allocation
.x
;
357 dy
+= widget
->allocation
.y
;
360 if (win
->HasFlag(wxRAISED_BORDER
))
362 gtk_paint_shadow (widget
->style
,
366 NULL
, NULL
, NULL
, // FIXME: No clipping?
368 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
372 if (win
->HasFlag(wxSUNKEN_BORDER
))
374 gtk_paint_shadow (widget
->style
,
378 NULL
, NULL
, NULL
, // FIXME: No clipping?
380 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
384 if (win
->HasFlag(wxSIMPLE_BORDER
))
387 gc
= gdk_gc_new( widget
->window
);
388 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
389 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
391 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
395 #endif // __WXUNIVERSAL__
398 //-----------------------------------------------------------------------------
399 // "expose_event" of m_widget
400 //-----------------------------------------------------------------------------
403 static gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
405 if (gdk_event
->count
> 0) return FALSE
;
407 draw_frame( widget
, win
);
409 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
415 //-----------------------------------------------------------------------------
416 // "size_request" of m_widget
417 //-----------------------------------------------------------------------------
419 // make it extern because wxStaticText needs to disconnect this one
421 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
422 GtkRequisition
*requisition
,
426 win
->GetSize( &w
, &h
);
432 requisition
->height
= h
;
433 requisition
->width
= w
;
439 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
440 GtkRequisition
*requisition
,
443 // This callback is actually hooked into the text entry
444 // of the combo box, not the GtkHBox.
447 win
->GetSize( &w
, &h
);
453 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
455 GtkRequisition entry_req
;
457 entry_req
.height
= 2;
458 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
459 (gcombo
->button
, &entry_req
);
461 requisition
->width
= w
- entry_req
.width
;
462 requisition
->height
= entry_req
.height
;
466 //-----------------------------------------------------------------------------
467 // "expose_event" of m_wxwindow
468 //-----------------------------------------------------------------------------
471 static int gtk_window_expose_callback( GtkWidget
*widget
,
472 GdkEventExpose
*gdk_event
,
478 wxapp_install_idle_handler();
480 // This callback gets called in drawing-idle time under
481 // GTK 2.0, so we don't need to defer anything to idle
484 GtkPizza
*pizza
= GTK_PIZZA( widget
);
485 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
490 wxPrintf( wxT("OnExpose from ") );
491 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
492 wxPrintf( win
->GetClassInfo()->GetClassName() );
493 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
494 (int)gdk_event
->area
.y
,
495 (int)gdk_event
->area
.width
,
496 (int)gdk_event
->area
.height
);
501 win
->m_wxwindow
->style
,
505 (GdkRectangle
*) NULL
,
507 (char *)"button", // const_cast
512 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
514 win
->GtkSendPaintEvents();
517 // Let parent window draw window-less widgets
518 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
524 //-----------------------------------------------------------------------------
525 // "key_press_event" from any window
526 //-----------------------------------------------------------------------------
528 // set WXTRACE to this to see the key event codes on the console
529 #define TRACE_KEYS _T("keyevent")
531 // translates an X key symbol to WXK_XXX value
533 // if isChar is true it means that the value returned will be used for EVT_CHAR
534 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
535 // for example, while if it is false it means that the value is going to be
536 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
538 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
544 // Shift, Control and Alt don't generate the CHAR events at all
547 key_code
= isChar
? 0 : WXK_SHIFT
;
551 key_code
= isChar
? 0 : WXK_CONTROL
;
559 key_code
= isChar
? 0 : WXK_ALT
;
562 // neither do the toggle modifies
563 case GDK_Scroll_Lock
:
564 key_code
= isChar
? 0 : WXK_SCROLL
;
568 key_code
= isChar
? 0 : WXK_CAPITAL
;
572 key_code
= isChar
? 0 : WXK_NUMLOCK
;
576 // various other special keys
589 case GDK_ISO_Left_Tab
:
596 key_code
= WXK_RETURN
;
600 key_code
= WXK_CLEAR
;
604 key_code
= WXK_PAUSE
;
608 key_code
= WXK_SELECT
;
612 key_code
= WXK_PRINT
;
616 key_code
= WXK_EXECUTE
;
620 key_code
= WXK_ESCAPE
;
623 // cursor and other extended keyboard keys
625 key_code
= WXK_DELETE
;
641 key_code
= WXK_RIGHT
;
648 case GDK_Prior
: // == GDK_Page_Up
649 key_code
= WXK_PRIOR
;
652 case GDK_Next
: // == GDK_Page_Down
665 key_code
= WXK_INSERT
;
680 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
684 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
688 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
692 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
696 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
700 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
704 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
708 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
712 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
716 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
720 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
724 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
728 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
731 case GDK_KP_Prior
: // == GDK_KP_Page_Up
732 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
735 case GDK_KP_Next
: // == GDK_KP_Page_Down
736 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
740 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
744 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
748 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
752 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
756 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
759 case GDK_KP_Multiply
:
760 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
764 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
767 case GDK_KP_Separator
:
768 // FIXME: what is this?
769 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
772 case GDK_KP_Subtract
:
773 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
777 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
781 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
798 key_code
= WXK_F1
+ keysym
- GDK_F1
;
808 static inline bool wxIsAsciiKeysym(KeySym ks
)
813 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
815 GdkEventKey
*gdk_event
)
819 GdkModifierType state
;
820 if (gdk_event
->window
)
821 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
823 event
.SetTimestamp( gdk_event
->time
);
824 event
.SetId(win
->GetId());
825 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
826 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
827 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
828 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
829 event
.m_scanCode
= gdk_event
->keyval
;
830 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
831 event
.m_rawFlags
= 0;
833 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
834 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
836 event
.m_uniChar
= toupper(event
.m_uniChar
);
839 wxGetMousePosition( &x
, &y
);
840 win
->ScreenToClient( &x
, &y
);
843 event
.SetEventObject( win
);
848 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
850 GdkEventKey
*gdk_event
)
852 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
853 // but only event->keyval which is quite useless to us, so remember
854 // the last character from GDK_KEY_PRESS and reuse it as last resort
856 // NB: should be MT-safe as we're always called from the main thread only
861 } s_lastKeyPress
= { 0, 0 };
863 KeySym keysym
= gdk_event
->keyval
;
865 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
866 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
870 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
874 // do we have the translation or is it a plain ASCII character?
875 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
877 // we should use keysym if it is ASCII as X does some translations
878 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
879 // which we don't want here (but which we do use for OnChar())
880 if ( !wxIsAsciiKeysym(keysym
) )
882 keysym
= (KeySym
)gdk_event
->string
[0];
885 // we want to always get the same key code when the same key is
886 // pressed regardless of the state of the modifiers, i.e. on a
887 // standard US keyboard pressing '5' or '%' ('5' key with
888 // Shift) should result in the same key code in OnKeyDown():
889 // '5' (although OnChar() will get either '5' or '%').
891 // to do it we first translate keysym to keycode (== scan code)
892 // and then back but always using the lower register
893 Display
*dpy
= (Display
*)wxGetDisplay();
894 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
896 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
898 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
900 // use the normalized, i.e. lower register, keysym if we've
902 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
904 // as explained above, we want to have lower register key codes
905 // normally but for the letter keys we want to have the upper ones
907 // NB: don't use XConvertCase() here, we want to do it for letters
909 key_code
= toupper(key_code
);
911 else // non ASCII key, what to do?
913 // by default, ignore it
916 // but if we have cached information from the last KEY_PRESS
917 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
920 if ( keysym
== s_lastKeyPress
.keysym
)
922 key_code
= s_lastKeyPress
.keycode
;
927 if ( gdk_event
->type
== GDK_KEY_PRESS
)
929 // remember it to be reused for KEY_UP event later
930 s_lastKeyPress
.keysym
= keysym
;
931 s_lastKeyPress
.keycode
= key_code
;
935 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
937 // sending unknown key events doesn't really make sense
941 // now fill all the other fields
942 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
944 event
.m_keyCode
= key_code
;
952 GtkIMContext
*context
;
953 GdkEventKey
*lastKeyEvent
;
957 context
= gtk_im_multicontext_new();
962 g_object_unref(context
);
967 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
968 GdkEventKey
*gdk_event
,
974 wxapp_install_idle_handler();
978 if (g_blockEventsOnDrag
)
982 wxKeyEvent
event( wxEVT_KEY_DOWN
);
984 bool return_after_IM
= false;
986 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
988 // Emit KEY_DOWN event
989 ret
= win
->GetEventHandler()->ProcessEvent( event
);
993 // Return after IM processing as we cannot do
994 // anything with it anyhow.
995 return_after_IM
= true;
998 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
999 // When we get a key_press event here, it could be originate
1000 // from the current widget or its child widgets. However, only the widget
1001 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1002 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1003 // originated from its child widgets and shouldn't be passed to IM context.
1004 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1005 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1006 // widgets has both IM context and input focus, the event should be filtered
1007 // by gtk_im_context_filter_keypress().
1008 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1009 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1011 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1012 // docs, if IM filter returns true, no further processing should be done.
1013 // we should send the key_down event anyway.
1014 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1015 win
->m_imData
->lastKeyEvent
= NULL
;
1016 if (intercepted_by_IM
)
1018 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1023 if (return_after_IM
)
1029 wxWindowGTK
*ancestor
= win
;
1032 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1035 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1036 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1039 if (ancestor
->IsTopLevel())
1041 ancestor
= ancestor
->GetParent();
1044 #endif // wxUSE_ACCEL
1046 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1047 // will only be sent if it is not in an accelerator table.
1051 KeySym keysym
= gdk_event
->keyval
;
1052 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1053 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1056 if ( wxIsAsciiKeysym(keysym
) )
1059 key_code
= (unsigned char)keysym
;
1061 // gdk_event->string is actually deprecated
1062 else if ( gdk_event
->length
== 1 )
1064 key_code
= (unsigned char)gdk_event
->string
[0];
1070 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1072 event
.m_keyCode
= key_code
;
1074 // To conform to the docs we need to translate Ctrl-alpha
1075 // characters to values in the range 1-26.
1076 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1078 event
.m_keyCode
= key_code
- 'a' + 1;
1080 event
.m_uniChar
= event
.m_keyCode
;
1084 // Implement OnCharHook by checking ancestor top level windows
1085 wxWindow
*parent
= win
;
1086 while (parent
&& !parent
->IsTopLevel())
1087 parent
= parent
->GetParent();
1090 event
.SetEventType( wxEVT_CHAR_HOOK
);
1091 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1096 event
.SetEventType(wxEVT_CHAR
);
1097 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1106 // win is a control: tab can be propagated up
1108 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1109 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1110 // have this style, yet choose not to process this particular TAB in which
1111 // case TAB must still work as a navigational character
1112 // JS: enabling again to make consistent with other platforms
1113 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1114 // navigation behaviour)
1116 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1118 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1120 wxNavigationKeyEvent new_event
;
1121 new_event
.SetEventObject( win
->GetParent() );
1122 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1123 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1124 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1125 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1126 new_event
.SetCurrentFocus( win
);
1127 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1130 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1132 (gdk_event
->keyval
== GDK_Escape
) )
1134 // however only do it if we have a Cancel button in the dialog,
1135 // otherwise the user code may get confused by the events from a
1136 // non-existing button and, worse, a wxButton might get button event
1137 // from another button which is not really expected
1138 wxWindow
*winForCancel
= win
,
1140 while ( winForCancel
)
1142 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1145 // found a cancel button
1149 if ( winForCancel
->IsTopLevel() )
1151 // no need to look further
1155 // maybe our parent has a cancel button?
1156 winForCancel
= winForCancel
->GetParent();
1161 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1162 eventClick
.SetEventObject(btnCancel
);
1163 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1169 g_signal_stop_emission_by_name (widget
, "key_press_event");
1178 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1182 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1184 // take modifiers, cursor position, timestamp etc. from the last
1185 // key_press_event that was fed into Input Method:
1186 if (window
->m_imData
->lastKeyEvent
)
1188 wxFillOtherKeyEventFields(event
,
1189 window
, window
->m_imData
->lastKeyEvent
);
1193 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1195 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1196 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1197 #endif // wxUSE_UNICODE
1198 if( !(const wxChar
*)data
)
1203 // Implement OnCharHook by checking ancestor top level windows
1204 wxWindow
*parent
= window
;
1205 while (parent
&& !parent
->IsTopLevel())
1206 parent
= parent
->GetParent();
1208 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1211 event
.m_uniChar
= *pstr
;
1212 // Backward compatible for ISO-8859-1
1213 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1214 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1216 event
.m_keyCode
= *pstr
;
1217 #endif // wxUSE_UNICODE
1219 // To conform to the docs we need to translate Ctrl-alpha
1220 // characters to values in the range 1-26.
1221 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1223 event
.m_keyCode
= *pstr
- 'a' + 1;
1225 event
.m_uniChar
= event
.m_keyCode
;
1231 event
.SetEventType( wxEVT_CHAR_HOOK
);
1232 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1237 event
.SetEventType(wxEVT_CHAR
);
1238 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1245 //-----------------------------------------------------------------------------
1246 // "key_release_event" from any window
1247 //-----------------------------------------------------------------------------
1250 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1251 GdkEventKey
*gdk_event
,
1257 wxapp_install_idle_handler();
1262 if (g_blockEventsOnDrag
)
1265 wxKeyEvent
event( wxEVT_KEY_UP
);
1266 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1268 // unknown key pressed, ignore (the event would be useless anyhow)
1272 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1275 g_signal_stop_emission_by_name (widget
, "key_release_event");
1280 // ============================================================================
1282 // ============================================================================
1284 // ----------------------------------------------------------------------------
1285 // mouse event processing helpers
1286 // ----------------------------------------------------------------------------
1288 // init wxMouseEvent with the info from GdkEventXXX struct
1289 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1290 wxMouseEvent
& event
,
1293 event
.SetTimestamp( gdk_event
->time
);
1294 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1295 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1296 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1297 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1298 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1299 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1300 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1301 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1303 event
.m_linesPerAction
= 3;
1304 event
.m_wheelDelta
= 120;
1305 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1306 event
.m_wheelRotation
= 120;
1307 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1308 event
.m_wheelRotation
= -120;
1311 wxPoint pt
= win
->GetClientAreaOrigin();
1312 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1313 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1315 event
.SetEventObject( win
);
1316 event
.SetId( win
->GetId() );
1317 event
.SetTimestamp( gdk_event
->time
);
1320 static void AdjustEventButtonState(wxMouseEvent
& event
)
1322 // GDK reports the old state of the button for a button press event, but
1323 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1324 // for a LEFT_DOWN event, not FALSE, so we will invert
1325 // left/right/middleDown for the corresponding click events
1327 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1328 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1329 (event
.GetEventType() == wxEVT_LEFT_UP
))
1331 event
.m_leftDown
= !event
.m_leftDown
;
1335 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1336 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1337 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1339 event
.m_middleDown
= !event
.m_middleDown
;
1343 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1344 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1345 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1347 event
.m_rightDown
= !event
.m_rightDown
;
1352 // find the window to send the mouse event too
1354 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1359 if (win
->m_wxwindow
)
1361 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1362 xx
+= pizza
->xoffset
;
1363 yy
+= pizza
->yoffset
;
1366 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1369 wxWindowGTK
*child
= node
->GetData();
1371 node
= node
->GetNext();
1372 if (!child
->IsShown())
1375 if (child
->IsTransparentForMouse())
1377 // wxStaticBox is transparent in the box itself
1378 int xx1
= child
->m_x
;
1379 int yy1
= child
->m_y
;
1380 int xx2
= child
->m_x
+ child
->m_width
;
1381 int yy2
= child
->m_y
+ child
->m_height
;
1384 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1386 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1388 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1390 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1401 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1402 (child
->m_x
<= xx
) &&
1403 (child
->m_y
<= yy
) &&
1404 (child
->m_x
+child
->m_width
>= xx
) &&
1405 (child
->m_y
+child
->m_height
>= yy
))
1418 //-----------------------------------------------------------------------------
1419 // "button_press_event"
1420 //-----------------------------------------------------------------------------
1423 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1424 GdkEventButton
*gdk_event
,
1430 wxapp_install_idle_handler();
1433 wxPrintf( wxT("1) OnButtonPress from ") );
1434 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1435 wxPrintf( win->GetClassInfo()->GetClassName() );
1436 wxPrintf( wxT(".\n") );
1438 if (!win
->m_hasVMT
) return FALSE
;
1439 if (g_blockEventsOnDrag
) return TRUE
;
1440 if (g_blockEventsOnScroll
) return TRUE
;
1442 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1444 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1446 gtk_widget_grab_focus( win
->m_wxwindow
);
1448 wxPrintf( wxT("GrabFocus from ") );
1449 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1450 wxPrintf( win->GetClassInfo()->GetClassName() );
1451 wxPrintf( wxT(".\n") );
1455 // GDK sends surplus button down events
1456 // before a double click event. We
1457 // need to filter these out.
1458 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1460 GdkEvent
*peek_event
= gdk_event_peek();
1463 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1464 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1466 gdk_event_free( peek_event
);
1471 gdk_event_free( peek_event
);
1476 wxEventType event_type
= wxEVT_NULL
;
1478 // GdkDisplay is a GTK+ 2.2.0 thing
1479 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1480 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1481 !gtk_check_version(2,2,0) &&
1482 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1484 // Reset GDK internal timestamp variables in order to disable GDK
1485 // triple click events. GDK will then next time believe no button has
1486 // been clicked just before, and send a normal button click event.
1487 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1488 display
->button_click_time
[1] = 0;
1489 display
->button_click_time
[0] = 0;
1493 if (gdk_event
->button
== 1)
1495 // note that GDK generates triple click events which are not supported
1496 // by wxWidgets but still have to be passed to the app as otherwise
1497 // clicks would simply go missing
1498 switch (gdk_event
->type
)
1500 // we shouldn't get triple clicks at all for GTK2 because we
1501 // suppress them artificially using the code above but we still
1502 // should map them to something for GTK1 and not just ignore them
1503 // as this would lose clicks
1504 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1505 case GDK_BUTTON_PRESS
:
1506 event_type
= wxEVT_LEFT_DOWN
;
1509 case GDK_2BUTTON_PRESS
:
1510 event_type
= wxEVT_LEFT_DCLICK
;
1514 // just to silence gcc warnings
1518 else if (gdk_event
->button
== 2)
1520 switch (gdk_event
->type
)
1522 case GDK_3BUTTON_PRESS
:
1523 case GDK_BUTTON_PRESS
:
1524 event_type
= wxEVT_MIDDLE_DOWN
;
1527 case GDK_2BUTTON_PRESS
:
1528 event_type
= wxEVT_MIDDLE_DCLICK
;
1535 else if (gdk_event
->button
== 3)
1537 switch (gdk_event
->type
)
1539 case GDK_3BUTTON_PRESS
:
1540 case GDK_BUTTON_PRESS
:
1541 event_type
= wxEVT_RIGHT_DOWN
;
1544 case GDK_2BUTTON_PRESS
:
1545 event_type
= wxEVT_RIGHT_DCLICK
;
1552 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1554 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1556 event_type
= wxEVT_MOUSEWHEEL
;
1560 if ( event_type
== wxEVT_NULL
)
1562 // unknown mouse button or click type
1566 wxMouseEvent
event( event_type
);
1567 InitMouseEvent( win
, event
, gdk_event
);
1569 AdjustEventButtonState(event
);
1571 // wxListBox actually gets mouse events from the item, so we need to give it
1572 // a chance to correct this
1573 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1575 // find the correct window to send the event to: it may be a different one
1576 // from the one which got it at GTK+ level because some controls don't have
1577 // their own X window and thus cannot get any events.
1578 if ( !g_captureWindow
)
1579 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1581 if (win
->GetEventHandler()->ProcessEvent( event
))
1583 g_signal_stop_emission_by_name (widget
, "button_press_event");
1587 if (event_type
== wxEVT_RIGHT_DOWN
)
1589 // generate a "context menu" event: this is similar to right mouse
1590 // click under many GUIs except that it is generated differently
1591 // (right up under MSW, ctrl-click under Mac, right down here) and
1593 // (a) it's a command event and so is propagated to the parent
1594 // (b) under some ports it can be generated from kbd too
1595 // (c) it uses screen coords (because of (a))
1596 wxContextMenuEvent
evtCtx(
1599 win
->ClientToScreen(event
.GetPosition()));
1600 evtCtx
.SetEventObject(win
);
1601 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1608 //-----------------------------------------------------------------------------
1609 // "button_release_event"
1610 //-----------------------------------------------------------------------------
1613 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1614 GdkEventButton
*gdk_event
,
1620 wxapp_install_idle_handler();
1622 if (!win
->m_hasVMT
) return FALSE
;
1623 if (g_blockEventsOnDrag
) return FALSE
;
1624 if (g_blockEventsOnScroll
) return FALSE
;
1626 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1628 wxEventType event_type
= wxEVT_NULL
;
1630 switch (gdk_event
->button
)
1633 event_type
= wxEVT_LEFT_UP
;
1637 event_type
= wxEVT_MIDDLE_UP
;
1641 event_type
= wxEVT_RIGHT_UP
;
1645 // unknwon button, don't process
1649 wxMouseEvent
event( event_type
);
1650 InitMouseEvent( win
, event
, gdk_event
);
1652 AdjustEventButtonState(event
);
1654 // same wxListBox hack as above
1655 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1657 if ( !g_captureWindow
)
1658 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1660 if (win
->GetEventHandler()->ProcessEvent( event
))
1662 g_signal_stop_emission_by_name (widget
, "button_release_event");
1670 //-----------------------------------------------------------------------------
1671 // "motion_notify_event"
1672 //-----------------------------------------------------------------------------
1675 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1676 GdkEventMotion
*gdk_event
,
1682 wxapp_install_idle_handler();
1684 if (!win
->m_hasVMT
) return FALSE
;
1685 if (g_blockEventsOnDrag
) return FALSE
;
1686 if (g_blockEventsOnScroll
) return FALSE
;
1688 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1690 if (gdk_event
->is_hint
)
1694 GdkModifierType state
;
1695 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1701 printf( "OnMotion from " );
1702 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1703 printf( win->GetClassInfo()->GetClassName() );
1707 wxMouseEvent
event( wxEVT_MOTION
);
1708 InitMouseEvent(win
, event
, gdk_event
);
1710 if ( g_captureWindow
)
1712 // synthetize a mouse enter or leave event if needed
1713 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1714 // This seems to be necessary and actually been added to
1715 // GDK itself in version 2.0.X
1718 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1719 if ( hasMouse
!= g_captureWindowHasMouse
)
1721 // the mouse changed window
1722 g_captureWindowHasMouse
= hasMouse
;
1724 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1725 : wxEVT_LEAVE_WINDOW
);
1726 InitMouseEvent(win
, eventM
, gdk_event
);
1727 eventM
.SetEventObject(win
);
1728 win
->GetEventHandler()->ProcessEvent(eventM
);
1733 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1736 if (win
->GetEventHandler()->ProcessEvent( event
))
1738 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1746 //-----------------------------------------------------------------------------
1747 // "mouse_wheel_event"
1748 //-----------------------------------------------------------------------------
1751 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1752 GdkEventScroll
* gdk_event
,
1758 wxapp_install_idle_handler();
1760 wxEventType event_type
= wxEVT_NULL
;
1761 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1762 event_type
= wxEVT_MOUSEWHEEL
;
1763 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1764 event_type
= wxEVT_MOUSEWHEEL
;
1768 wxMouseEvent
event( event_type
);
1769 // Can't use InitMouse macro because scroll events don't have button
1770 event
.SetTimestamp( gdk_event
->time
);
1771 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1772 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1773 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1774 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1775 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1776 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1777 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1778 event
.m_linesPerAction
= 3;
1779 event
.m_wheelDelta
= 120;
1780 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1781 event
.m_wheelRotation
= 120;
1783 event
.m_wheelRotation
= -120;
1785 wxPoint pt
= win
->GetClientAreaOrigin();
1786 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1787 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1789 event
.SetEventObject( win
);
1790 event
.SetId( win
->GetId() );
1791 event
.SetTimestamp( gdk_event
->time
);
1793 if (win
->GetEventHandler()->ProcessEvent( event
))
1795 g_signal_stop_emission_by_name (widget
, "scroll_event");
1803 //-----------------------------------------------------------------------------
1805 //-----------------------------------------------------------------------------
1807 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1809 wxContextMenuEvent
event(
1813 event
.SetEventObject(win
);
1814 return win
->GetEventHandler()->ProcessEvent(event
);
1818 //-----------------------------------------------------------------------------
1820 //-----------------------------------------------------------------------------
1822 // send the wxChildFocusEvent and wxFocusEvent, common code of
1823 // gtk_window_focus_in_callback() and SetFocus()
1824 static bool DoSendFocusEvents(wxWindow
*win
)
1826 // Notify the parent keeping track of focus for the kbd navigation
1827 // purposes that we got it.
1828 wxChildFocusEvent
eventChildFocus(win
);
1829 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1831 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1832 eventFocus
.SetEventObject(win
);
1834 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1838 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1839 GdkEvent
*WXUNUSED(event
),
1845 wxapp_install_idle_handler();
1848 gtk_im_context_focus_in(win
->m_imData
->context
);
1851 g_focusWindow
= win
;
1853 wxLogTrace(TRACE_FOCUS
,
1854 _T("%s: focus in"), win
->GetName().c_str());
1858 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1862 // caret needs to be informed about focus change
1863 wxCaret
*caret
= win
->GetCaret();
1866 caret
->OnSetFocus();
1868 #endif // wxUSE_CARET
1872 // does the window itself think that it has the focus?
1873 if ( !win
->m_hasFocus
)
1875 // not yet, notify it
1876 win
->m_hasFocus
= true;
1878 (void)DoSendFocusEvents(win
);
1883 // Disable default focus handling for custom windows
1884 // since the default GTK+ handler issues a repaint
1885 if (win
->m_wxwindow
)
1886 g_signal_stop_emission_by_name (widget
, "focus_in_event");
1892 //-----------------------------------------------------------------------------
1893 // "focus_out_event"
1894 //-----------------------------------------------------------------------------
1897 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1902 wxapp_install_idle_handler();
1905 gtk_im_context_focus_out(win
->m_imData
->context
);
1907 wxLogTrace( TRACE_FOCUS
,
1908 _T("%s: focus out"), win
->GetName().c_str() );
1911 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1915 g_focusWindow
= (wxWindowGTK
*)NULL
;
1923 // caret needs to be informed about focus change
1924 wxCaret
*caret
= win
->GetCaret();
1927 caret
->OnKillFocus();
1929 #endif // wxUSE_CARET
1933 // don't send the window a kill focus event if it thinks that it doesn't
1934 // have focus already
1935 if ( win
->m_hasFocus
)
1937 win
->m_hasFocus
= false;
1939 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1940 event
.SetEventObject( win
);
1942 (void)win
->GetEventHandler()->ProcessEvent( event
);
1947 // Disable default focus handling for custom windows
1948 // since the default GTK+ handler issues a repaint
1949 if (win
->m_wxwindow
)
1950 g_signal_stop_emission_by_name (widget
, "focus_out_event");
1956 //-----------------------------------------------------------------------------
1957 // "enter_notify_event"
1958 //-----------------------------------------------------------------------------
1962 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1963 GdkEventCrossing
*gdk_event
,
1969 wxapp_install_idle_handler();
1971 if (!win
->m_hasVMT
) return FALSE
;
1972 if (g_blockEventsOnDrag
) return FALSE
;
1974 // Event was emitted after a grab
1975 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1977 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1981 GdkModifierType state
= (GdkModifierType
)0;
1983 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1985 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1986 InitMouseEvent(win
, event
, gdk_event
);
1987 wxPoint pt
= win
->GetClientAreaOrigin();
1988 event
.m_x
= x
+ pt
.x
;
1989 event
.m_y
= y
+ pt
.y
;
1991 if (win
->GetEventHandler()->ProcessEvent( event
))
1993 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2001 //-----------------------------------------------------------------------------
2002 // "leave_notify_event"
2003 //-----------------------------------------------------------------------------
2006 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2011 wxapp_install_idle_handler();
2013 if (!win
->m_hasVMT
) return FALSE
;
2014 if (g_blockEventsOnDrag
) return FALSE
;
2016 // Event was emitted after an ungrab
2017 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2019 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2021 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2022 event
.SetTimestamp( gdk_event
->time
);
2023 event
.SetEventObject( win
);
2027 GdkModifierType state
= (GdkModifierType
)0;
2029 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2031 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2032 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2033 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2034 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2035 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2036 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2037 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2039 wxPoint pt
= win
->GetClientAreaOrigin();
2040 event
.m_x
= x
+ pt
.x
;
2041 event
.m_y
= y
+ pt
.y
;
2043 if (win
->GetEventHandler()->ProcessEvent( event
))
2045 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2053 //-----------------------------------------------------------------------------
2054 // "value_changed" from m_vAdjust
2055 //-----------------------------------------------------------------------------
2058 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2064 wxapp_install_idle_handler();
2066 if (g_blockEventsOnDrag
) return;
2068 if (!win
->m_hasVMT
) return;
2070 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2071 if (fabs(diff
) < 0.2) return;
2073 win
->m_oldVerticalPos
= adjust
->value
;
2075 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2077 int value
= (int)(adjust
->value
+0.5);
2079 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2080 event
.SetEventObject( win
);
2081 win
->GetEventHandler()->ProcessEvent( event
);
2085 //-----------------------------------------------------------------------------
2086 // "value_changed" from m_hAdjust
2087 //-----------------------------------------------------------------------------
2090 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2096 wxapp_install_idle_handler();
2098 if (g_blockEventsOnDrag
) return;
2099 if (!win
->m_hasVMT
) return;
2101 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2102 if (fabs(diff
) < 0.2) return;
2104 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2106 win
->m_oldHorizontalPos
= adjust
->value
;
2108 int value
= (int)(adjust
->value
+0.5);
2110 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2111 event
.SetEventObject( win
);
2112 win
->GetEventHandler()->ProcessEvent( event
);
2116 //-----------------------------------------------------------------------------
2117 // "button_press_event" from scrollbar
2118 //-----------------------------------------------------------------------------
2121 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2122 GdkEventButton
*gdk_event
,
2128 wxapp_install_idle_handler();
2131 g_blockEventsOnScroll
= true;
2133 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2135 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2142 //-----------------------------------------------------------------------------
2143 // "button_release_event" from scrollbar
2144 //-----------------------------------------------------------------------------
2147 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2148 GdkEventButton
*WXUNUSED(gdk_event
),
2153 // don't test here as we can release the mouse while being over
2154 // a different window than the slider
2156 // if (gdk_event->window != widget->slider) return FALSE;
2158 g_blockEventsOnScroll
= false;
2160 if (win
->m_isScrolling
)
2162 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2166 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2167 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2169 value
= (int)(win
->m_hAdjust
->value
+0.5);
2172 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2174 value
= (int)(win
->m_vAdjust
->value
+0.5);
2178 wxScrollWinEvent
event( command
, value
, dir
);
2179 event
.SetEventObject( win
);
2180 win
->GetEventHandler()->ProcessEvent( event
);
2183 win
->m_isScrolling
= false;
2189 // ----------------------------------------------------------------------------
2190 // this wxWindowBase function is implemented here (in platform-specific file)
2191 // because it is static and so couldn't be made virtual
2192 // ----------------------------------------------------------------------------
2194 wxWindow
*wxWindowBase::DoFindFocus()
2196 // the cast is necessary when we compile in wxUniversal mode
2197 return (wxWindow
*)g_focusWindow
;
2200 //-----------------------------------------------------------------------------
2201 // "realize" from m_widget
2202 //-----------------------------------------------------------------------------
2204 /* We cannot set colours and fonts before the widget has
2205 been realized, so we do this directly after realization. */
2209 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2214 wxapp_install_idle_handler();
2218 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2219 gtk_im_context_set_client_window( win
->m_imData
->context
,
2220 pizza
->bin_window
);
2223 wxWindowCreateEvent
event( win
);
2224 event
.SetEventObject( win
);
2225 win
->GetEventHandler()->ProcessEvent( event
);
2231 //-----------------------------------------------------------------------------
2233 //-----------------------------------------------------------------------------
2237 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2238 GtkAllocation
*WXUNUSED(alloc
),
2242 wxapp_install_idle_handler();
2244 if (!win
->m_hasScrolling
) return;
2246 int client_width
= 0;
2247 int client_height
= 0;
2248 win
->GetClientSize( &client_width
, &client_height
);
2249 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2252 win
->m_oldClientWidth
= client_width
;
2253 win
->m_oldClientHeight
= client_height
;
2255 if (!win
->m_nativeSizeEvent
)
2257 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2258 event
.SetEventObject( win
);
2259 win
->GetEventHandler()->ProcessEvent( event
);
2266 #define WXUNUSED_UNLESS_XIM(param) param
2268 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2271 /* Resize XIM window */
2275 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2276 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2277 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2280 wxapp_install_idle_handler();
2286 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2290 gdk_window_get_size (widget
->window
, &width
, &height
);
2291 win
->m_icattr
->preedit_area
.width
= width
;
2292 win
->m_icattr
->preedit_area
.height
= height
;
2293 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2299 //-----------------------------------------------------------------------------
2300 // "realize" from m_wxwindow
2301 //-----------------------------------------------------------------------------
2303 /* Initialize XIM support */
2307 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2308 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2311 wxapp_install_idle_handler();
2314 if (win
->m_ic
) return FALSE
;
2315 if (!widget
) return FALSE
;
2316 if (!gdk_im_ready()) return FALSE
;
2318 win
->m_icattr
= gdk_ic_attr_new();
2319 if (!win
->m_icattr
) return FALSE
;
2323 GdkColormap
*colormap
;
2324 GdkICAttr
*attr
= win
->m_icattr
;
2325 unsigned attrmask
= GDK_IC_ALL_REQ
;
2327 GdkIMStyle supported_style
= (GdkIMStyle
)
2328 (GDK_IM_PREEDIT_NONE
|
2329 GDK_IM_PREEDIT_NOTHING
|
2330 GDK_IM_PREEDIT_POSITION
|
2331 GDK_IM_STATUS_NONE
|
2332 GDK_IM_STATUS_NOTHING
);
2334 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2335 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2337 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2338 attr
->client_window
= widget
->window
;
2340 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2341 gtk_widget_get_default_colormap ())
2343 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2344 attr
->preedit_colormap
= colormap
;
2347 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2348 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2349 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2350 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2352 switch (style
& GDK_IM_PREEDIT_MASK
)
2354 case GDK_IM_PREEDIT_POSITION
:
2355 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2357 g_warning ("over-the-spot style requires fontset");
2361 gdk_window_get_size (widget
->window
, &width
, &height
);
2363 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2364 attr
->spot_location
.x
= 0;
2365 attr
->spot_location
.y
= height
;
2366 attr
->preedit_area
.x
= 0;
2367 attr
->preedit_area
.y
= 0;
2368 attr
->preedit_area
.width
= width
;
2369 attr
->preedit_area
.height
= height
;
2370 attr
->preedit_fontset
= widget
->style
->font
;
2375 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2377 if (win
->m_ic
== NULL
)
2378 g_warning ("Can't create input context.");
2381 mask
= gdk_window_get_events (widget
->window
);
2382 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2383 gdk_window_set_events (widget
->window
, mask
);
2385 if (GTK_WIDGET_HAS_FOCUS(widget
))
2386 gdk_im_begin (win
->m_ic
, widget
->window
);
2394 //-----------------------------------------------------------------------------
2395 // InsertChild for wxWindowGTK.
2396 //-----------------------------------------------------------------------------
2398 /* Callback for wxWindowGTK. This very strange beast has to be used because
2399 * C++ has no virtual methods in a constructor. We have to emulate a
2400 * virtual function here as wxNotebook requires a different way to insert
2401 * a child in it. I had opted for creating a wxNotebookPage window class
2402 * which would have made this superfluous (such in the MDI window system),
2403 * but no-one was listening to me... */
2405 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2407 /* the window might have been scrolled already, do we
2408 have to adapt the position */
2409 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2410 child
->m_x
+= pizza
->xoffset
;
2411 child
->m_y
+= pizza
->yoffset
;
2413 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2414 GTK_WIDGET(child
->m_widget
),
2421 //-----------------------------------------------------------------------------
2423 //-----------------------------------------------------------------------------
2425 wxWindow
*wxGetActiveWindow()
2427 return wxWindow::FindFocus();
2431 wxMouseState
wxGetMouseState()
2437 GdkModifierType mask
;
2439 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2443 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2444 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2445 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2447 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2448 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2449 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2450 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2455 //-----------------------------------------------------------------------------
2457 //-----------------------------------------------------------------------------
2459 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2461 #ifdef __WXUNIVERSAL__
2462 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2464 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2465 #endif // __WXUNIVERSAL__/__WXGTK__
2467 void wxWindowGTK::Init()
2470 m_widget
= (GtkWidget
*) NULL
;
2471 m_wxwindow
= (GtkWidget
*) NULL
;
2472 m_focusWidget
= (GtkWidget
*) NULL
;
2482 m_needParent
= true;
2483 m_isBeingDeleted
= false;
2486 m_nativeSizeEvent
= false;
2488 m_hasScrolling
= false;
2489 m_isScrolling
= false;
2491 m_hAdjust
= (GtkAdjustment
*) NULL
;
2492 m_vAdjust
= (GtkAdjustment
*) NULL
;
2493 m_oldHorizontalPos
=
2494 m_oldVerticalPos
= 0.0;
2496 m_oldClientHeight
= 0;
2500 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2502 m_acceptsFocus
= false;
2505 m_clipPaintRegion
= false;
2507 m_needsStyleChange
= false;
2509 m_cursor
= *wxSTANDARD_CURSOR
;
2512 m_dirtyTabOrder
= false;
2515 wxWindowGTK::wxWindowGTK()
2520 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2525 const wxString
&name
)
2529 Create( parent
, id
, pos
, size
, style
, name
);
2532 bool wxWindowGTK::Create( wxWindow
*parent
,
2537 const wxString
&name
)
2539 if (!PreCreation( parent
, pos
, size
) ||
2540 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2542 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2546 m_insertCallback
= wxInsertChildInWindow
;
2548 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2549 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2551 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2553 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2554 scroll_class
->scrollbar_spacing
= 0;
2556 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2558 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2559 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2561 m_wxwindow
= gtk_pizza_new();
2563 #ifndef __WXUNIVERSAL__
2564 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2566 if (HasFlag(wxRAISED_BORDER
))
2568 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2570 else if (HasFlag(wxSUNKEN_BORDER
))
2572 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2574 else if (HasFlag(wxSIMPLE_BORDER
))
2576 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2580 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2582 #endif // __WXUNIVERSAL__
2584 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2586 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2587 m_acceptsFocus
= true;
2589 // I _really_ don't want scrollbars in the beginning
2590 m_vAdjust
->lower
= 0.0;
2591 m_vAdjust
->upper
= 1.0;
2592 m_vAdjust
->value
= 0.0;
2593 m_vAdjust
->step_increment
= 1.0;
2594 m_vAdjust
->page_increment
= 1.0;
2595 m_vAdjust
->page_size
= 5.0;
2596 g_signal_emit_by_name (m_vAdjust
, "changed");
2597 m_hAdjust
->lower
= 0.0;
2598 m_hAdjust
->upper
= 1.0;
2599 m_hAdjust
->value
= 0.0;
2600 m_hAdjust
->step_increment
= 1.0;
2601 m_hAdjust
->page_increment
= 1.0;
2602 m_hAdjust
->page_size
= 5.0;
2603 g_signal_emit_by_name (m_hAdjust
, "changed");
2605 // these handlers block mouse events to any window during scrolling such as
2606 // motion events and prevent GTK and wxWidgets from fighting over where the
2608 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2609 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2610 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2611 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2612 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2613 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2614 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2615 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2617 // these handlers get notified when screen updates are required either when
2618 // scrolling or when the window size (and therefore scrollbar configuration)
2621 g_signal_connect (m_hAdjust
, "value_changed",
2622 G_CALLBACK (gtk_window_hscroll_callback
), this);
2623 g_signal_connect (m_vAdjust
, "value_changed",
2624 G_CALLBACK (gtk_window_vscroll_callback
), this);
2626 gtk_widget_show( m_wxwindow
);
2629 m_parent
->DoAddChild( this );
2631 m_focusWidget
= m_wxwindow
;
2638 wxWindowGTK::~wxWindowGTK()
2642 if (g_focusWindow
== this)
2643 g_focusWindow
= NULL
;
2645 if ( g_delayedFocus
== this )
2646 g_delayedFocus
= NULL
;
2648 m_isBeingDeleted
= true;
2651 // destroy children before destroying this window itself
2654 // unhook focus handlers to prevent stray events being
2655 // propagated to this (soon to be) dead object
2656 if (m_focusWidget
!= NULL
)
2658 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2659 (gpointer
) gtk_window_focus_in_callback
,
2661 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2662 (gpointer
) gtk_window_focus_out_callback
,
2671 gdk_ic_destroy (m_ic
);
2673 gdk_ic_attr_destroy (m_icattr
);
2676 // delete before the widgets to avoid a crash on solaris
2681 gtk_widget_destroy( m_wxwindow
);
2682 m_wxwindow
= (GtkWidget
*) NULL
;
2687 gtk_widget_destroy( m_widget
);
2688 m_widget
= (GtkWidget
*) NULL
;
2692 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2694 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2696 // Use either the given size, or the default if -1 is given.
2697 // See wxWindowBase for these functions.
2698 m_width
= WidthDefault(size
.x
) ;
2699 m_height
= HeightDefault(size
.y
);
2707 void wxWindowGTK::PostCreation()
2709 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2715 // these get reported to wxWidgets -> wxPaintEvent
2717 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2719 g_signal_connect (m_wxwindow
, "expose_event",
2720 G_CALLBACK (gtk_window_expose_callback
), this);
2722 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2725 // Create input method handler
2726 m_imData
= new wxGtkIMData
;
2728 // Cannot handle drawing preedited text yet
2729 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2731 g_signal_connect (m_imData
->context
, "commit",
2732 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2734 // these are called when the "sunken" or "raised" borders are drawn
2735 g_signal_connect (m_widget
, "expose_event",
2736 G_CALLBACK (gtk_window_own_expose_callback
), this);
2741 if (!GTK_IS_WINDOW(m_widget
))
2743 if (m_focusWidget
== NULL
)
2744 m_focusWidget
= m_widget
;
2746 g_signal_connect (m_focusWidget
, "focus_in_event",
2747 G_CALLBACK (gtk_window_focus_in_callback
), this);
2748 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2749 G_CALLBACK (gtk_window_focus_out_callback
), this);
2752 // connect to the various key and mouse handlers
2754 GtkWidget
*connect_widget
= GetConnectWidget();
2756 ConnectWidget( connect_widget
);
2758 /* We cannot set colours, fonts and cursors before the widget has
2759 been realized, so we do this directly after realization */
2760 g_signal_connect (connect_widget
, "realize",
2761 G_CALLBACK (gtk_window_realized_callback
), this);
2765 // Catch native resize events
2766 g_signal_connect (m_wxwindow
, "size_allocate",
2767 G_CALLBACK (gtk_window_size_callback
), this);
2769 // Initialize XIM support
2770 g_signal_connect (m_wxwindow
, "realize",
2771 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2773 // And resize XIM window
2774 g_signal_connect (m_wxwindow
, "size_allocate",
2775 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2778 if (GTK_IS_COMBO(m_widget
))
2780 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2782 g_signal_connect (gcombo
->entry
, "size_request",
2783 G_CALLBACK (wxgtk_combo_size_request_callback
),
2788 // This is needed if we want to add our windows into native
2789 // GTK controls, such as the toolbar. With this callback, the
2790 // toolbar gets to know the correct size (the one set by the
2791 // programmer). Sadly, it misbehaves for wxComboBox.
2792 g_signal_connect (m_widget
, "size_request",
2793 G_CALLBACK (wxgtk_window_size_request_callback
),
2797 InheritAttributes();
2801 // unless the window was created initially hidden (i.e. Hide() had been
2802 // called before Create()), we should show it at GTK+ level as well
2804 gtk_widget_show( m_widget
);
2807 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2809 g_signal_connect (widget
, "key_press_event",
2810 G_CALLBACK (gtk_window_key_press_callback
), this);
2811 g_signal_connect (widget
, "key_release_event",
2812 G_CALLBACK (gtk_window_key_release_callback
), this);
2813 g_signal_connect (widget
, "button_press_event",
2814 G_CALLBACK (gtk_window_button_press_callback
), this);
2815 g_signal_connect (widget
, "button_release_event",
2816 G_CALLBACK (gtk_window_button_release_callback
), this);
2817 g_signal_connect (widget
, "motion_notify_event",
2818 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2819 g_signal_connect (widget
, "scroll_event",
2820 G_CALLBACK (gtk_window_wheel_callback
), this);
2821 g_signal_connect (widget
, "popup_menu",
2822 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2823 g_signal_connect (widget
, "enter_notify_event",
2824 G_CALLBACK (gtk_window_enter_callback
), this);
2825 g_signal_connect (widget
, "leave_notify_event",
2826 G_CALLBACK (gtk_window_leave_callback
), this);
2829 bool wxWindowGTK::Destroy()
2831 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2835 return wxWindowBase::Destroy();
2838 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2840 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2843 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2845 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2846 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2849 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2852 if (m_resizing
) return; /* I don't like recursions */
2855 int currentX
, currentY
;
2856 GetPosition(¤tX
, ¤tY
);
2857 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2859 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2861 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2863 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2865 /* don't set the size for children of wxNotebook, just take the values. */
2873 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2874 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2876 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2877 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2881 m_x
= x
+ pizza
->xoffset
;
2882 m_y
= y
+ pizza
->yoffset
;
2885 // calculate the best size if we should auto size the window
2886 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2887 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2889 const wxSize sizeBest
= GetBestSize();
2890 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2892 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2893 height
= sizeBest
.y
;
2901 int minWidth
= GetMinWidth(),
2902 minHeight
= GetMinHeight(),
2903 maxWidth
= GetMaxWidth(),
2904 maxHeight
= GetMaxHeight();
2906 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2907 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2908 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2909 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2911 int left_border
= 0;
2912 int right_border
= 0;
2914 int bottom_border
= 0;
2916 /* the default button has a border around it */
2917 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2919 GtkBorder
*default_border
= NULL
;
2920 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2923 left_border
+= default_border
->left
;
2924 right_border
+= default_border
->right
;
2925 top_border
+= default_border
->top
;
2926 bottom_border
+= default_border
->bottom
;
2927 g_free( default_border
);
2931 DoMoveWindow( m_x
-top_border
,
2933 m_width
+left_border
+right_border
,
2934 m_height
+top_border
+bottom_border
);
2939 /* Sometimes the client area changes size without the
2940 whole windows's size changing, but if the whole
2941 windows's size doesn't change, no wxSizeEvent will
2942 normally be sent. Here we add an extra test if
2943 the client test has been changed and this will
2945 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2949 wxPrintf( "OnSize sent from " );
2950 if (GetClassInfo() && GetClassInfo()->GetClassName())
2951 wxPrintf( GetClassInfo()->GetClassName() );
2952 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2955 if (!m_nativeSizeEvent
)
2957 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2958 event
.SetEventObject( this );
2959 GetEventHandler()->ProcessEvent( event
);
2965 void wxWindowGTK::OnInternalIdle()
2967 if ( m_dirtyTabOrder
)
2969 m_dirtyTabOrder
= false;
2973 // Update style if the window was not yet realized
2974 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2975 if (m_needsStyleChange
)
2977 SetBackgroundStyle(GetBackgroundStyle());
2978 m_needsStyleChange
= false;
2981 // Update invalidated regions.
2984 wxCursor cursor
= m_cursor
;
2985 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2989 /* I now set the cursor anew in every OnInternalIdle call
2990 as setting the cursor in a parent window also effects the
2991 windows above so that checking for the current cursor is
2996 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2998 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3000 if (!g_globalCursor
.Ok())
3001 cursor
= *wxSTANDARD_CURSOR
;
3003 window
= m_widget
->window
;
3004 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3005 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3011 GdkWindow
*window
= m_widget
->window
;
3012 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3013 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3018 if (wxUpdateUIEvent::CanUpdate(this))
3019 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3022 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3024 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3026 if (width
) (*width
) = m_width
;
3027 if (height
) (*height
) = m_height
;
3030 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3032 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3036 SetSize( width
, height
);
3043 #ifndef __WXUNIVERSAL__
3044 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3046 /* when using GTK 1.2 we set the shadow border size to 2 */
3050 if (HasFlag(wxSIMPLE_BORDER
))
3052 /* when using GTK 1.2 we set the simple border size to 1 */
3056 #endif // __WXUNIVERSAL__
3060 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3062 GtkRequisition vscroll_req
;
3063 vscroll_req
.width
= 2;
3064 vscroll_req
.height
= 2;
3065 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3066 (scroll_window
->vscrollbar
, &vscroll_req
);
3068 GtkRequisition hscroll_req
;
3069 hscroll_req
.width
= 2;
3070 hscroll_req
.height
= 2;
3071 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3072 (scroll_window
->hscrollbar
, &hscroll_req
);
3074 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3076 if (scroll_window
->vscrollbar_visible
)
3078 dw
+= vscroll_req
.width
;
3079 dw
+= scroll_class
->scrollbar_spacing
;
3082 if (scroll_window
->hscrollbar_visible
)
3084 dh
+= hscroll_req
.height
;
3085 dh
+= scroll_class
->scrollbar_spacing
;
3089 SetSize( width
+dw
, height
+dh
);
3093 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3095 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3099 if (width
) (*width
) = m_width
;
3100 if (height
) (*height
) = m_height
;
3107 #ifndef __WXUNIVERSAL__
3108 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3110 /* when using GTK 1.2 we set the shadow border size to 2 */
3114 if (HasFlag(wxSIMPLE_BORDER
))
3116 /* when using GTK 1.2 we set the simple border size to 1 */
3120 #endif // __WXUNIVERSAL__
3124 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3126 GtkRequisition vscroll_req
;
3127 vscroll_req
.width
= 2;
3128 vscroll_req
.height
= 2;
3129 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3130 (scroll_window
->vscrollbar
, &vscroll_req
);
3132 GtkRequisition hscroll_req
;
3133 hscroll_req
.width
= 2;
3134 hscroll_req
.height
= 2;
3135 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3136 (scroll_window
->hscrollbar
, &hscroll_req
);
3138 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3140 if (scroll_window
->vscrollbar_visible
)
3142 dw
+= vscroll_req
.width
;
3143 dw
+= scroll_class
->scrollbar_spacing
;
3146 if (scroll_window
->hscrollbar_visible
)
3148 dh
+= hscroll_req
.height
;
3149 dh
+= scroll_class
->scrollbar_spacing
;
3153 if (width
) (*width
) = m_width
- dw
;
3154 if (height
) (*height
) = m_height
- dh
;
3158 printf( "GetClientSize, name %s ", GetName().c_str() );
3159 if (width) printf( " width = %d", (*width) );
3160 if (height) printf( " height = %d", (*height) );
3165 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3167 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3171 if (m_parent
&& m_parent
->m_wxwindow
)
3173 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3174 dx
= pizza
->xoffset
;
3175 dy
= pizza
->yoffset
;
3178 if (x
) (*x
) = m_x
- dx
;
3179 if (y
) (*y
) = m_y
- dy
;
3182 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3184 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3186 if (!m_widget
->window
) return;
3188 GdkWindow
*source
= (GdkWindow
*) NULL
;
3190 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3192 source
= m_widget
->window
;
3196 gdk_window_get_origin( source
, &org_x
, &org_y
);
3200 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3202 org_x
+= m_widget
->allocation
.x
;
3203 org_y
+= m_widget
->allocation
.y
;
3211 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3213 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3215 if (!m_widget
->window
) return;
3217 GdkWindow
*source
= (GdkWindow
*) NULL
;
3219 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3221 source
= m_widget
->window
;
3225 gdk_window_get_origin( source
, &org_x
, &org_y
);
3229 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3231 org_x
+= m_widget
->allocation
.x
;
3232 org_y
+= m_widget
->allocation
.y
;
3240 bool wxWindowGTK::Show( bool show
)
3242 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3244 if (!wxWindowBase::Show(show
))
3251 gtk_widget_show( m_widget
);
3253 gtk_widget_hide( m_widget
);
3255 wxShowEvent
eventShow(GetId(), show
);
3256 eventShow
.SetEventObject(this);
3258 GetEventHandler()->ProcessEvent(eventShow
);
3263 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3265 win
->OnParentEnable(enable
);
3267 // Recurse, so that children have the opportunity to Do The Right Thing
3268 // and reset colours that have been messed up by a parent's (really ancestor's)
3270 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3272 node
= node
->GetNext() )
3274 wxWindow
*child
= node
->GetData();
3275 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3276 wxWindowNotifyEnable(child
, enable
);
3280 bool wxWindowGTK::Enable( bool enable
)
3282 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3284 if (!wxWindowBase::Enable(enable
))
3290 gtk_widget_set_sensitive( m_widget
, enable
);
3292 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3294 wxWindowNotifyEnable(this, enable
);
3299 int wxWindowGTK::GetCharHeight() const
3301 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3303 wxFont font
= GetFont();
3304 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3306 PangoContext
*context
= NULL
;
3308 context
= gtk_widget_get_pango_context( m_widget
);
3313 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3314 PangoLayout
*layout
= pango_layout_new(context
);
3315 pango_layout_set_font_description(layout
, desc
);
3316 pango_layout_set_text(layout
, "H", 1);
3317 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3319 PangoRectangle rect
;
3320 pango_layout_line_get_extents(line
, NULL
, &rect
);
3322 g_object_unref( G_OBJECT( layout
) );
3324 return (int) PANGO_PIXELS(rect
.height
);
3327 int wxWindowGTK::GetCharWidth() const
3329 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3331 wxFont font
= GetFont();
3332 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3334 PangoContext
*context
= NULL
;
3336 context
= gtk_widget_get_pango_context( m_widget
);
3341 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3342 PangoLayout
*layout
= pango_layout_new(context
);
3343 pango_layout_set_font_description(layout
, desc
);
3344 pango_layout_set_text(layout
, "g", 1);
3345 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3347 PangoRectangle rect
;
3348 pango_layout_line_get_extents(line
, NULL
, &rect
);
3350 g_object_unref( G_OBJECT( layout
) );
3352 return (int) PANGO_PIXELS(rect
.width
);
3355 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3359 int *externalLeading
,
3360 const wxFont
*theFont
) const
3362 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3364 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3373 PangoContext
*context
= NULL
;
3375 context
= gtk_widget_get_pango_context( m_widget
);
3384 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3385 PangoLayout
*layout
= pango_layout_new(context
);
3386 pango_layout_set_font_description(layout
, desc
);
3389 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3390 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3392 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3393 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3394 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3398 PangoRectangle rect
;
3399 pango_layout_get_extents(layout
, NULL
, &rect
);
3401 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3402 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3405 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3406 int baseline
= pango_layout_iter_get_baseline(iter
);
3407 pango_layout_iter_free(iter
);
3408 *descent
= *y
- PANGO_PIXELS(baseline
);
3410 if (externalLeading
) (*externalLeading
) = 0; // ??
3412 g_object_unref( G_OBJECT( layout
) );
3415 void wxWindowGTK::SetFocus()
3417 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3420 // don't do anything if we already have focus
3426 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3428 gtk_widget_grab_focus (m_wxwindow
);
3433 if (GTK_IS_CONTAINER(m_widget
))
3435 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3438 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3441 if (!GTK_WIDGET_REALIZED(m_widget
))
3443 // we can't set the focus to the widget now so we remember that
3444 // it should be focused and will do it later, during the idle
3445 // time, as soon as we can
3446 wxLogTrace(TRACE_FOCUS
,
3447 _T("Delaying setting focus to %s(%s)"),
3448 GetClassInfo()->GetClassName(), GetLabel().c_str());
3450 g_delayedFocus
= this;
3454 wxLogTrace(TRACE_FOCUS
,
3455 _T("Setting focus to %s(%s)"),
3456 GetClassInfo()->GetClassName(), GetLabel().c_str());
3458 gtk_widget_grab_focus (m_widget
);
3463 wxLogTrace(TRACE_FOCUS
,
3464 _T("Can't set focus to %s(%s)"),
3465 GetClassInfo()->GetClassName(), GetLabel().c_str());
3470 bool wxWindowGTK::AcceptsFocus() const
3472 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3475 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3477 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3479 wxWindowGTK
*oldParent
= m_parent
,
3480 *newParent
= (wxWindowGTK
*)newParentBase
;
3482 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3484 if ( !wxWindowBase::Reparent(newParent
) )
3487 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3489 /* prevent GTK from deleting the widget arbitrarily */
3490 gtk_widget_ref( m_widget
);
3494 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3497 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3501 /* insert GTK representation */
3502 (*(newParent
->m_insertCallback
))(newParent
, this);
3505 /* reverse: prevent GTK from deleting the widget arbitrarily */
3506 gtk_widget_unref( m_widget
);
3511 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3513 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3515 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3517 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3522 /* insert GTK representation */
3523 (*m_insertCallback
)(this, child
);
3526 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3528 wxWindowBase::AddChild(child
);
3529 m_dirtyTabOrder
= true;
3531 wxapp_install_idle_handler();
3534 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3536 wxWindowBase::RemoveChild(child
);
3537 m_dirtyTabOrder
= true;
3539 wxapp_install_idle_handler();
3542 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3544 wxWindowBase::DoMoveInTabOrder(win
, move
);
3545 m_dirtyTabOrder
= true;
3547 wxapp_install_idle_handler();
3550 void wxWindowGTK::RealizeTabOrder()
3554 if ( !m_children
.empty() )
3557 // we don't only construct the correct focus chain but also use
3558 // this opportunity to update the mnemonic widgets for all labels
3560 // it would be nice to extract this code from here and put it in
3561 // stattext.cpp to reduce dependencies but there is no really easy
3562 // way to do it unfortunately
3563 wxStaticText
*lastLabel
= NULL
;
3564 #endif // wxUSE_STATTEXT
3566 GList
*chain
= NULL
;
3568 for ( wxWindowList::const_iterator i
= m_children
.begin();
3569 i
!= m_children
.end();
3572 wxWindowGTK
*win
= *i
;
3576 if ( win
->AcceptsFocusFromKeyboard() )
3578 GtkLabel
*l
= GTK_LABEL(lastLabel
->m_widget
);
3579 gtk_label_set_mnemonic_widget(l
, win
->m_widget
);
3583 else // check if this one is a label
3585 lastLabel
= wxDynamicCast(win
, wxStaticText
);
3587 #endif // wxUSE_STATTEXT
3589 chain
= g_list_prepend(chain
, win
->m_widget
);
3592 chain
= g_list_reverse(chain
);
3594 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3599 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3604 void wxWindowGTK::Raise()
3606 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3608 if (m_wxwindow
&& m_wxwindow
->window
)
3610 gdk_window_raise( m_wxwindow
->window
);
3612 else if (m_widget
->window
)
3614 gdk_window_raise( m_widget
->window
);
3618 void wxWindowGTK::Lower()
3620 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3622 if (m_wxwindow
&& m_wxwindow
->window
)
3624 gdk_window_lower( m_wxwindow
->window
);
3626 else if (m_widget
->window
)
3628 gdk_window_lower( m_widget
->window
);
3632 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3634 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3636 if (cursor
== m_cursor
)
3640 wxapp_install_idle_handler();
3642 if (cursor
== wxNullCursor
)
3643 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3645 return wxWindowBase::SetCursor( cursor
);
3648 void wxWindowGTK::WarpPointer( int x
, int y
)
3650 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3652 // We provide this function ourselves as it is
3653 // missing in GDK (top of this file).
3655 GdkWindow
*window
= (GdkWindow
*) NULL
;
3657 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3659 window
= GetConnectWidget()->window
;
3662 gdk_window_warp_pointer( window
, x
, y
);
3665 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3667 double value_start
= adj
->value
;
3668 double value
= value_start
+ change
;
3669 double upper
= adj
->upper
- adj
->page_size
;
3674 // Lower bound will be checked by gtk_adjustment_set_value
3675 gtk_adjustment_set_value(adj
, value
);
3676 return adj
->value
!= value_start
;
3679 bool wxWindowGTK::ScrollLines(int lines
)
3682 m_vAdjust
!= NULL
&&
3683 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3686 bool wxWindowGTK::ScrollPages(int pages
)
3689 m_vAdjust
!= NULL
&&
3690 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3693 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3695 wxASSERT(m_vAdjust
== NULL
);
3699 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3703 if (!m_widget
->window
)
3708 GdkRectangle gdk_rect
,
3712 gdk_rect
.x
= rect
->x
;
3713 gdk_rect
.y
= rect
->y
;
3714 gdk_rect
.width
= rect
->width
;
3715 gdk_rect
.height
= rect
->height
;
3718 else // invalidate everything
3723 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3727 void wxWindowGTK::Update()
3731 // when we call Update() we really want to update the window immediately on
3732 // screen, even if it means flushing the entire queue and hence slowing down
3733 // everything -- but it should still be done, it's just that Update() should
3734 // be called very rarely
3738 void wxWindowGTK::GtkUpdate()
3740 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3741 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3743 // for consistency with other platforms (and also because it's convenient
3744 // to be able to update an entire TLW by calling Update() only once), we
3745 // should also update all our children here
3746 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3748 node
= node
->GetNext() )
3750 node
->GetData()->GtkUpdate();
3754 void wxWindowGTK::GtkSendPaintEvents()
3758 m_updateRegion
.Clear();
3762 // Clip to paint region in wxClientDC
3763 m_clipPaintRegion
= true;
3765 // widget to draw on
3766 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3768 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3770 // find ancestor from which to steal background
3771 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3773 parent
= (wxWindow
*)this;
3775 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3777 wxRegionIterator
upd( m_updateRegion
);
3781 rect
.x
= upd
.GetX();
3782 rect
.y
= upd
.GetY();
3783 rect
.width
= upd
.GetWidth();
3784 rect
.height
= upd
.GetHeight();
3786 gtk_paint_flat_box( parent
->m_widget
->style
,
3788 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3802 wxWindowDC
dc( (wxWindow
*)this );
3803 dc
.SetClippingRegion( m_updateRegion
);
3805 wxEraseEvent
erase_event( GetId(), &dc
);
3806 erase_event
.SetEventObject( this );
3808 GetEventHandler()->ProcessEvent(erase_event
);
3811 wxNcPaintEvent
nc_paint_event( GetId() );
3812 nc_paint_event
.SetEventObject( this );
3813 GetEventHandler()->ProcessEvent( nc_paint_event
);
3815 wxPaintEvent
paint_event( GetId() );
3816 paint_event
.SetEventObject( this );
3817 GetEventHandler()->ProcessEvent( paint_event
);
3819 m_clipPaintRegion
= false;
3821 m_updateRegion
.Clear();
3824 void wxWindowGTK::ClearBackground()
3826 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3830 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3832 wxWindowBase::DoSetToolTip(tip
);
3835 m_tooltip
->Apply( (wxWindow
*)this );
3838 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3840 wxString
tmp( tip
);
3841 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3843 #endif // wxUSE_TOOLTIPS
3845 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3847 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3849 if (!wxWindowBase::SetBackgroundColour(colour
))
3854 // We need the pixel value e.g. for background clearing.
3855 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3858 // apply style change (forceStyle=true so that new style is applied
3859 // even if the bg colour changed from valid to wxNullColour)
3860 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3861 ApplyWidgetStyle(true);
3866 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3868 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3870 if (!wxWindowBase::SetForegroundColour(colour
))
3877 // We need the pixel value e.g. for background clearing.
3878 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3881 // apply style change (forceStyle=true so that new style is applied
3882 // even if the bg colour changed from valid to wxNullColour):
3883 ApplyWidgetStyle(true);
3888 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3890 return gtk_widget_get_pango_context( m_widget
);
3893 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3895 // do we need to apply any changes at all?
3898 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3903 GtkRcStyle
*style
= gtk_rc_style_new();
3908 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3911 if ( m_foregroundColour
.Ok() )
3913 GdkColor
*fg
= m_foregroundColour
.GetColor();
3915 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3916 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3918 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3919 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3921 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3922 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3925 if ( m_backgroundColour
.Ok() )
3927 GdkColor
*bg
= m_backgroundColour
.GetColor();
3929 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3930 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3931 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3932 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3934 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3935 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3936 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3937 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3939 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3940 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3941 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3942 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3944 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3945 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3946 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3947 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3953 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3955 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3958 DoApplyWidgetStyle(style
);
3959 gtk_rc_style_unref(style
);
3962 // Style change may affect GTK+'s size calculation:
3963 InvalidateBestSize();
3966 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3969 gtk_widget_modify_style(m_wxwindow
, style
);
3971 gtk_widget_modify_style(m_widget
, style
);
3974 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3976 wxWindowBase::SetBackgroundStyle(style
);
3978 if (style
== wxBG_STYLE_CUSTOM
)
3980 GdkWindow
*window
= (GdkWindow
*) NULL
;
3982 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3984 window
= GetConnectWidget()->window
;
3988 // Make sure GDK/X11 doesn't refresh the window
3990 gdk_window_set_back_pixmap( window
, None
, False
);
3992 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3995 m_needsStyleChange
= false;
3998 // Do in OnIdle, because the window is not yet available
3999 m_needsStyleChange
= true;
4001 // Don't apply widget style, or we get a grey background
4005 // apply style change (forceStyle=true so that new style is applied
4006 // even if the bg colour changed from valid to wxNullColour):
4007 ApplyWidgetStyle(true);
4012 #if wxUSE_DRAG_AND_DROP
4014 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4016 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4018 GtkWidget
*dnd_widget
= GetConnectWidget();
4020 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4022 if (m_dropTarget
) delete m_dropTarget
;
4023 m_dropTarget
= dropTarget
;
4025 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4028 #endif // wxUSE_DRAG_AND_DROP
4030 GtkWidget
* wxWindowGTK::GetConnectWidget()
4032 GtkWidget
*connect_widget
= m_widget
;
4033 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4035 return connect_widget
;
4038 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4041 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4043 return (window
== m_widget
->window
);
4046 bool wxWindowGTK::SetFont( const wxFont
&font
)
4048 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4050 if (!wxWindowBase::SetFont(font
))
4053 // apply style change (forceStyle=true so that new style is applied
4054 // even if the font changed from valid to wxNullFont):
4055 ApplyWidgetStyle(true);
4060 void wxWindowGTK::DoCaptureMouse()
4062 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4064 GdkWindow
*window
= (GdkWindow
*) NULL
;
4066 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4068 window
= GetConnectWidget()->window
;
4070 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4072 wxCursor
* cursor
= & m_cursor
;
4074 cursor
= wxSTANDARD_CURSOR
;
4076 gdk_pointer_grab( window
, FALSE
,
4078 (GDK_BUTTON_PRESS_MASK
|
4079 GDK_BUTTON_RELEASE_MASK
|
4080 GDK_POINTER_MOTION_HINT_MASK
|
4081 GDK_POINTER_MOTION_MASK
),
4083 cursor
->GetCursor(),
4084 (guint32
)GDK_CURRENT_TIME
);
4085 g_captureWindow
= this;
4086 g_captureWindowHasMouse
= true;
4089 void wxWindowGTK::DoReleaseMouse()
4091 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4093 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4095 g_captureWindow
= (wxWindowGTK
*) NULL
;
4097 GdkWindow
*window
= (GdkWindow
*) NULL
;
4099 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4101 window
= GetConnectWidget()->window
;
4106 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4110 wxWindow
*wxWindowBase::GetCapture()
4112 return (wxWindow
*)g_captureWindow
;
4115 bool wxWindowGTK::IsRetained() const
4120 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4121 int range
, bool refresh
)
4123 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4125 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4127 m_hasScrolling
= true;
4129 if (orient
== wxHORIZONTAL
)
4131 float fpos
= (float)pos
;
4132 float frange
= (float)range
;
4133 float fthumb
= (float)thumbVisible
;
4134 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4135 if (fpos
< 0.0) fpos
= 0.0;
4137 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4138 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4140 SetScrollPos( orient
, pos
, refresh
);
4144 m_oldHorizontalPos
= fpos
;
4146 m_hAdjust
->lower
= 0.0;
4147 m_hAdjust
->upper
= frange
;
4148 m_hAdjust
->value
= fpos
;
4149 m_hAdjust
->step_increment
= 1.0;
4150 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4151 m_hAdjust
->page_size
= fthumb
;
4155 float fpos
= (float)pos
;
4156 float frange
= (float)range
;
4157 float fthumb
= (float)thumbVisible
;
4158 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4159 if (fpos
< 0.0) fpos
= 0.0;
4161 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4162 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4164 SetScrollPos( orient
, pos
, refresh
);
4168 m_oldVerticalPos
= fpos
;
4170 m_vAdjust
->lower
= 0.0;
4171 m_vAdjust
->upper
= frange
;
4172 m_vAdjust
->value
= fpos
;
4173 m_vAdjust
->step_increment
= 1.0;
4174 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4175 m_vAdjust
->page_size
= fthumb
;
4178 if (orient
== wxHORIZONTAL
)
4179 g_signal_emit_by_name (m_hAdjust
, "changed");
4181 g_signal_emit_by_name (m_vAdjust
, "changed");
4184 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4186 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4187 gpointer fn
= orient
== wxHORIZONTAL
4188 ? (gpointer
) gtk_window_hscroll_callback
4189 : (gpointer
) gtk_window_vscroll_callback
;
4191 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4192 g_signal_emit_by_name (adj
, "value_changed");
4193 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4196 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4198 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4199 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4201 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4203 float fpos
= (float)pos
;
4204 if (fpos
> adj
->upper
- adj
->page_size
)
4205 fpos
= adj
->upper
- adj
->page_size
;
4208 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4210 if (fabs(fpos
-adj
->value
) < 0.2)
4214 if ( m_wxwindow
->window
)
4219 int wxWindowGTK::GetScrollThumb( int orient
) const
4221 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4223 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4225 if (orient
== wxHORIZONTAL
)
4226 return (int)(m_hAdjust
->page_size
+0.5);
4228 return (int)(m_vAdjust
->page_size
+0.5);
4231 int wxWindowGTK::GetScrollPos( int orient
) const
4233 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4235 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4237 if (orient
== wxHORIZONTAL
)
4238 return (int)(m_hAdjust
->value
+0.5);
4240 return (int)(m_vAdjust
->value
+0.5);
4243 int wxWindowGTK::GetScrollRange( int orient
) const
4245 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4247 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4249 if (orient
== wxHORIZONTAL
)
4250 return (int)(m_hAdjust
->upper
+0.5);
4252 return (int)(m_vAdjust
->upper
+0.5);
4255 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4257 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4259 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4261 // No scrolling requested.
4262 if ((dx
== 0) && (dy
== 0)) return;
4264 m_clipPaintRegion
= true;
4266 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4268 m_clipPaintRegion
= false;
4271 void wxWindowGTK::SetWindowStyleFlag( long style
)
4273 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4274 wxWindowBase::SetWindowStyleFlag(style
);
4277 // Find the wxWindow at the current mouse position, also returning the mouse
4279 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4281 pt
= wxGetMousePosition();
4282 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4286 // Get the current mouse position.
4287 wxPoint
wxGetMousePosition()
4289 /* This crashes when used within wxHelpContext,
4290 so we have to use the X-specific implementation below.
4292 GdkModifierType *mask;
4293 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4295 return wxPoint(x, y);
4299 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4301 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4302 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4303 Window rootReturn
, childReturn
;
4304 int rootX
, rootY
, winX
, winY
;
4305 unsigned int maskReturn
;
4307 XQueryPointer (display
,
4311 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4312 return wxPoint(rootX
, rootY
);
4316 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4317 void wxAddGrab(wxWindow
* window
)
4319 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4322 void wxRemoveGrab(wxWindow
* window
)
4324 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4327 // ----------------------------------------------------------------------------
4329 // ----------------------------------------------------------------------------
4331 class wxWinModule
: public wxModule
4338 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4341 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4343 bool wxWinModule::OnInit()
4345 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4346 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4351 void wxWinModule::OnExit()
4354 gdk_gc_unref( g_eraseGC
);