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"
52 #include "wx/thread.h"
58 #include "wx/gtk/private.h"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
68 #include <pango/pangox.h>
74 extern GtkContainerClass
*pizza_parent_class
;
76 //-----------------------------------------------------------------------------
77 // documentation on internals
78 //-----------------------------------------------------------------------------
81 I have been asked several times about writing some documentation about
82 the GTK port of wxWidgets, especially its internal structures. Obviously,
83 you cannot understand wxGTK without knowing a little about the GTK, but
84 some more information about what the wxWindow, which is the base class
85 for all other window classes, does seems required as well.
89 What does wxWindow do? It contains the common interface for the following
90 jobs of its descendants:
92 1) Define the rudimentary behaviour common to all window classes, such as
93 resizing, intercepting user input (so as to make it possible to use these
94 events for special purposes in a derived class), window names etc.
96 2) Provide the possibility to contain and manage children, if the derived
97 class is allowed to contain children, which holds true for those window
98 classes which do not display a native GTK widget. To name them, these
99 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
100 work classes are a special case and are handled a bit differently from
101 the rest. The same holds true for the wxNotebook class.
103 3) Provide the possibility to draw into a client area of a window. This,
104 too, only holds true for classes that do not display a native GTK widget
107 4) Provide the entire mechanism for scrolling widgets. This actual inter-
108 face for this is usually in wxScrolledWindow, but the GTK implementation
111 5) A multitude of helper or extra methods for special purposes, such as
112 Drag'n'Drop, managing validators etc.
114 6) Display a border (sunken, raised, simple or none).
116 Normally one might expect, that one wxWidgets window would always correspond
117 to one GTK widget. Under GTK, there is no such allround widget that has all
118 the functionality. Moreover, the GTK defines a client area as a different
119 widget from the actual widget you are handling. Last but not least some
120 special classes (e.g. wxFrame) handle different categories of widgets and
121 still have the possibility to draw something in the client area.
122 It was therefore required to write a special purpose GTK widget, that would
123 represent a client area in the sense of wxWidgets capable to do the jobs
124 2), 3) and 4). I have written this class and it resides in win_gtk.c of
127 All windows must have a widget, with which they interact with other under-
128 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
129 the wxWindow class has a member variable called m_widget which holds a
130 pointer to this widget. When the window class represents a GTK native widget,
131 this is (in most cases) the only GTK widget the class manages. E.g. the
132 wxStaticText class handles only a GtkLabel widget a pointer to which you
133 can find in m_widget (defined in wxWindow)
135 When the class has a client area for drawing into and for containing children
136 it has to handle the client area widget (of the type GtkPizza, defined in
137 win_gtk.c), but there could be any number of widgets, handled by a class
138 The common rule for all windows is only, that the widget that interacts with
139 the rest of GTK must be referenced in m_widget and all other widgets must be
140 children of this widget on the GTK level. The top-most widget, which also
141 represents the client area, must be in the m_wxwindow field and must be of
144 As I said, the window classes that display a GTK native widget only have
145 one widget, so in the case of e.g. the wxButton class m_widget holds a
146 pointer to a GtkButton widget. But windows with client areas (for drawing
147 and children) have a m_widget field that is a pointer to a GtkScrolled-
148 Window and a m_wxwindow field that is pointer to a GtkPizza and this
149 one is (in the GTK sense) a child of the GtkScrolledWindow.
151 If the m_wxwindow field is set, then all input to this widget is inter-
152 cepted and sent to the wxWidgets class. If not, all input to the widget
153 that gets pointed to by m_widget gets intercepted and sent to the class.
157 The design of scrolling in wxWidgets is markedly different from that offered
158 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
159 clicking on a scrollbar belonging to scrolled window will inevitably move
160 the window. In wxWidgets, the scrollbar will only emit an event, send this
161 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
162 which actually moves the window and its subchildren. Note that GtkPizza
163 memorizes how much it has been scrolled but that wxWidgets forgets this
164 so that the two coordinates systems have to be kept in synch. This is done
165 in various places using the pizza->xoffset and pizza->yoffset values.
169 Singularily the most broken code in GTK is the code that is supposed to
170 inform subwindows (child windows) about new positions. Very often, duplicate
171 events are sent without changes in size or position, equally often no
172 events are sent at all (All this is due to a bug in the GtkContainer code
173 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
174 GTK's own system and it simply waits for size events for toplevel windows
175 and then iterates down the respective size events to all window. This has
176 the disadvantage that windows might get size events before the GTK widget
177 actually has the reported size. This doesn't normally pose any problem, but
178 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
179 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
180 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
181 window that is used for OpenGL output really has that size (as reported by
186 If someone at some point of time feels the immense desire to have a look at,
187 change or attempt to optimise the Refresh() logic, this person will need an
188 intimate understanding of what "draw" and "expose" events are and what
189 they are used for, in particular when used in connection with GTK's
190 own windowless widgets. Beware.
194 Cursors, too, have been a constant source of pleasure. The main difficulty
195 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
196 for the parent. To prevent this from doing too much harm, I use idle time
197 to set the cursor over and over again, starting from the toplevel windows
198 and ending with the youngest generation (speaking of parent and child windows).
199 Also don't forget that cursors (like much else) are connected to GdkWindows,
200 not GtkWidgets and that the "window" field of a GtkWidget might very well
201 point to the GdkWindow of the parent widget (-> "window-less widget") and
202 that the two obviously have very different meanings.
206 //-----------------------------------------------------------------------------
208 //-----------------------------------------------------------------------------
210 extern wxList wxPendingDelete
;
211 extern bool g_blockEventsOnDrag
;
212 extern bool g_blockEventsOnScroll
;
213 extern wxCursor g_globalCursor
;
215 static GdkGC
*g_eraseGC
= NULL
;
217 // mouse capture state: the window which has it and if the mouse is currently
219 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
220 static bool g_captureWindowHasMouse
= false;
222 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
224 // the last window which had the focus - this is normally never NULL (except
225 // if we never had focus at all) as even when g_focusWindow is NULL it still
226 // keeps its previous value
227 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
229 // If a window get the focus set but has not been realized
230 // yet, defer setting the focus to idle time.
231 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
233 extern bool g_mainThreadLocked
;
235 //-----------------------------------------------------------------------------
237 //-----------------------------------------------------------------------------
242 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
244 # define DEBUG_MAIN_THREAD
247 #define DEBUG_MAIN_THREAD
250 // the trace mask used for the focus debugging messages
251 #define TRACE_FOCUS _T("focus")
253 //-----------------------------------------------------------------------------
254 // missing gdk functions
255 //-----------------------------------------------------------------------------
258 gdk_window_warp_pointer (GdkWindow
*window
,
263 window
= GDK_ROOT_PARENT();
265 if (!GDK_WINDOW_DESTROYED(window
))
267 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
268 None
, /* not source window -> move from anywhere */
269 GDK_WINDOW_XID(window
), /* dest window */
270 0, 0, 0, 0, /* not source window -> move from anywhere */
275 //-----------------------------------------------------------------------------
277 //-----------------------------------------------------------------------------
279 extern void wxapp_install_idle_handler();
280 extern bool g_isIdle
;
282 //-----------------------------------------------------------------------------
283 // local code (see below)
284 //-----------------------------------------------------------------------------
286 // returns the child of win which currently has focus or NULL if not found
288 // Note: can't be static, needed by textctrl.cpp.
289 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
291 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
293 return (wxWindow
*)NULL
;
295 if ( winFocus
== win
)
296 return (wxWindow
*)win
;
298 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
300 node
= node
->GetNext() )
302 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
307 return (wxWindow
*)NULL
;
310 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
312 // wxUniversal widgets draw the borders and scrollbars themselves
313 #ifndef __WXUNIVERSAL__
320 if (win
->m_hasScrolling
)
322 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
324 GtkRequisition vscroll_req
;
325 vscroll_req
.width
= 2;
326 vscroll_req
.height
= 2;
327 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
328 (scroll_window
->vscrollbar
, &vscroll_req
);
330 GtkRequisition hscroll_req
;
331 hscroll_req
.width
= 2;
332 hscroll_req
.height
= 2;
333 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
334 (scroll_window
->hscrollbar
, &hscroll_req
);
336 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
338 if (scroll_window
->vscrollbar_visible
)
340 dw
+= vscroll_req
.width
;
341 dw
+= scroll_class
->scrollbar_spacing
;
344 if (scroll_window
->hscrollbar_visible
)
346 dh
+= hscroll_req
.height
;
347 dh
+= scroll_class
->scrollbar_spacing
;
353 if (GTK_WIDGET_NO_WINDOW (widget
))
355 dx
+= widget
->allocation
.x
;
356 dy
+= widget
->allocation
.y
;
359 if (win
->HasFlag(wxRAISED_BORDER
))
361 gtk_draw_shadow( widget
->style
,
366 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
370 if (win
->HasFlag(wxSUNKEN_BORDER
))
372 gtk_draw_shadow( widget
->style
,
377 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
381 if (win
->HasFlag(wxSIMPLE_BORDER
))
384 gc
= gdk_gc_new( widget
->window
);
385 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
386 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
388 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
392 #endif // __WXUNIVERSAL__
395 //-----------------------------------------------------------------------------
396 // "expose_event" of m_widget
397 //-----------------------------------------------------------------------------
400 static gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
402 if (gdk_event
->count
> 0) return FALSE
;
404 draw_frame( widget
, win
);
406 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
412 //-----------------------------------------------------------------------------
413 // "size_request" of m_widget
414 //-----------------------------------------------------------------------------
416 // make it extern because wxStaticText needs to disconnect this one
418 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
419 GtkRequisition
*requisition
,
423 win
->GetSize( &w
, &h
);
429 requisition
->height
= h
;
430 requisition
->width
= w
;
436 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
437 GtkRequisition
*requisition
,
440 // This callback is actually hooked into the text entry
441 // of the combo box, not the GtkHBox.
444 win
->GetSize( &w
, &h
);
450 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
452 GtkRequisition entry_req
;
454 entry_req
.height
= 2;
455 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
456 (gcombo
->button
, &entry_req
);
458 requisition
->width
= w
- entry_req
.width
;
459 requisition
->height
= entry_req
.height
;
463 //-----------------------------------------------------------------------------
464 // "expose_event" of m_wxwindow
465 //-----------------------------------------------------------------------------
468 static int gtk_window_expose_callback( GtkWidget
*widget
,
469 GdkEventExpose
*gdk_event
,
475 wxapp_install_idle_handler();
477 // This callback gets called in drawing-idle time under
478 // GTK 2.0, so we don't need to defer anything to idle
481 GtkPizza
*pizza
= GTK_PIZZA( widget
);
482 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
487 wxPrintf( wxT("OnExpose from ") );
488 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
489 wxPrintf( win
->GetClassInfo()->GetClassName() );
490 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
491 (int)gdk_event
->area
.y
,
492 (int)gdk_event
->area
.width
,
493 (int)gdk_event
->area
.height
);
498 win
->m_wxwindow
->style
,
502 (GdkRectangle
*) NULL
,
504 (char *)"button", // const_cast
509 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
511 win
->GtkSendPaintEvents();
514 // Let parent window draw window-less widgets
515 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
521 //-----------------------------------------------------------------------------
522 // "key_press_event" from any window
523 //-----------------------------------------------------------------------------
525 // set WXTRACE to this to see the key event codes on the console
526 #define TRACE_KEYS _T("keyevent")
528 // translates an X key symbol to WXK_XXX value
530 // if isChar is true it means that the value returned will be used for EVT_CHAR
531 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
532 // for example, while if it is false it means that the value is going to be
533 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
535 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
541 // Shift, Control and Alt don't generate the CHAR events at all
544 key_code
= isChar
? 0 : WXK_SHIFT
;
548 key_code
= isChar
? 0 : WXK_CONTROL
;
556 key_code
= isChar
? 0 : WXK_ALT
;
559 // neither do the toggle modifies
560 case GDK_Scroll_Lock
:
561 key_code
= isChar
? 0 : WXK_SCROLL
;
565 key_code
= isChar
? 0 : WXK_CAPITAL
;
569 key_code
= isChar
? 0 : WXK_NUMLOCK
;
573 // various other special keys
586 case GDK_ISO_Left_Tab
:
593 key_code
= WXK_RETURN
;
597 key_code
= WXK_CLEAR
;
601 key_code
= WXK_PAUSE
;
605 key_code
= WXK_SELECT
;
609 key_code
= WXK_PRINT
;
613 key_code
= WXK_EXECUTE
;
617 key_code
= WXK_ESCAPE
;
620 // cursor and other extended keyboard keys
622 key_code
= WXK_DELETE
;
638 key_code
= WXK_RIGHT
;
645 case GDK_Prior
: // == GDK_Page_Up
646 key_code
= WXK_PRIOR
;
649 case GDK_Next
: // == GDK_Page_Down
662 key_code
= WXK_INSERT
;
677 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
681 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
685 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
689 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
693 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
697 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
701 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
705 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
709 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
713 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
717 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
721 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
725 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
728 case GDK_KP_Prior
: // == GDK_KP_Page_Up
729 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
732 case GDK_KP_Next
: // == GDK_KP_Page_Down
733 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
737 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
741 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
745 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
749 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
753 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
756 case GDK_KP_Multiply
:
757 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
761 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
764 case GDK_KP_Separator
:
765 // FIXME: what is this?
766 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
769 case GDK_KP_Subtract
:
770 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
774 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
778 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
795 key_code
= WXK_F1
+ keysym
- GDK_F1
;
805 static inline bool wxIsAsciiKeysym(KeySym ks
)
810 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
812 GdkEventKey
*gdk_event
)
816 GdkModifierType state
;
817 if (gdk_event
->window
)
818 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
820 event
.SetTimestamp( gdk_event
->time
);
821 event
.SetId(win
->GetId());
822 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
823 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
824 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
825 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
826 event
.m_scanCode
= gdk_event
->keyval
;
827 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
828 event
.m_rawFlags
= 0;
830 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
832 wxGetMousePosition( &x
, &y
);
833 win
->ScreenToClient( &x
, &y
);
836 event
.SetEventObject( win
);
841 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
843 GdkEventKey
*gdk_event
)
845 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
846 // but only event->keyval which is quite useless to us, so remember
847 // the last character from GDK_KEY_PRESS and reuse it as last resort
849 // NB: should be MT-safe as we're always called from the main thread only
854 } s_lastKeyPress
= { 0, 0 };
856 KeySym keysym
= gdk_event
->keyval
;
858 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
859 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
863 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
867 // do we have the translation or is it a plain ASCII character?
868 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
870 // we should use keysym if it is ASCII as X does some translations
871 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
872 // which we don't want here (but which we do use for OnChar())
873 if ( !wxIsAsciiKeysym(keysym
) )
875 keysym
= (KeySym
)gdk_event
->string
[0];
878 // we want to always get the same key code when the same key is
879 // pressed regardless of the state of the modifiers, i.e. on a
880 // standard US keyboard pressing '5' or '%' ('5' key with
881 // Shift) should result in the same key code in OnKeyDown():
882 // '5' (although OnChar() will get either '5' or '%').
884 // to do it we first translate keysym to keycode (== scan code)
885 // and then back but always using the lower register
886 Display
*dpy
= (Display
*)wxGetDisplay();
887 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
889 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
891 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
893 // use the normalized, i.e. lower register, keysym if we've
895 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
897 // as explained above, we want to have lower register key codes
898 // normally but for the letter keys we want to have the upper ones
900 // NB: don't use XConvertCase() here, we want to do it for letters
902 key_code
= toupper(key_code
);
904 else // non ASCII key, what to do?
906 // by default, ignore it
909 // but if we have cached information from the last KEY_PRESS
910 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
913 if ( keysym
== s_lastKeyPress
.keysym
)
915 key_code
= s_lastKeyPress
.keycode
;
920 if ( gdk_event
->type
== GDK_KEY_PRESS
)
922 // remember it to be reused for KEY_UP event later
923 s_lastKeyPress
.keysym
= keysym
;
924 s_lastKeyPress
.keycode
= key_code
;
928 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
930 // sending unknown key events doesn't really make sense
934 // now fill all the other fields
935 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
937 event
.m_keyCode
= key_code
;
945 GtkIMContext
*context
;
946 GdkEventKey
*lastKeyEvent
;
950 context
= gtk_im_multicontext_new();
955 g_object_unref(context
);
960 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
961 GdkEventKey
*gdk_event
,
967 wxapp_install_idle_handler();
971 if (g_blockEventsOnDrag
)
975 wxKeyEvent
event( wxEVT_KEY_DOWN
);
977 bool return_after_IM
= false;
979 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) == false )
981 // Return after IM processing as we cannot do
982 // anything with it anyhow.
983 return_after_IM
= true;
986 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
987 // When we get a key_press event here, it could be originate
988 // from the current widget or its child widgets. However, only the widget
989 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
990 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
991 // originated from its child widgets and shouldn't be passed to IM context.
992 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
993 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
994 // widgets has both IM context and input focus, the event should be filtered
995 // by gtk_im_context_filter_keypress().
996 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
997 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
999 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1000 // docs, if IM filter returns true, no further processing should be done.
1001 // we should send the key_down event anyway.
1002 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1003 win
->m_imData
->lastKeyEvent
= NULL
;
1004 if (intercepted_by_IM
)
1006 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1011 if (return_after_IM
)
1014 // Emit KEY_DOWN event
1015 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1020 wxWindowGTK
*ancestor
= win
;
1023 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1026 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1027 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1030 if (ancestor
->IsTopLevel())
1032 ancestor
= ancestor
->GetParent();
1035 #endif // wxUSE_ACCEL
1037 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1038 // will only be sent if it is not in an accelerator table.
1042 KeySym keysym
= gdk_event
->keyval
;
1043 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1044 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1047 if ( wxIsAsciiKeysym(keysym
) )
1050 key_code
= (unsigned char)keysym
;
1052 // gdk_event->string is actually deprecated
1053 else if ( gdk_event
->length
== 1 )
1055 key_code
= (unsigned char)gdk_event
->string
[0];
1061 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1063 event
.m_keyCode
= key_code
;
1065 // Implement OnCharHook by checking ancestor top level windows
1066 wxWindow
*parent
= win
;
1067 while (parent
&& !parent
->IsTopLevel())
1068 parent
= parent
->GetParent();
1071 event
.SetEventType( wxEVT_CHAR_HOOK
);
1072 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1077 event
.SetEventType(wxEVT_CHAR
);
1078 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1087 // win is a control: tab can be propagated up
1089 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1090 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1091 // have this style, yet choose not to process this particular TAB in which
1092 // case TAB must still work as a navigational character
1093 // JS: enabling again to make consistent with other platforms
1094 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1095 // navigation behaviour)
1097 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1099 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1101 wxNavigationKeyEvent new_event
;
1102 new_event
.SetEventObject( win
->GetParent() );
1103 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1104 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1105 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1106 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1107 new_event
.SetCurrentFocus( win
);
1108 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1111 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1113 (gdk_event
->keyval
== GDK_Escape
) )
1115 // however only do it if we have a Cancel button in the dialog,
1116 // otherwise the user code may get confused by the events from a
1117 // non-existing button and, worse, a wxButton might get button event
1118 // from another button which is not really expected
1119 wxWindow
*winForCancel
= win
,
1121 while ( winForCancel
)
1123 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1126 // found a cancel button
1130 if ( winForCancel
->IsTopLevel() )
1132 // no need to look further
1136 // maybe our parent has a cancel button?
1137 winForCancel
= winForCancel
->GetParent();
1142 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1143 eventClick
.SetEventObject(btnCancel
);
1144 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1150 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1159 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1163 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1165 // take modifiers, cursor position, timestamp etc. from the last
1166 // key_press_event that was fed into Input Method:
1167 if (window
->m_imData
->lastKeyEvent
)
1169 wxFillOtherKeyEventFields(event
,
1170 window
, window
->m_imData
->lastKeyEvent
);
1174 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1176 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1177 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1178 #endif // wxUSE_UNICODE
1179 if( !(const wxChar
*)data
)
1184 // Implement OnCharHook by checking ancestor top level windows
1185 wxWindow
*parent
= window
;
1186 while (parent
&& !parent
->IsTopLevel())
1187 parent
= parent
->GetParent();
1189 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1192 event
.m_uniChar
= *pstr
;
1193 // Backward compatible for ISO-8859-1
1194 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1195 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1197 event
.m_keyCode
= *pstr
;
1198 #endif // wxUSE_UNICODE
1201 event
.SetEventType( wxEVT_CHAR_HOOK
);
1202 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1207 event
.SetEventType(wxEVT_CHAR
);
1208 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1215 //-----------------------------------------------------------------------------
1216 // "key_release_event" from any window
1217 //-----------------------------------------------------------------------------
1220 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1221 GdkEventKey
*gdk_event
,
1227 wxapp_install_idle_handler();
1232 if (g_blockEventsOnDrag
)
1235 wxKeyEvent
event( wxEVT_KEY_UP
);
1236 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1238 // unknown key pressed, ignore (the event would be useless anyhow)
1242 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1245 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1250 // ============================================================================
1252 // ============================================================================
1254 // ----------------------------------------------------------------------------
1255 // mouse event processing helpers
1256 // ----------------------------------------------------------------------------
1258 // init wxMouseEvent with the info from GdkEventXXX struct
1259 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1260 wxMouseEvent
& event
,
1263 event
.SetTimestamp( gdk_event
->time
);
1264 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1265 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1266 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1267 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1268 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1269 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1270 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1271 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1273 event
.m_linesPerAction
= 3;
1274 event
.m_wheelDelta
= 120;
1275 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1276 event
.m_wheelRotation
= 120;
1277 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1278 event
.m_wheelRotation
= -120;
1281 wxPoint pt
= win
->GetClientAreaOrigin();
1282 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1283 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1285 event
.SetEventObject( win
);
1286 event
.SetId( win
->GetId() );
1287 event
.SetTimestamp( gdk_event
->time
);
1290 static void AdjustEventButtonState(wxMouseEvent
& event
)
1292 // GDK reports the old state of the button for a button press event, but
1293 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1294 // for a LEFT_DOWN event, not FALSE, so we will invert
1295 // left/right/middleDown for the corresponding click events
1297 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1298 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1299 (event
.GetEventType() == wxEVT_LEFT_UP
))
1301 event
.m_leftDown
= !event
.m_leftDown
;
1305 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1306 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1307 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1309 event
.m_middleDown
= !event
.m_middleDown
;
1313 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1314 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1315 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1317 event
.m_rightDown
= !event
.m_rightDown
;
1322 // find the window to send the mouse event too
1324 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1329 if (win
->m_wxwindow
)
1331 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1332 xx
+= pizza
->xoffset
;
1333 yy
+= pizza
->yoffset
;
1336 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1339 wxWindowGTK
*child
= node
->GetData();
1341 node
= node
->GetNext();
1342 if (!child
->IsShown())
1345 if (child
->IsTransparentForMouse())
1347 // wxStaticBox is transparent in the box itself
1348 int xx1
= child
->m_x
;
1349 int yy1
= child
->m_y
;
1350 int xx2
= child
->m_x
+ child
->m_width
;
1351 int yy2
= child
->m_y
+ child
->m_height
;
1354 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1356 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1358 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1360 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1371 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1372 (child
->m_x
<= xx
) &&
1373 (child
->m_y
<= yy
) &&
1374 (child
->m_x
+child
->m_width
>= xx
) &&
1375 (child
->m_y
+child
->m_height
>= yy
))
1388 //-----------------------------------------------------------------------------
1389 // "button_press_event"
1390 //-----------------------------------------------------------------------------
1393 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1394 GdkEventButton
*gdk_event
,
1400 wxapp_install_idle_handler();
1403 wxPrintf( wxT("1) OnButtonPress from ") );
1404 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1405 wxPrintf( win->GetClassInfo()->GetClassName() );
1406 wxPrintf( wxT(".\n") );
1408 if (!win
->m_hasVMT
) return FALSE
;
1409 if (g_blockEventsOnDrag
) return TRUE
;
1410 if (g_blockEventsOnScroll
) return TRUE
;
1412 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1414 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1416 gtk_widget_grab_focus( win
->m_wxwindow
);
1418 wxPrintf( wxT("GrabFocus from ") );
1419 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1420 wxPrintf( win->GetClassInfo()->GetClassName() );
1421 wxPrintf( wxT(".\n") );
1425 // GDK sends surplus button down events
1426 // before a double click event. We
1427 // need to filter these out.
1428 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1430 GdkEvent
*peek_event
= gdk_event_peek();
1433 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1434 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1436 gdk_event_free( peek_event
);
1441 gdk_event_free( peek_event
);
1446 wxEventType event_type
= wxEVT_NULL
;
1448 // GdkDisplay is a GTK+ 2.2.0 thing
1449 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1450 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1451 !gtk_check_version(2,2,0) &&
1452 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1454 // Reset GDK internal timestamp variables in order to disable GDK
1455 // triple click events. GDK will then next time believe no button has
1456 // been clicked just before, and send a normal button click event.
1457 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1458 display
->button_click_time
[1] = 0;
1459 display
->button_click_time
[0] = 0;
1463 if (gdk_event
->button
== 1)
1465 // note that GDK generates triple click events which are not supported
1466 // by wxWidgets but still have to be passed to the app as otherwise
1467 // clicks would simply go missing
1468 switch (gdk_event
->type
)
1470 // we shouldn't get triple clicks at all for GTK2 because we
1471 // suppress them artificially using the code above but we still
1472 // should map them to something for GTK1 and not just ignore them
1473 // as this would lose clicks
1474 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1475 case GDK_BUTTON_PRESS
:
1476 event_type
= wxEVT_LEFT_DOWN
;
1479 case GDK_2BUTTON_PRESS
:
1480 event_type
= wxEVT_LEFT_DCLICK
;
1484 // just to silence gcc warnings
1488 else if (gdk_event
->button
== 2)
1490 switch (gdk_event
->type
)
1492 case GDK_3BUTTON_PRESS
:
1493 case GDK_BUTTON_PRESS
:
1494 event_type
= wxEVT_MIDDLE_DOWN
;
1497 case GDK_2BUTTON_PRESS
:
1498 event_type
= wxEVT_MIDDLE_DCLICK
;
1505 else if (gdk_event
->button
== 3)
1507 switch (gdk_event
->type
)
1509 case GDK_3BUTTON_PRESS
:
1510 case GDK_BUTTON_PRESS
:
1511 event_type
= wxEVT_RIGHT_DOWN
;
1514 case GDK_2BUTTON_PRESS
:
1515 event_type
= wxEVT_RIGHT_DCLICK
;
1522 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1524 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1526 event_type
= wxEVT_MOUSEWHEEL
;
1530 if ( event_type
== wxEVT_NULL
)
1532 // unknown mouse button or click type
1536 wxMouseEvent
event( event_type
);
1537 InitMouseEvent( win
, event
, gdk_event
);
1539 AdjustEventButtonState(event
);
1541 // wxListBox actually gets mouse events from the item, so we need to give it
1542 // a chance to correct this
1543 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1545 // find the correct window to send the event to: it may be a different one
1546 // from the one which got it at GTK+ level because some controls don't have
1547 // their own X window and thus cannot get any events.
1548 if ( !g_captureWindow
)
1549 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1551 if (win
->GetEventHandler()->ProcessEvent( event
))
1553 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1557 if (event_type
== wxEVT_RIGHT_DOWN
)
1559 // generate a "context menu" event: this is similar to right mouse
1560 // click under many GUIs except that it is generated differently
1561 // (right up under MSW, ctrl-click under Mac, right down here) and
1563 // (a) it's a command event and so is propagated to the parent
1564 // (b) under some ports it can be generated from kbd too
1565 // (c) it uses screen coords (because of (a))
1566 wxContextMenuEvent
evtCtx(
1569 win
->ClientToScreen(event
.GetPosition()));
1570 evtCtx
.SetEventObject(win
);
1571 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1578 //-----------------------------------------------------------------------------
1579 // "button_release_event"
1580 //-----------------------------------------------------------------------------
1583 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1584 GdkEventButton
*gdk_event
,
1590 wxapp_install_idle_handler();
1592 if (!win
->m_hasVMT
) return FALSE
;
1593 if (g_blockEventsOnDrag
) return FALSE
;
1594 if (g_blockEventsOnScroll
) return FALSE
;
1596 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1598 wxEventType event_type
= wxEVT_NULL
;
1600 switch (gdk_event
->button
)
1603 event_type
= wxEVT_LEFT_UP
;
1607 event_type
= wxEVT_MIDDLE_UP
;
1611 event_type
= wxEVT_RIGHT_UP
;
1615 // unknwon button, don't process
1619 wxMouseEvent
event( event_type
);
1620 InitMouseEvent( win
, event
, gdk_event
);
1622 AdjustEventButtonState(event
);
1624 // same wxListBox hack as above
1625 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1627 if ( !g_captureWindow
)
1628 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1630 if (win
->GetEventHandler()->ProcessEvent( event
))
1632 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1640 //-----------------------------------------------------------------------------
1641 // "motion_notify_event"
1642 //-----------------------------------------------------------------------------
1645 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1646 GdkEventMotion
*gdk_event
,
1652 wxapp_install_idle_handler();
1654 if (!win
->m_hasVMT
) return FALSE
;
1655 if (g_blockEventsOnDrag
) return FALSE
;
1656 if (g_blockEventsOnScroll
) return FALSE
;
1658 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1660 if (gdk_event
->is_hint
)
1664 GdkModifierType state
;
1665 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1671 printf( "OnMotion from " );
1672 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1673 printf( win->GetClassInfo()->GetClassName() );
1677 wxMouseEvent
event( wxEVT_MOTION
);
1678 InitMouseEvent(win
, event
, gdk_event
);
1680 if ( g_captureWindow
)
1682 // synthetize a mouse enter or leave event if needed
1683 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1684 // This seems to be necessary and actually been added to
1685 // GDK itself in version 2.0.X
1688 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1689 if ( hasMouse
!= g_captureWindowHasMouse
)
1691 // the mouse changed window
1692 g_captureWindowHasMouse
= hasMouse
;
1694 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1695 : wxEVT_LEAVE_WINDOW
);
1696 InitMouseEvent(win
, eventM
, gdk_event
);
1697 eventM
.SetEventObject(win
);
1698 win
->GetEventHandler()->ProcessEvent(eventM
);
1703 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1706 if (win
->GetEventHandler()->ProcessEvent( event
))
1708 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1716 //-----------------------------------------------------------------------------
1717 // "mouse_wheel_event"
1718 //-----------------------------------------------------------------------------
1721 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1722 GdkEventScroll
* gdk_event
,
1728 wxapp_install_idle_handler();
1730 wxEventType event_type
= wxEVT_NULL
;
1731 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1732 event_type
= wxEVT_MOUSEWHEEL
;
1733 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1734 event_type
= wxEVT_MOUSEWHEEL
;
1738 wxMouseEvent
event( event_type
);
1739 // Can't use InitMouse macro because scroll events don't have button
1740 event
.SetTimestamp( gdk_event
->time
);
1741 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1742 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1743 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1744 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1745 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1746 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1747 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1748 event
.m_linesPerAction
= 3;
1749 event
.m_wheelDelta
= 120;
1750 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1751 event
.m_wheelRotation
= 120;
1753 event
.m_wheelRotation
= -120;
1755 wxPoint pt
= win
->GetClientAreaOrigin();
1756 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1757 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1759 event
.SetEventObject( win
);
1760 event
.SetId( win
->GetId() );
1761 event
.SetTimestamp( gdk_event
->time
);
1763 if (win
->GetEventHandler()->ProcessEvent( event
))
1765 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1773 //-----------------------------------------------------------------------------
1775 //-----------------------------------------------------------------------------
1777 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1779 wxContextMenuEvent
event(
1783 event
.SetEventObject(win
);
1784 return win
->GetEventHandler()->ProcessEvent(event
);
1788 //-----------------------------------------------------------------------------
1790 //-----------------------------------------------------------------------------
1792 // send the wxChildFocusEvent and wxFocusEvent, common code of
1793 // gtk_window_focus_in_callback() and SetFocus()
1794 static bool DoSendFocusEvents(wxWindow
*win
)
1796 // Notify the parent keeping track of focus for the kbd navigation
1797 // purposes that we got it.
1798 wxChildFocusEvent
eventChildFocus(win
);
1799 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1801 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1802 eventFocus
.SetEventObject(win
);
1804 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1808 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1809 GdkEvent
*WXUNUSED(event
),
1815 wxapp_install_idle_handler();
1818 gtk_im_context_focus_in(win
->m_imData
->context
);
1821 g_focusWindow
= win
;
1823 wxLogTrace(TRACE_FOCUS
,
1824 _T("%s: focus in"), win
->GetName().c_str());
1828 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1832 // caret needs to be informed about focus change
1833 wxCaret
*caret
= win
->GetCaret();
1836 caret
->OnSetFocus();
1838 #endif // wxUSE_CARET
1840 // does the window itself think that it has the focus?
1841 if ( !win
->m_hasFocus
)
1843 // not yet, notify it
1844 win
->m_hasFocus
= true;
1846 if ( DoSendFocusEvents(win
) )
1848 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1857 //-----------------------------------------------------------------------------
1858 // "focus_out_event"
1859 //-----------------------------------------------------------------------------
1862 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1867 wxapp_install_idle_handler();
1870 gtk_im_context_focus_out(win
->m_imData
->context
);
1872 wxLogTrace( TRACE_FOCUS
,
1873 _T("%s: focus out"), win
->GetName().c_str() );
1876 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1880 g_focusWindow
= (wxWindowGTK
*)NULL
;
1888 // caret needs to be informed about focus change
1889 wxCaret
*caret
= win
->GetCaret();
1892 caret
->OnKillFocus();
1894 #endif // wxUSE_CARET
1896 // don't send the window a kill focus event if it thinks that it doesn't
1897 // have focus already
1898 if ( win
->m_hasFocus
)
1900 win
->m_hasFocus
= false;
1902 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1903 event
.SetEventObject( win
);
1905 // even if we did process the event in wx code, still let GTK itself
1906 // process it too as otherwise bad things happen, especially in GTK2
1907 // where the text control simply aborts the program if it doesn't get
1908 // the matching focus out event
1909 (void)win
->GetEventHandler()->ProcessEvent( event
);
1916 //-----------------------------------------------------------------------------
1917 // "enter_notify_event"
1918 //-----------------------------------------------------------------------------
1922 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1923 GdkEventCrossing
*gdk_event
,
1929 wxapp_install_idle_handler();
1931 if (!win
->m_hasVMT
) return FALSE
;
1932 if (g_blockEventsOnDrag
) return FALSE
;
1934 // Event was emitted after a grab
1935 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1937 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1941 GdkModifierType state
= (GdkModifierType
)0;
1943 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1945 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1946 InitMouseEvent(win
, event
, gdk_event
);
1947 wxPoint pt
= win
->GetClientAreaOrigin();
1948 event
.m_x
= x
+ pt
.x
;
1949 event
.m_y
= y
+ pt
.y
;
1951 if (win
->GetEventHandler()->ProcessEvent( event
))
1953 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1961 //-----------------------------------------------------------------------------
1962 // "leave_notify_event"
1963 //-----------------------------------------------------------------------------
1966 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1971 wxapp_install_idle_handler();
1973 if (!win
->m_hasVMT
) return FALSE
;
1974 if (g_blockEventsOnDrag
) return FALSE
;
1976 // Event was emitted after an ungrab
1977 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1979 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1981 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1982 event
.SetTimestamp( gdk_event
->time
);
1983 event
.SetEventObject( win
);
1987 GdkModifierType state
= (GdkModifierType
)0;
1989 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1991 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1992 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1993 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1994 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1995 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1996 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1997 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1999 wxPoint pt
= win
->GetClientAreaOrigin();
2000 event
.m_x
= x
+ pt
.x
;
2001 event
.m_y
= y
+ pt
.y
;
2003 if (win
->GetEventHandler()->ProcessEvent( event
))
2005 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2013 //-----------------------------------------------------------------------------
2014 // "value_changed" from m_vAdjust
2015 //-----------------------------------------------------------------------------
2018 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2025 wxapp_install_idle_handler();
2027 if (g_blockEventsOnDrag
) return;
2029 if (!win
->m_hasVMT
) return;
2031 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2032 if (fabs(diff
) < 0.2) return;
2034 win
->m_oldVerticalPos
= adjust
->value
;
2036 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2038 int value
= (int)(adjust
->value
+0.5);
2040 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2041 event
.SetEventObject( win
);
2042 win
->GetEventHandler()->ProcessEvent( event
);
2046 //-----------------------------------------------------------------------------
2047 // "value_changed" from m_hAdjust
2048 //-----------------------------------------------------------------------------
2051 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2058 wxapp_install_idle_handler();
2060 if (g_blockEventsOnDrag
) return;
2061 if (!win
->m_hasVMT
) return;
2063 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2064 if (fabs(diff
) < 0.2) return;
2066 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2068 win
->m_oldHorizontalPos
= adjust
->value
;
2070 int value
= (int)(adjust
->value
+0.5);
2072 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2073 event
.SetEventObject( win
);
2074 win
->GetEventHandler()->ProcessEvent( event
);
2078 //-----------------------------------------------------------------------------
2079 // "button_press_event" from scrollbar
2080 //-----------------------------------------------------------------------------
2083 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2084 GdkEventButton
*gdk_event
,
2090 wxapp_install_idle_handler();
2093 g_blockEventsOnScroll
= true;
2095 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2097 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2104 //-----------------------------------------------------------------------------
2105 // "button_release_event" from scrollbar
2106 //-----------------------------------------------------------------------------
2109 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2110 GdkEventButton
*WXUNUSED(gdk_event
),
2115 // don't test here as we can release the mouse while being over
2116 // a different window than the slider
2118 // if (gdk_event->window != widget->slider) return FALSE;
2120 g_blockEventsOnScroll
= false;
2122 if (win
->m_isScrolling
)
2124 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2128 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2129 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2131 value
= (int)(win
->m_hAdjust
->value
+0.5);
2134 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2136 value
= (int)(win
->m_vAdjust
->value
+0.5);
2140 wxScrollWinEvent
event( command
, value
, dir
);
2141 event
.SetEventObject( win
);
2142 win
->GetEventHandler()->ProcessEvent( event
);
2145 win
->m_isScrolling
= false;
2151 // ----------------------------------------------------------------------------
2152 // this wxWindowBase function is implemented here (in platform-specific file)
2153 // because it is static and so couldn't be made virtual
2154 // ----------------------------------------------------------------------------
2156 wxWindow
*wxWindowBase::DoFindFocus()
2158 // the cast is necessary when we compile in wxUniversal mode
2159 return (wxWindow
*)g_focusWindow
;
2162 //-----------------------------------------------------------------------------
2163 // "realize" from m_widget
2164 //-----------------------------------------------------------------------------
2166 /* We cannot set colours and fonts before the widget has
2167 been realized, so we do this directly after realization. */
2171 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2176 wxapp_install_idle_handler();
2180 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2181 gtk_im_context_set_client_window( win
->m_imData
->context
,
2182 pizza
->bin_window
);
2185 wxWindowCreateEvent
event( win
);
2186 event
.SetEventObject( win
);
2187 win
->GetEventHandler()->ProcessEvent( event
);
2193 //-----------------------------------------------------------------------------
2195 //-----------------------------------------------------------------------------
2199 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2200 GtkAllocation
*WXUNUSED(alloc
),
2204 wxapp_install_idle_handler();
2206 if (!win
->m_hasScrolling
) return;
2208 int client_width
= 0;
2209 int client_height
= 0;
2210 win
->GetClientSize( &client_width
, &client_height
);
2211 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2214 win
->m_oldClientWidth
= client_width
;
2215 win
->m_oldClientHeight
= client_height
;
2217 if (!win
->m_nativeSizeEvent
)
2219 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2220 event
.SetEventObject( win
);
2221 win
->GetEventHandler()->ProcessEvent( event
);
2228 #define WXUNUSED_UNLESS_XIM(param) param
2230 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2233 /* Resize XIM window */
2237 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2238 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2239 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2242 wxapp_install_idle_handler();
2248 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2252 gdk_window_get_size (widget
->window
, &width
, &height
);
2253 win
->m_icattr
->preedit_area
.width
= width
;
2254 win
->m_icattr
->preedit_area
.height
= height
;
2255 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2261 //-----------------------------------------------------------------------------
2262 // "realize" from m_wxwindow
2263 //-----------------------------------------------------------------------------
2265 /* Initialize XIM support */
2269 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2270 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2273 wxapp_install_idle_handler();
2276 if (win
->m_ic
) return FALSE
;
2277 if (!widget
) return FALSE
;
2278 if (!gdk_im_ready()) return FALSE
;
2280 win
->m_icattr
= gdk_ic_attr_new();
2281 if (!win
->m_icattr
) return FALSE
;
2285 GdkColormap
*colormap
;
2286 GdkICAttr
*attr
= win
->m_icattr
;
2287 unsigned attrmask
= GDK_IC_ALL_REQ
;
2289 GdkIMStyle supported_style
= (GdkIMStyle
)
2290 (GDK_IM_PREEDIT_NONE
|
2291 GDK_IM_PREEDIT_NOTHING
|
2292 GDK_IM_PREEDIT_POSITION
|
2293 GDK_IM_STATUS_NONE
|
2294 GDK_IM_STATUS_NOTHING
);
2296 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2297 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2299 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2300 attr
->client_window
= widget
->window
;
2302 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2303 gtk_widget_get_default_colormap ())
2305 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2306 attr
->preedit_colormap
= colormap
;
2309 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2310 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2311 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2312 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2314 switch (style
& GDK_IM_PREEDIT_MASK
)
2316 case GDK_IM_PREEDIT_POSITION
:
2317 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2319 g_warning ("over-the-spot style requires fontset");
2323 gdk_window_get_size (widget
->window
, &width
, &height
);
2325 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2326 attr
->spot_location
.x
= 0;
2327 attr
->spot_location
.y
= height
;
2328 attr
->preedit_area
.x
= 0;
2329 attr
->preedit_area
.y
= 0;
2330 attr
->preedit_area
.width
= width
;
2331 attr
->preedit_area
.height
= height
;
2332 attr
->preedit_fontset
= widget
->style
->font
;
2337 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2339 if (win
->m_ic
== NULL
)
2340 g_warning ("Can't create input context.");
2343 mask
= gdk_window_get_events (widget
->window
);
2344 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2345 gdk_window_set_events (widget
->window
, mask
);
2347 if (GTK_WIDGET_HAS_FOCUS(widget
))
2348 gdk_im_begin (win
->m_ic
, widget
->window
);
2356 //-----------------------------------------------------------------------------
2357 // InsertChild for wxWindowGTK.
2358 //-----------------------------------------------------------------------------
2360 /* Callback for wxWindowGTK. This very strange beast has to be used because
2361 * C++ has no virtual methods in a constructor. We have to emulate a
2362 * virtual function here as wxNotebook requires a different way to insert
2363 * a child in it. I had opted for creating a wxNotebookPage window class
2364 * which would have made this superfluous (such in the MDI window system),
2365 * but no-one was listening to me... */
2367 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2369 /* the window might have been scrolled already, do we
2370 have to adapt the position */
2371 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2372 child
->m_x
+= pizza
->xoffset
;
2373 child
->m_y
+= pizza
->yoffset
;
2375 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2376 GTK_WIDGET(child
->m_widget
),
2383 //-----------------------------------------------------------------------------
2385 //-----------------------------------------------------------------------------
2387 wxWindow
*wxGetActiveWindow()
2389 return wxWindow::FindFocus();
2393 wxMouseState
wxGetMouseState()
2399 GdkModifierType mask
;
2401 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2405 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2406 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2407 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2409 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2410 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2411 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2412 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2417 //-----------------------------------------------------------------------------
2419 //-----------------------------------------------------------------------------
2421 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2423 #ifdef __WXUNIVERSAL__
2424 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2426 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2427 #endif // __WXUNIVERSAL__/__WXGTK__
2429 void wxWindowGTK::Init()
2432 m_widget
= (GtkWidget
*) NULL
;
2433 m_wxwindow
= (GtkWidget
*) NULL
;
2434 m_focusWidget
= (GtkWidget
*) NULL
;
2444 m_needParent
= true;
2445 m_isBeingDeleted
= false;
2448 m_nativeSizeEvent
= false;
2450 m_hasScrolling
= false;
2451 m_isScrolling
= false;
2453 m_hAdjust
= (GtkAdjustment
*) NULL
;
2454 m_vAdjust
= (GtkAdjustment
*) NULL
;
2455 m_oldHorizontalPos
=
2456 m_oldVerticalPos
= 0.0;
2458 m_oldClientHeight
= 0;
2462 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2464 m_acceptsFocus
= false;
2467 m_clipPaintRegion
= false;
2469 m_needsStyleChange
= false;
2471 m_cursor
= *wxSTANDARD_CURSOR
;
2474 m_dirtyTabOrder
= false;
2477 wxWindowGTK::wxWindowGTK()
2482 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2487 const wxString
&name
)
2491 Create( parent
, id
, pos
, size
, style
, name
);
2494 bool wxWindowGTK::Create( wxWindow
*parent
,
2499 const wxString
&name
)
2501 if (!PreCreation( parent
, pos
, size
) ||
2502 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2504 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2508 m_insertCallback
= wxInsertChildInWindow
;
2510 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2511 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2513 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2515 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2516 scroll_class
->scrollbar_spacing
= 0;
2518 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2520 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2521 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2523 m_wxwindow
= gtk_pizza_new();
2525 #ifndef __WXUNIVERSAL__
2526 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2528 if (HasFlag(wxRAISED_BORDER
))
2530 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2532 else if (HasFlag(wxSUNKEN_BORDER
))
2534 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2536 else if (HasFlag(wxSIMPLE_BORDER
))
2538 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2542 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2544 #endif // __WXUNIVERSAL__
2546 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2548 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2549 m_acceptsFocus
= true;
2551 // I _really_ don't want scrollbars in the beginning
2552 m_vAdjust
->lower
= 0.0;
2553 m_vAdjust
->upper
= 1.0;
2554 m_vAdjust
->value
= 0.0;
2555 m_vAdjust
->step_increment
= 1.0;
2556 m_vAdjust
->page_increment
= 1.0;
2557 m_vAdjust
->page_size
= 5.0;
2558 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2559 m_hAdjust
->lower
= 0.0;
2560 m_hAdjust
->upper
= 1.0;
2561 m_hAdjust
->value
= 0.0;
2562 m_hAdjust
->step_increment
= 1.0;
2563 m_hAdjust
->page_increment
= 1.0;
2564 m_hAdjust
->page_size
= 5.0;
2565 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2567 // these handlers block mouse events to any window during scrolling such as
2568 // motion events and prevent GTK and wxWidgets from fighting over where the
2571 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2572 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2574 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2575 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2577 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2578 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2580 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2581 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2583 // these handlers get notified when screen updates are required either when
2584 // scrolling or when the window size (and therefore scrollbar configuration)
2587 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2588 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2589 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2590 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2592 gtk_widget_show( m_wxwindow
);
2595 m_parent
->DoAddChild( this );
2597 m_focusWidget
= m_wxwindow
;
2604 wxWindowGTK::~wxWindowGTK()
2608 if (g_focusWindow
== this)
2609 g_focusWindow
= NULL
;
2611 if ( g_delayedFocus
== this )
2612 g_delayedFocus
= NULL
;
2614 m_isBeingDeleted
= true;
2617 // destroy children before destroying this window itself
2620 // unhook focus handlers to prevent stray events being
2621 // propagated to this (soon to be) dead object
2622 if (m_focusWidget
!= NULL
)
2624 gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget
),
2625 (GtkSignalFunc
) gtk_window_focus_in_callback
, (gpointer
) this );
2626 gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget
),
2627 (GtkSignalFunc
) gtk_window_focus_out_callback
, (gpointer
) this );
2635 gdk_ic_destroy (m_ic
);
2637 gdk_ic_attr_destroy (m_icattr
);
2640 // delete before the widgets to avoid a crash on solaris
2645 gtk_widget_destroy( m_wxwindow
);
2646 m_wxwindow
= (GtkWidget
*) NULL
;
2651 gtk_widget_destroy( m_widget
);
2652 m_widget
= (GtkWidget
*) NULL
;
2656 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2658 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2660 // Use either the given size, or the default if -1 is given.
2661 // See wxWindowBase for these functions.
2662 m_width
= WidthDefault(size
.x
) ;
2663 m_height
= HeightDefault(size
.y
);
2671 void wxWindowGTK::PostCreation()
2673 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2679 // these get reported to wxWidgets -> wxPaintEvent
2681 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2683 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2684 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2686 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2689 // Create input method handler
2690 m_imData
= new wxGtkIMData
;
2692 // Cannot handle drawing preedited text yet
2693 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2695 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2696 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2698 // these are called when the "sunken" or "raised" borders are drawn
2699 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2700 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2706 if (!GTK_IS_WINDOW(m_widget
))
2708 if (m_focusWidget
== NULL
)
2709 m_focusWidget
= m_widget
;
2711 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2712 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2714 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2715 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2718 // connect to the various key and mouse handlers
2720 GtkWidget
*connect_widget
= GetConnectWidget();
2722 ConnectWidget( connect_widget
);
2724 /* We cannot set colours, fonts and cursors before the widget has
2725 been realized, so we do this directly after realization */
2726 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2727 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2731 // Catch native resize events
2732 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2733 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2735 // Initialize XIM support
2736 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2737 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2739 // And resize XIM window
2740 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2741 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2744 if (GTK_IS_COMBO(m_widget
))
2746 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2748 gtk_signal_connect( GTK_OBJECT(gcombo
->entry
), "size_request",
2749 GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback
),
2754 // This is needed if we want to add our windows into native
2755 // GTK controls, such as the toolbar. With this callback, the
2756 // toolbar gets to know the correct size (the one set by the
2757 // programmer). Sadly, it misbehaves for wxComboBox.
2758 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2759 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2763 InheritAttributes();
2767 // unless the window was created initially hidden (i.e. Hide() had been
2768 // called before Create()), we should show it at GTK+ level as well
2770 gtk_widget_show( m_widget
);
2773 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2775 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2776 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2778 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2779 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2781 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2782 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2784 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2785 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2787 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2788 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2790 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2791 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2792 g_signal_connect(widget
, "popup_menu",
2793 G_CALLBACK(wxgtk_window_popup_menu_callback
), this);
2795 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2796 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2798 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2799 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2802 bool wxWindowGTK::Destroy()
2804 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2808 return wxWindowBase::Destroy();
2811 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2813 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2816 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2818 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2819 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2822 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2825 if (m_resizing
) return; /* I don't like recursions */
2828 int currentX
, currentY
;
2829 GetPosition(¤tX
, ¤tY
);
2830 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2832 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2834 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2836 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2838 /* don't set the size for children of wxNotebook, just take the values. */
2846 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2847 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2849 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2850 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2854 m_x
= x
+ pizza
->xoffset
;
2855 m_y
= y
+ pizza
->yoffset
;
2858 // calculate the best size if we should auto size the window
2859 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2860 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2862 const wxSize sizeBest
= GetBestSize();
2863 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2865 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2866 height
= sizeBest
.y
;
2874 int minWidth
= GetMinWidth(),
2875 minHeight
= GetMinHeight(),
2876 maxWidth
= GetMaxWidth(),
2877 maxHeight
= GetMaxHeight();
2879 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2880 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2881 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2882 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2884 int left_border
= 0;
2885 int right_border
= 0;
2887 int bottom_border
= 0;
2889 /* the default button has a border around it */
2890 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2892 GtkBorder
*default_border
= NULL
;
2893 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2896 left_border
+= default_border
->left
;
2897 right_border
+= default_border
->right
;
2898 top_border
+= default_border
->top
;
2899 bottom_border
+= default_border
->bottom
;
2900 g_free( default_border
);
2904 DoMoveWindow( m_x
-top_border
,
2906 m_width
+left_border
+right_border
,
2907 m_height
+top_border
+bottom_border
);
2912 /* Sometimes the client area changes size without the
2913 whole windows's size changing, but if the whole
2914 windows's size doesn't change, no wxSizeEvent will
2915 normally be sent. Here we add an extra test if
2916 the client test has been changed and this will
2918 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2922 wxPrintf( "OnSize sent from " );
2923 if (GetClassInfo() && GetClassInfo()->GetClassName())
2924 wxPrintf( GetClassInfo()->GetClassName() );
2925 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2928 if (!m_nativeSizeEvent
)
2930 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2931 event
.SetEventObject( this );
2932 GetEventHandler()->ProcessEvent( event
);
2938 void wxWindowGTK::OnInternalIdle()
2940 if ( m_dirtyTabOrder
)
2943 // Update style if the window was not yet realized
2944 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2945 if (m_needsStyleChange
)
2947 SetBackgroundStyle(GetBackgroundStyle());
2948 m_needsStyleChange
= false;
2951 // Update invalidated regions.
2954 wxCursor cursor
= m_cursor
;
2955 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2959 /* I now set the cursor anew in every OnInternalIdle call
2960 as setting the cursor in a parent window also effects the
2961 windows above so that checking for the current cursor is
2966 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2968 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2970 if (!g_globalCursor
.Ok())
2971 cursor
= *wxSTANDARD_CURSOR
;
2973 window
= m_widget
->window
;
2974 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2975 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2981 GdkWindow
*window
= m_widget
->window
;
2982 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2983 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2988 if (wxUpdateUIEvent::CanUpdate(this))
2989 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
2992 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2994 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2996 if (width
) (*width
) = m_width
;
2997 if (height
) (*height
) = m_height
;
3000 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3002 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3006 SetSize( width
, height
);
3013 #ifndef __WXUNIVERSAL__
3014 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3016 /* when using GTK 1.2 we set the shadow border size to 2 */
3020 if (HasFlag(wxSIMPLE_BORDER
))
3022 /* when using GTK 1.2 we set the simple border size to 1 */
3026 #endif // __WXUNIVERSAL__
3030 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3032 GtkRequisition vscroll_req
;
3033 vscroll_req
.width
= 2;
3034 vscroll_req
.height
= 2;
3035 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3036 (scroll_window
->vscrollbar
, &vscroll_req
);
3038 GtkRequisition hscroll_req
;
3039 hscroll_req
.width
= 2;
3040 hscroll_req
.height
= 2;
3041 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3042 (scroll_window
->hscrollbar
, &hscroll_req
);
3044 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3046 if (scroll_window
->vscrollbar_visible
)
3048 dw
+= vscroll_req
.width
;
3049 dw
+= scroll_class
->scrollbar_spacing
;
3052 if (scroll_window
->hscrollbar_visible
)
3054 dh
+= hscroll_req
.height
;
3055 dh
+= scroll_class
->scrollbar_spacing
;
3059 SetSize( width
+dw
, height
+dh
);
3063 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3065 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3069 if (width
) (*width
) = m_width
;
3070 if (height
) (*height
) = m_height
;
3077 #ifndef __WXUNIVERSAL__
3078 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3080 /* when using GTK 1.2 we set the shadow border size to 2 */
3084 if (HasFlag(wxSIMPLE_BORDER
))
3086 /* when using GTK 1.2 we set the simple border size to 1 */
3090 #endif // __WXUNIVERSAL__
3094 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3096 GtkRequisition vscroll_req
;
3097 vscroll_req
.width
= 2;
3098 vscroll_req
.height
= 2;
3099 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3100 (scroll_window
->vscrollbar
, &vscroll_req
);
3102 GtkRequisition hscroll_req
;
3103 hscroll_req
.width
= 2;
3104 hscroll_req
.height
= 2;
3105 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3106 (scroll_window
->hscrollbar
, &hscroll_req
);
3108 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3110 if (scroll_window
->vscrollbar_visible
)
3112 dw
+= vscroll_req
.width
;
3113 dw
+= scroll_class
->scrollbar_spacing
;
3116 if (scroll_window
->hscrollbar_visible
)
3118 dh
+= hscroll_req
.height
;
3119 dh
+= scroll_class
->scrollbar_spacing
;
3123 if (width
) (*width
) = m_width
- dw
;
3124 if (height
) (*height
) = m_height
- dh
;
3128 printf( "GetClientSize, name %s ", GetName().c_str() );
3129 if (width) printf( " width = %d", (*width) );
3130 if (height) printf( " height = %d", (*height) );
3135 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3137 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3141 if (m_parent
&& m_parent
->m_wxwindow
)
3143 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3144 dx
= pizza
->xoffset
;
3145 dy
= pizza
->yoffset
;
3148 if (x
) (*x
) = m_x
- dx
;
3149 if (y
) (*y
) = m_y
- dy
;
3152 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3154 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3156 if (!m_widget
->window
) return;
3158 GdkWindow
*source
= (GdkWindow
*) NULL
;
3160 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3162 source
= m_widget
->window
;
3166 gdk_window_get_origin( source
, &org_x
, &org_y
);
3170 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3172 org_x
+= m_widget
->allocation
.x
;
3173 org_y
+= m_widget
->allocation
.y
;
3181 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3183 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3185 if (!m_widget
->window
) return;
3187 GdkWindow
*source
= (GdkWindow
*) NULL
;
3189 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3191 source
= m_widget
->window
;
3195 gdk_window_get_origin( source
, &org_x
, &org_y
);
3199 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3201 org_x
+= m_widget
->allocation
.x
;
3202 org_y
+= m_widget
->allocation
.y
;
3210 bool wxWindowGTK::Show( bool show
)
3212 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3214 if (!wxWindowBase::Show(show
))
3221 gtk_widget_show( m_widget
);
3223 gtk_widget_hide( m_widget
);
3225 wxShowEvent
eventShow(GetId(), show
);
3226 eventShow
.SetEventObject(this);
3228 GetEventHandler()->ProcessEvent(eventShow
);
3233 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3235 win
->OnParentEnable(enable
);
3237 // Recurse, so that children have the opportunity to Do The Right Thing
3238 // and reset colours that have been messed up by a parent's (really ancestor's)
3240 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3242 node
= node
->GetNext() )
3244 wxWindow
*child
= node
->GetData();
3245 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3246 wxWindowNotifyEnable(child
, enable
);
3250 bool wxWindowGTK::Enable( bool enable
)
3252 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3254 if (!wxWindowBase::Enable(enable
))
3260 gtk_widget_set_sensitive( m_widget
, enable
);
3262 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3264 wxWindowNotifyEnable(this, enable
);
3269 int wxWindowGTK::GetCharHeight() const
3271 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3273 wxFont font
= GetFont();
3274 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3276 PangoContext
*context
= NULL
;
3278 context
= gtk_widget_get_pango_context( m_widget
);
3283 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3284 PangoLayout
*layout
= pango_layout_new(context
);
3285 pango_layout_set_font_description(layout
, desc
);
3286 pango_layout_set_text(layout
, "H", 1);
3287 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3289 PangoRectangle rect
;
3290 pango_layout_line_get_extents(line
, NULL
, &rect
);
3292 g_object_unref( G_OBJECT( layout
) );
3294 return (int) PANGO_PIXELS(rect
.height
);
3297 int wxWindowGTK::GetCharWidth() const
3299 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3301 wxFont font
= GetFont();
3302 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3304 PangoContext
*context
= NULL
;
3306 context
= gtk_widget_get_pango_context( m_widget
);
3311 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3312 PangoLayout
*layout
= pango_layout_new(context
);
3313 pango_layout_set_font_description(layout
, desc
);
3314 pango_layout_set_text(layout
, "g", 1);
3315 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3317 PangoRectangle rect
;
3318 pango_layout_line_get_extents(line
, NULL
, &rect
);
3320 g_object_unref( G_OBJECT( layout
) );
3322 return (int) PANGO_PIXELS(rect
.width
);
3325 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3329 int *externalLeading
,
3330 const wxFont
*theFont
) const
3332 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3334 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3343 PangoContext
*context
= NULL
;
3345 context
= gtk_widget_get_pango_context( m_widget
);
3354 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3355 PangoLayout
*layout
= pango_layout_new(context
);
3356 pango_layout_set_font_description(layout
, desc
);
3359 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3360 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3362 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3363 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3364 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3368 PangoRectangle rect
;
3369 pango_layout_get_extents(layout
, NULL
, &rect
);
3371 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3372 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3375 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3376 int baseline
= pango_layout_iter_get_baseline(iter
);
3377 pango_layout_iter_free(iter
);
3378 *descent
= *y
- PANGO_PIXELS(baseline
);
3380 if (externalLeading
) (*externalLeading
) = 0; // ??
3382 g_object_unref( G_OBJECT( layout
) );
3385 void wxWindowGTK::SetFocus()
3387 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3390 // don't do anything if we already have focus
3396 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3398 gtk_widget_grab_focus (m_wxwindow
);
3403 if (GTK_IS_CONTAINER(m_widget
))
3405 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3408 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3411 if (!GTK_WIDGET_REALIZED(m_widget
))
3413 // we can't set the focus to the widget now so we remember that
3414 // it should be focused and will do it later, during the idle
3415 // time, as soon as we can
3416 wxLogTrace(TRACE_FOCUS
,
3417 _T("Delaying setting focus to %s(%s)"),
3418 GetClassInfo()->GetClassName(), GetLabel().c_str());
3420 g_delayedFocus
= this;
3424 wxLogTrace(TRACE_FOCUS
,
3425 _T("Setting focus to %s(%s)"),
3426 GetClassInfo()->GetClassName(), GetLabel().c_str());
3428 gtk_widget_grab_focus (m_widget
);
3433 wxLogTrace(TRACE_FOCUS
,
3434 _T("Can't set focus to %s(%s)"),
3435 GetClassInfo()->GetClassName(), GetLabel().c_str());
3440 bool wxWindowGTK::AcceptsFocus() const
3442 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3445 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3447 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3449 wxWindowGTK
*oldParent
= m_parent
,
3450 *newParent
= (wxWindowGTK
*)newParentBase
;
3452 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3454 if ( !wxWindowBase::Reparent(newParent
) )
3457 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3459 /* prevent GTK from deleting the widget arbitrarily */
3460 gtk_widget_ref( m_widget
);
3464 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3467 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3471 /* insert GTK representation */
3472 (*(newParent
->m_insertCallback
))(newParent
, this);
3475 /* reverse: prevent GTK from deleting the widget arbitrarily */
3476 gtk_widget_unref( m_widget
);
3481 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3483 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3485 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3487 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3492 /* insert GTK representation */
3493 (*m_insertCallback
)(this, child
);
3496 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3498 wxWindowBase::AddChild(child
);
3499 m_dirtyTabOrder
= true;
3501 wxapp_install_idle_handler();
3504 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3506 wxWindowBase::RemoveChild(child
);
3507 m_dirtyTabOrder
= true;
3509 wxapp_install_idle_handler();
3512 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3514 wxWindowBase::DoMoveInTabOrder(win
, move
);
3515 m_dirtyTabOrder
= true;
3517 wxapp_install_idle_handler();
3520 void wxWindowGTK::RealizeTabOrder()
3524 if (m_children
.size() > 0)
3526 GList
*chain
= NULL
;
3528 for (wxWindowList::const_iterator i
= m_children
.begin();
3529 i
!= m_children
.end(); ++i
)
3531 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3534 chain
= g_list_reverse(chain
);
3536 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3541 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3545 m_dirtyTabOrder
= false;
3548 void wxWindowGTK::Raise()
3550 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3552 if (m_wxwindow
&& m_wxwindow
->window
)
3554 gdk_window_raise( m_wxwindow
->window
);
3556 else if (m_widget
->window
)
3558 gdk_window_raise( m_widget
->window
);
3562 void wxWindowGTK::Lower()
3564 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3566 if (m_wxwindow
&& m_wxwindow
->window
)
3568 gdk_window_lower( m_wxwindow
->window
);
3570 else if (m_widget
->window
)
3572 gdk_window_lower( m_widget
->window
);
3576 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3578 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3580 if (cursor
== m_cursor
)
3584 wxapp_install_idle_handler();
3586 if (cursor
== wxNullCursor
)
3587 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3589 return wxWindowBase::SetCursor( cursor
);
3592 void wxWindowGTK::WarpPointer( int x
, int y
)
3594 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3596 // We provide this function ourselves as it is
3597 // missing in GDK (top of this file).
3599 GdkWindow
*window
= (GdkWindow
*) NULL
;
3601 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3603 window
= GetConnectWidget()->window
;
3606 gdk_window_warp_pointer( window
, x
, y
);
3610 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3614 if (!m_widget
->window
)
3619 GdkRectangle gdk_rect
,
3623 gdk_rect
.x
= rect
->x
;
3624 gdk_rect
.y
= rect
->y
;
3625 gdk_rect
.width
= rect
->width
;
3626 gdk_rect
.height
= rect
->height
;
3629 else // invalidate everything
3634 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3638 void wxWindowGTK::Update()
3642 // when we call Update() we really want to update the window immediately on
3643 // screen, even if it means flushing the entire queue and hence slowing down
3644 // everything -- but it should still be done, it's just that Update() should
3645 // be called very rarely
3649 void wxWindowGTK::GtkUpdate()
3651 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3652 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3654 // for consistency with other platforms (and also because it's convenient
3655 // to be able to update an entire TLW by calling Update() only once), we
3656 // should also update all our children here
3657 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3659 node
= node
->GetNext() )
3661 node
->GetData()->GtkUpdate();
3665 void wxWindowGTK::GtkSendPaintEvents()
3669 m_updateRegion
.Clear();
3673 // Clip to paint region in wxClientDC
3674 m_clipPaintRegion
= true;
3676 // widget to draw on
3677 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3679 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3681 // find ancestor from which to steal background
3682 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3684 parent
= (wxWindow
*)this;
3686 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3688 wxRegionIterator
upd( m_updateRegion
);
3692 rect
.x
= upd
.GetX();
3693 rect
.y
= upd
.GetY();
3694 rect
.width
= upd
.GetWidth();
3695 rect
.height
= upd
.GetHeight();
3697 gtk_paint_flat_box( parent
->m_widget
->style
,
3699 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3713 wxWindowDC
dc( (wxWindow
*)this );
3714 dc
.SetClippingRegion( m_updateRegion
);
3716 wxEraseEvent
erase_event( GetId(), &dc
);
3717 erase_event
.SetEventObject( this );
3719 GetEventHandler()->ProcessEvent(erase_event
);
3722 wxNcPaintEvent
nc_paint_event( GetId() );
3723 nc_paint_event
.SetEventObject( this );
3724 GetEventHandler()->ProcessEvent( nc_paint_event
);
3726 wxPaintEvent
paint_event( GetId() );
3727 paint_event
.SetEventObject( this );
3728 GetEventHandler()->ProcessEvent( paint_event
);
3730 m_clipPaintRegion
= false;
3732 m_updateRegion
.Clear();
3735 void wxWindowGTK::ClearBackground()
3737 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3741 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3743 wxWindowBase::DoSetToolTip(tip
);
3746 m_tooltip
->Apply( (wxWindow
*)this );
3749 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3751 wxString
tmp( tip
);
3752 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3754 #endif // wxUSE_TOOLTIPS
3756 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3758 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3760 if (!wxWindowBase::SetBackgroundColour(colour
))
3765 // We need the pixel value e.g. for background clearing.
3766 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3769 // apply style change (forceStyle=true so that new style is applied
3770 // even if the bg colour changed from valid to wxNullColour)
3771 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3772 ApplyWidgetStyle(true);
3777 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3779 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3781 if (!wxWindowBase::SetForegroundColour(colour
))
3788 // We need the pixel value e.g. for background clearing.
3789 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3792 // apply style change (forceStyle=true so that new style is applied
3793 // even if the bg colour changed from valid to wxNullColour):
3794 ApplyWidgetStyle(true);
3799 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3801 return gtk_widget_get_pango_context( m_widget
);
3804 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3806 // do we need to apply any changes at all?
3809 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3814 GtkRcStyle
*style
= gtk_rc_style_new();
3819 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3822 if ( m_foregroundColour
.Ok() )
3824 GdkColor
*fg
= m_foregroundColour
.GetColor();
3826 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3827 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3829 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3830 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3832 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3833 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3836 if ( m_backgroundColour
.Ok() )
3838 GdkColor
*bg
= m_backgroundColour
.GetColor();
3840 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3841 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3842 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3843 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3845 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3846 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3847 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3848 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3850 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3851 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3852 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3853 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3855 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3856 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3857 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3858 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3864 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
3866 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
3869 DoApplyWidgetStyle(style
);
3870 gtk_rc_style_unref(style
);
3873 // Style change may affect GTK+'s size calculation:
3874 InvalidateBestSize();
3877 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
3880 gtk_widget_modify_style(m_wxwindow
, style
);
3882 gtk_widget_modify_style(m_widget
, style
);
3885 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
3887 wxWindowBase::SetBackgroundStyle(style
);
3889 if (style
== wxBG_STYLE_CUSTOM
)
3891 GdkWindow
*window
= (GdkWindow
*) NULL
;
3893 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3895 window
= GetConnectWidget()->window
;
3899 // Make sure GDK/X11 doesn't refresh the window
3901 gdk_window_set_back_pixmap( window
, None
, False
);
3903 Display
* display
= GDK_WINDOW_DISPLAY(window
);
3906 m_needsStyleChange
= false;
3909 // Do in OnIdle, because the window is not yet available
3910 m_needsStyleChange
= true;
3912 // Don't apply widget style, or we get a grey background
3916 // apply style change (forceStyle=true so that new style is applied
3917 // even if the bg colour changed from valid to wxNullColour):
3918 ApplyWidgetStyle(true);
3923 #if wxUSE_DRAG_AND_DROP
3925 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3927 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3929 GtkWidget
*dnd_widget
= GetConnectWidget();
3931 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3933 if (m_dropTarget
) delete m_dropTarget
;
3934 m_dropTarget
= dropTarget
;
3936 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3939 #endif // wxUSE_DRAG_AND_DROP
3941 GtkWidget
* wxWindowGTK::GetConnectWidget()
3943 GtkWidget
*connect_widget
= m_widget
;
3944 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3946 return connect_widget
;
3949 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3952 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3954 return (window
== m_widget
->window
);
3957 bool wxWindowGTK::SetFont( const wxFont
&font
)
3959 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3961 if (!wxWindowBase::SetFont(font
))
3964 // apply style change (forceStyle=true so that new style is applied
3965 // even if the font changed from valid to wxNullFont):
3966 ApplyWidgetStyle(true);
3971 void wxWindowGTK::DoCaptureMouse()
3973 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3975 GdkWindow
*window
= (GdkWindow
*) NULL
;
3977 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3979 window
= GetConnectWidget()->window
;
3981 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3983 wxCursor
* cursor
= & m_cursor
;
3985 cursor
= wxSTANDARD_CURSOR
;
3987 gdk_pointer_grab( window
, FALSE
,
3989 (GDK_BUTTON_PRESS_MASK
|
3990 GDK_BUTTON_RELEASE_MASK
|
3991 GDK_POINTER_MOTION_HINT_MASK
|
3992 GDK_POINTER_MOTION_MASK
),
3994 cursor
->GetCursor(),
3995 (guint32
)GDK_CURRENT_TIME
);
3996 g_captureWindow
= this;
3997 g_captureWindowHasMouse
= true;
4000 void wxWindowGTK::DoReleaseMouse()
4002 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4004 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4006 g_captureWindow
= (wxWindowGTK
*) NULL
;
4008 GdkWindow
*window
= (GdkWindow
*) NULL
;
4010 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4012 window
= GetConnectWidget()->window
;
4017 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4021 wxWindow
*wxWindowBase::GetCapture()
4023 return (wxWindow
*)g_captureWindow
;
4026 bool wxWindowGTK::IsRetained() const
4031 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4032 int range
, bool refresh
)
4034 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4036 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4038 m_hasScrolling
= true;
4040 if (orient
== wxHORIZONTAL
)
4042 float fpos
= (float)pos
;
4043 float frange
= (float)range
;
4044 float fthumb
= (float)thumbVisible
;
4045 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4046 if (fpos
< 0.0) fpos
= 0.0;
4048 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4049 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4051 SetScrollPos( orient
, pos
, refresh
);
4055 m_oldHorizontalPos
= fpos
;
4057 m_hAdjust
->lower
= 0.0;
4058 m_hAdjust
->upper
= frange
;
4059 m_hAdjust
->value
= fpos
;
4060 m_hAdjust
->step_increment
= 1.0;
4061 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4062 m_hAdjust
->page_size
= fthumb
;
4066 float fpos
= (float)pos
;
4067 float frange
= (float)range
;
4068 float fthumb
= (float)thumbVisible
;
4069 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4070 if (fpos
< 0.0) fpos
= 0.0;
4072 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4073 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4075 SetScrollPos( orient
, pos
, refresh
);
4079 m_oldVerticalPos
= fpos
;
4081 m_vAdjust
->lower
= 0.0;
4082 m_vAdjust
->upper
= frange
;
4083 m_vAdjust
->value
= fpos
;
4084 m_vAdjust
->step_increment
= 1.0;
4085 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4086 m_vAdjust
->page_size
= fthumb
;
4089 if (orient
== wxHORIZONTAL
)
4090 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4092 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4095 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4097 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4098 GtkSignalFunc fn
= orient
== wxHORIZONTAL
4099 ? (GtkSignalFunc
)gtk_window_hscroll_callback
4100 : (GtkSignalFunc
)gtk_window_vscroll_callback
;
4102 gtk_signal_disconnect_by_func(GTK_OBJECT(adj
), fn
, (gpointer
)this);
4103 gtk_signal_emit_by_name(GTK_OBJECT(adj
), "value_changed");
4104 gtk_signal_connect(GTK_OBJECT(adj
), "value_changed", fn
, (gpointer
)this);
4107 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4109 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4110 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4112 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4114 float fpos
= (float)pos
;
4115 if (fpos
> adj
->upper
- adj
->page_size
)
4116 fpos
= adj
->upper
- adj
->page_size
;
4119 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4121 if (fabs(fpos
-adj
->value
) < 0.2)
4125 if ( m_wxwindow
->window
)
4130 int wxWindowGTK::GetScrollThumb( int orient
) const
4132 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4134 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4136 if (orient
== wxHORIZONTAL
)
4137 return (int)(m_hAdjust
->page_size
+0.5);
4139 return (int)(m_vAdjust
->page_size
+0.5);
4142 int wxWindowGTK::GetScrollPos( int orient
) const
4144 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4146 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4148 if (orient
== wxHORIZONTAL
)
4149 return (int)(m_hAdjust
->value
+0.5);
4151 return (int)(m_vAdjust
->value
+0.5);
4154 int wxWindowGTK::GetScrollRange( int orient
) const
4156 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4158 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4160 if (orient
== wxHORIZONTAL
)
4161 return (int)(m_hAdjust
->upper
+0.5);
4163 return (int)(m_vAdjust
->upper
+0.5);
4166 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4168 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4170 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4172 // No scrolling requested.
4173 if ((dx
== 0) && (dy
== 0)) return;
4175 m_clipPaintRegion
= true;
4177 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4179 m_clipPaintRegion
= false;
4182 void wxWindowGTK::SetWindowStyleFlag( long style
)
4184 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4185 wxWindowBase::SetWindowStyleFlag(style
);
4188 // Find the wxWindow at the current mouse position, also returning the mouse
4190 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4192 pt
= wxGetMousePosition();
4193 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4197 // Get the current mouse position.
4198 wxPoint
wxGetMousePosition()
4200 /* This crashes when used within wxHelpContext,
4201 so we have to use the X-specific implementation below.
4203 GdkModifierType *mask;
4204 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4206 return wxPoint(x, y);
4210 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4212 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4213 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4214 Window rootReturn
, childReturn
;
4215 int rootX
, rootY
, winX
, winY
;
4216 unsigned int maskReturn
;
4218 XQueryPointer (display
,
4222 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4223 return wxPoint(rootX
, rootY
);
4227 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4228 void wxAddGrab(wxWindow
* window
)
4230 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4233 void wxRemoveGrab(wxWindow
* window
)
4235 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4238 // ----------------------------------------------------------------------------
4240 // ----------------------------------------------------------------------------
4242 class wxWinModule
: public wxModule
4249 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4252 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4254 bool wxWinModule::OnInit()
4256 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4257 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4262 void wxWinModule::OnExit()
4265 gdk_gc_unref( g_eraseGC
);