1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
18 #include "wx/dcclient.h"
21 #include "wx/layout.h"
23 #include "wx/dialog.h"
24 #include "wx/msgdlg.h"
25 #include "wx/module.h"
26 #include "wx/combobox.h"
28 #if wxUSE_DRAG_AND_DROP
33 #include "wx/tooltip.h"
41 #include "wx/textctrl.h"
45 #include "wx/statusbr.h"
47 #include "wx/settings.h"
49 #include "wx/fontutil.h"
50 #include "wx/stattext.h"
53 #include "wx/thread.h"
59 // FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
60 #include <gtk/gtkversion.h>
61 #if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
62 #undef GTK_DISABLE_DEPRECATED
65 #include "wx/gtk/private.h"
66 #include <gdk/gdkprivate.h>
67 #include <gdk/gdkkeysyms.h>
71 #include <gtk/gtkprivate.h>
73 #include "wx/gtk/win_gtk.h"
75 #include <pango/pangox.h>
81 extern GtkContainerClass
*pizza_parent_class
;
83 //-----------------------------------------------------------------------------
84 // documentation on internals
85 //-----------------------------------------------------------------------------
88 I have been asked several times about writing some documentation about
89 the GTK port of wxWidgets, especially its internal structures. Obviously,
90 you cannot understand wxGTK without knowing a little about the GTK, but
91 some more information about what the wxWindow, which is the base class
92 for all other window classes, does seems required as well.
96 What does wxWindow do? It contains the common interface for the following
97 jobs of its descendants:
99 1) Define the rudimentary behaviour common to all window classes, such as
100 resizing, intercepting user input (so as to make it possible to use these
101 events for special purposes in a derived class), window names etc.
103 2) Provide the possibility to contain and manage children, if the derived
104 class is allowed to contain children, which holds true for those window
105 classes which do not display a native GTK widget. To name them, these
106 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
107 work classes are a special case and are handled a bit differently from
108 the rest. The same holds true for the wxNotebook class.
110 3) Provide the possibility to draw into a client area of a window. This,
111 too, only holds true for classes that do not display a native GTK widget
114 4) Provide the entire mechanism for scrolling widgets. This actual inter-
115 face for this is usually in wxScrolledWindow, but the GTK implementation
118 5) A multitude of helper or extra methods for special purposes, such as
119 Drag'n'Drop, managing validators etc.
121 6) Display a border (sunken, raised, simple or none).
123 Normally one might expect, that one wxWidgets window would always correspond
124 to one GTK widget. Under GTK, there is no such allround widget that has all
125 the functionality. Moreover, the GTK defines a client area as a different
126 widget from the actual widget you are handling. Last but not least some
127 special classes (e.g. wxFrame) handle different categories of widgets and
128 still have the possibility to draw something in the client area.
129 It was therefore required to write a special purpose GTK widget, that would
130 represent a client area in the sense of wxWidgets capable to do the jobs
131 2), 3) and 4). I have written this class and it resides in win_gtk.c of
134 All windows must have a widget, with which they interact with other under-
135 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
136 the wxWindow class has a member variable called m_widget which holds a
137 pointer to this widget. When the window class represents a GTK native widget,
138 this is (in most cases) the only GTK widget the class manages. E.g. the
139 wxStaticText class handles only a GtkLabel widget a pointer to which you
140 can find in m_widget (defined in wxWindow)
142 When the class has a client area for drawing into and for containing children
143 it has to handle the client area widget (of the type GtkPizza, defined in
144 win_gtk.c), but there could be any number of widgets, handled by a class
145 The common rule for all windows is only, that the widget that interacts with
146 the rest of GTK must be referenced in m_widget and all other widgets must be
147 children of this widget on the GTK level. The top-most widget, which also
148 represents the client area, must be in the m_wxwindow field and must be of
151 As I said, the window classes that display a GTK native widget only have
152 one widget, so in the case of e.g. the wxButton class m_widget holds a
153 pointer to a GtkButton widget. But windows with client areas (for drawing
154 and children) have a m_widget field that is a pointer to a GtkScrolled-
155 Window and a m_wxwindow field that is pointer to a GtkPizza and this
156 one is (in the GTK sense) a child of the GtkScrolledWindow.
158 If the m_wxwindow field is set, then all input to this widget is inter-
159 cepted and sent to the wxWidgets class. If not, all input to the widget
160 that gets pointed to by m_widget gets intercepted and sent to the class.
164 The design of scrolling in wxWidgets is markedly different from that offered
165 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
166 clicking on a scrollbar belonging to scrolled window will inevitably move
167 the window. In wxWidgets, the scrollbar will only emit an event, send this
168 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
169 which actually moves the window and its subchildren. Note that GtkPizza
170 memorizes how much it has been scrolled but that wxWidgets forgets this
171 so that the two coordinates systems have to be kept in synch. This is done
172 in various places using the pizza->xoffset and pizza->yoffset values.
176 Singularily the most broken code in GTK is the code that is supposed to
177 inform subwindows (child windows) about new positions. Very often, duplicate
178 events are sent without changes in size or position, equally often no
179 events are sent at all (All this is due to a bug in the GtkContainer code
180 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
181 GTK's own system and it simply waits for size events for toplevel windows
182 and then iterates down the respective size events to all window. This has
183 the disadvantage that windows might get size events before the GTK widget
184 actually has the reported size. This doesn't normally pose any problem, but
185 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
186 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
187 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
188 window that is used for OpenGL output really has that size (as reported by
193 If someone at some point of time feels the immense desire to have a look at,
194 change or attempt to optimise the Refresh() logic, this person will need an
195 intimate understanding of what "draw" and "expose" events are and what
196 they are used for, in particular when used in connection with GTK's
197 own windowless widgets. Beware.
201 Cursors, too, have been a constant source of pleasure. The main difficulty
202 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
203 for the parent. To prevent this from doing too much harm, I use idle time
204 to set the cursor over and over again, starting from the toplevel windows
205 and ending with the youngest generation (speaking of parent and child windows).
206 Also don't forget that cursors (like much else) are connected to GdkWindows,
207 not GtkWidgets and that the "window" field of a GtkWidget might very well
208 point to the GdkWindow of the parent widget (-> "window-less widget") and
209 that the two obviously have very different meanings.
213 //-----------------------------------------------------------------------------
215 //-----------------------------------------------------------------------------
217 extern wxList wxPendingDelete
;
218 extern bool g_blockEventsOnDrag
;
219 extern bool g_blockEventsOnScroll
;
220 extern wxCursor g_globalCursor
;
222 static GdkGC
*g_eraseGC
= NULL
;
224 // mouse capture state: the window which has it and if the mouse is currently
226 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
227 static bool g_captureWindowHasMouse
= false;
229 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
231 // the last window which had the focus - this is normally never NULL (except
232 // if we never had focus at all) as even when g_focusWindow is NULL it still
233 // keeps its previous value
234 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
236 // If a window get the focus set but has not been realized
237 // yet, defer setting the focus to idle time.
238 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
240 extern bool g_mainThreadLocked
;
242 //-----------------------------------------------------------------------------
244 //-----------------------------------------------------------------------------
249 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
251 # define DEBUG_MAIN_THREAD
254 #define DEBUG_MAIN_THREAD
257 // the trace mask used for the focus debugging messages
258 #define TRACE_FOCUS _T("focus")
260 //-----------------------------------------------------------------------------
261 // missing gdk functions
262 //-----------------------------------------------------------------------------
265 gdk_window_warp_pointer (GdkWindow
*window
,
270 window
= GDK_ROOT_PARENT();
272 if (!GDK_WINDOW_DESTROYED(window
))
274 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
275 None
, /* not source window -> move from anywhere */
276 GDK_WINDOW_XID(window
), /* dest window */
277 0, 0, 0, 0, /* not source window -> move from anywhere */
282 //-----------------------------------------------------------------------------
284 //-----------------------------------------------------------------------------
286 extern void wxapp_install_idle_handler();
287 extern bool g_isIdle
;
289 //-----------------------------------------------------------------------------
290 // local code (see below)
291 //-----------------------------------------------------------------------------
293 // returns the child of win which currently has focus or NULL if not found
295 // Note: can't be static, needed by textctrl.cpp.
296 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
298 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
300 return (wxWindow
*)NULL
;
302 if ( winFocus
== win
)
303 return (wxWindow
*)win
;
305 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
307 node
= node
->GetNext() )
309 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
314 return (wxWindow
*)NULL
;
317 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
319 // wxUniversal widgets draw the borders and scrollbars themselves
320 #ifndef __WXUNIVERSAL__
327 if (win
->m_hasScrolling
)
329 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
331 GtkRequisition vscroll_req
;
332 vscroll_req
.width
= 2;
333 vscroll_req
.height
= 2;
334 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
335 (scroll_window
->vscrollbar
, &vscroll_req
);
337 GtkRequisition hscroll_req
;
338 hscroll_req
.width
= 2;
339 hscroll_req
.height
= 2;
340 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
341 (scroll_window
->hscrollbar
, &hscroll_req
);
343 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
345 if (scroll_window
->vscrollbar_visible
)
347 dw
+= vscroll_req
.width
;
348 dw
+= scroll_class
->scrollbar_spacing
;
351 if (scroll_window
->hscrollbar_visible
)
353 dh
+= hscroll_req
.height
;
354 dh
+= scroll_class
->scrollbar_spacing
;
360 if (GTK_WIDGET_NO_WINDOW (widget
))
362 dx
+= widget
->allocation
.x
;
363 dy
+= widget
->allocation
.y
;
366 if (win
->HasFlag(wxRAISED_BORDER
))
368 gtk_paint_shadow (widget
->style
,
372 NULL
, NULL
, NULL
, // FIXME: No clipping?
374 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
378 if (win
->HasFlag(wxSUNKEN_BORDER
))
380 gtk_paint_shadow (widget
->style
,
384 NULL
, NULL
, NULL
, // FIXME: No clipping?
386 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
390 if (win
->HasFlag(wxSIMPLE_BORDER
))
393 gc
= gdk_gc_new( widget
->window
);
394 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
395 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
397 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
401 #endif // __WXUNIVERSAL__
404 //-----------------------------------------------------------------------------
405 // "expose_event" of m_widget
406 //-----------------------------------------------------------------------------
410 gtk_window_own_expose_callback( GtkWidget
*widget
,
411 GdkEventExpose
*gdk_event
,
414 if (gdk_event
->count
> 0) return FALSE
;
416 draw_frame( widget
, win
);
418 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
424 //-----------------------------------------------------------------------------
425 // "size_request" of m_widget
426 //-----------------------------------------------------------------------------
428 // make it extern because wxStaticText needs to disconnect this one
430 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
431 GtkRequisition
*requisition
,
435 win
->GetSize( &w
, &h
);
441 requisition
->height
= h
;
442 requisition
->width
= w
;
448 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
449 GtkRequisition
*requisition
,
452 // This callback is actually hooked into the text entry
453 // of the combo box, not the GtkHBox.
456 win
->GetSize( &w
, &h
);
462 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
464 GtkRequisition entry_req
;
466 entry_req
.height
= 2;
467 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
468 (gcombo
->button
, &entry_req
);
470 requisition
->width
= w
- entry_req
.width
;
471 requisition
->height
= entry_req
.height
;
475 //-----------------------------------------------------------------------------
476 // "expose_event" of m_wxwindow
477 //-----------------------------------------------------------------------------
481 gtk_window_expose_callback( GtkWidget
*widget
,
482 GdkEventExpose
*gdk_event
,
488 wxapp_install_idle_handler();
490 // This callback gets called in drawing-idle time under
491 // GTK 2.0, so we don't need to defer anything to idle
494 GtkPizza
*pizza
= GTK_PIZZA( widget
);
495 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
500 wxPrintf( wxT("OnExpose from ") );
501 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
502 wxPrintf( win
->GetClassInfo()->GetClassName() );
503 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
504 (int)gdk_event
->area
.y
,
505 (int)gdk_event
->area
.width
,
506 (int)gdk_event
->area
.height
);
511 win
->m_wxwindow
->style
,
515 (GdkRectangle
*) NULL
,
517 (char *)"button", // const_cast
522 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
524 win
->GtkSendPaintEvents();
527 // Let parent window draw window-less widgets
528 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
534 //-----------------------------------------------------------------------------
535 // "key_press_event" from any window
536 //-----------------------------------------------------------------------------
538 // set WXTRACE to this to see the key event codes on the console
539 #define TRACE_KEYS _T("keyevent")
541 // translates an X key symbol to WXK_XXX value
543 // if isChar is true it means that the value returned will be used for EVT_CHAR
544 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
545 // for example, while if it is false it means that the value is going to be
546 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
548 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
554 // Shift, Control and Alt don't generate the CHAR events at all
557 key_code
= isChar
? 0 : WXK_SHIFT
;
561 key_code
= isChar
? 0 : WXK_CONTROL
;
569 key_code
= isChar
? 0 : WXK_ALT
;
572 // neither do the toggle modifies
573 case GDK_Scroll_Lock
:
574 key_code
= isChar
? 0 : WXK_SCROLL
;
578 key_code
= isChar
? 0 : WXK_CAPITAL
;
582 key_code
= isChar
? 0 : WXK_NUMLOCK
;
586 // various other special keys
599 case GDK_ISO_Left_Tab
:
606 key_code
= WXK_RETURN
;
610 key_code
= WXK_CLEAR
;
614 key_code
= WXK_PAUSE
;
618 key_code
= WXK_SELECT
;
622 key_code
= WXK_PRINT
;
626 key_code
= WXK_EXECUTE
;
630 key_code
= WXK_ESCAPE
;
633 // cursor and other extended keyboard keys
635 key_code
= WXK_DELETE
;
651 key_code
= WXK_RIGHT
;
658 case GDK_Prior
: // == GDK_Page_Up
659 key_code
= WXK_PRIOR
;
662 case GDK_Next
: // == GDK_Page_Down
675 key_code
= WXK_INSERT
;
690 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
694 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
698 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
702 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
706 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
710 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
714 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
718 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
722 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
726 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
730 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
734 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
738 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
741 case GDK_KP_Prior
: // == GDK_KP_Page_Up
742 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
745 case GDK_KP_Next
: // == GDK_KP_Page_Down
746 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
750 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
754 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
758 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
762 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
766 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
769 case GDK_KP_Multiply
:
770 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
774 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
777 case GDK_KP_Separator
:
778 // FIXME: what is this?
779 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
782 case GDK_KP_Subtract
:
783 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
787 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
791 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
808 key_code
= WXK_F1
+ keysym
- GDK_F1
;
818 static inline bool wxIsAsciiKeysym(KeySym ks
)
823 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
825 GdkEventKey
*gdk_event
)
829 GdkModifierType state
;
830 if (gdk_event
->window
)
831 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
833 event
.SetTimestamp( gdk_event
->time
);
834 event
.SetId(win
->GetId());
835 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
836 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
837 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
838 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
839 event
.m_scanCode
= gdk_event
->keyval
;
840 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
841 event
.m_rawFlags
= 0;
843 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
844 if ( gdk_event
->type
== GDK_KEY_PRESS
|| gdk_event
->type
== GDK_KEY_RELEASE
)
846 event
.m_uniChar
= toupper(event
.m_uniChar
);
849 wxGetMousePosition( &x
, &y
);
850 win
->ScreenToClient( &x
, &y
);
853 event
.SetEventObject( win
);
858 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
860 GdkEventKey
*gdk_event
)
862 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
863 // but only event->keyval which is quite useless to us, so remember
864 // the last character from GDK_KEY_PRESS and reuse it as last resort
866 // NB: should be MT-safe as we're always called from the main thread only
871 } s_lastKeyPress
= { 0, 0 };
873 KeySym keysym
= gdk_event
->keyval
;
875 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
876 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
880 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
884 // do we have the translation or is it a plain ASCII character?
885 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
887 // we should use keysym if it is ASCII as X does some translations
888 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
889 // which we don't want here (but which we do use for OnChar())
890 if ( !wxIsAsciiKeysym(keysym
) )
892 keysym
= (KeySym
)gdk_event
->string
[0];
895 // we want to always get the same key code when the same key is
896 // pressed regardless of the state of the modifiers, i.e. on a
897 // standard US keyboard pressing '5' or '%' ('5' key with
898 // Shift) should result in the same key code in OnKeyDown():
899 // '5' (although OnChar() will get either '5' or '%').
901 // to do it we first translate keysym to keycode (== scan code)
902 // and then back but always using the lower register
903 Display
*dpy
= (Display
*)wxGetDisplay();
904 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
906 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
908 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
910 // use the normalized, i.e. lower register, keysym if we've
912 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
914 // as explained above, we want to have lower register key codes
915 // normally but for the letter keys we want to have the upper ones
917 // NB: don't use XConvertCase() here, we want to do it for letters
919 key_code
= toupper(key_code
);
921 else // non ASCII key, what to do?
923 // by default, ignore it
926 // but if we have cached information from the last KEY_PRESS
927 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
930 if ( keysym
== s_lastKeyPress
.keysym
)
932 key_code
= s_lastKeyPress
.keycode
;
937 if ( gdk_event
->type
== GDK_KEY_PRESS
)
939 // remember it to be reused for KEY_UP event later
940 s_lastKeyPress
.keysym
= keysym
;
941 s_lastKeyPress
.keycode
= key_code
;
945 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
947 // sending unknown key events doesn't really make sense
951 // now fill all the other fields
952 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
954 event
.m_keyCode
= key_code
;
962 GtkIMContext
*context
;
963 GdkEventKey
*lastKeyEvent
;
967 context
= gtk_im_multicontext_new();
972 g_object_unref(context
);
978 gtk_window_key_press_callback( GtkWidget
*widget
,
979 GdkEventKey
*gdk_event
,
985 wxapp_install_idle_handler();
989 if (g_blockEventsOnDrag
)
993 wxKeyEvent
event( wxEVT_KEY_DOWN
);
995 bool return_after_IM
= false;
997 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
999 // Emit KEY_DOWN event
1000 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1004 // Return after IM processing as we cannot do
1005 // anything with it anyhow.
1006 return_after_IM
= true;
1009 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1010 // When we get a key_press event here, it could be originate
1011 // from the current widget or its child widgets. However, only the widget
1012 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1013 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1014 // originated from its child widgets and shouldn't be passed to IM context.
1015 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1016 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1017 // widgets has both IM context and input focus, the event should be filtered
1018 // by gtk_im_context_filter_keypress().
1019 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1020 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1022 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1023 // docs, if IM filter returns true, no further processing should be done.
1024 // we should send the key_down event anyway.
1025 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1026 win
->m_imData
->lastKeyEvent
= NULL
;
1027 if (intercepted_by_IM
)
1029 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1034 if (return_after_IM
)
1040 wxWindowGTK
*ancestor
= win
;
1043 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1046 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1047 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1050 if (ancestor
->IsTopLevel())
1052 ancestor
= ancestor
->GetParent();
1055 #endif // wxUSE_ACCEL
1057 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1058 // will only be sent if it is not in an accelerator table.
1062 KeySym keysym
= gdk_event
->keyval
;
1063 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1064 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1067 if ( wxIsAsciiKeysym(keysym
) )
1070 key_code
= (unsigned char)keysym
;
1072 // gdk_event->string is actually deprecated
1073 else if ( gdk_event
->length
== 1 )
1075 key_code
= (unsigned char)gdk_event
->string
[0];
1081 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1083 event
.m_keyCode
= key_code
;
1085 // To conform to the docs we need to translate Ctrl-alpha
1086 // characters to values in the range 1-26.
1087 if (event
.ControlDown() && key_code
>= 'a' && key_code
<= 'z' )
1089 event
.m_keyCode
= key_code
- 'a' + 1;
1091 event
.m_uniChar
= event
.m_keyCode
;
1095 // Implement OnCharHook by checking ancestor top level windows
1096 wxWindow
*parent
= win
;
1097 while (parent
&& !parent
->IsTopLevel())
1098 parent
= parent
->GetParent();
1101 event
.SetEventType( wxEVT_CHAR_HOOK
);
1102 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1107 event
.SetEventType(wxEVT_CHAR
);
1108 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1117 // win is a control: tab can be propagated up
1119 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1120 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1121 // have this style, yet choose not to process this particular TAB in which
1122 // case TAB must still work as a navigational character
1123 // JS: enabling again to make consistent with other platforms
1124 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1125 // navigation behaviour)
1127 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1129 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1131 wxNavigationKeyEvent new_event
;
1132 new_event
.SetEventObject( win
->GetParent() );
1133 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1134 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1135 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1136 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1137 new_event
.SetCurrentFocus( win
);
1138 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1141 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1143 (gdk_event
->keyval
== GDK_Escape
) )
1145 // however only do it if we have a Cancel button in the dialog,
1146 // otherwise the user code may get confused by the events from a
1147 // non-existing button and, worse, a wxButton might get button event
1148 // from another button which is not really expected
1149 wxWindow
*winForCancel
= win
,
1151 while ( winForCancel
)
1153 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1156 // found a cancel button
1160 if ( winForCancel
->IsTopLevel() )
1162 // no need to look further
1166 // maybe our parent has a cancel button?
1167 winForCancel
= winForCancel
->GetParent();
1172 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1173 eventClick
.SetEventObject(btnCancel
);
1174 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1180 g_signal_stop_emission_by_name (widget
, "key_press_event");
1190 gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1194 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1196 // take modifiers, cursor position, timestamp etc. from the last
1197 // key_press_event that was fed into Input Method:
1198 if (window
->m_imData
->lastKeyEvent
)
1200 wxFillOtherKeyEventFields(event
,
1201 window
, window
->m_imData
->lastKeyEvent
);
1205 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1207 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1208 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1209 #endif // wxUSE_UNICODE
1210 if( !(const wxChar
*)data
)
1215 // Implement OnCharHook by checking ancestor top level windows
1216 wxWindow
*parent
= window
;
1217 while (parent
&& !parent
->IsTopLevel())
1218 parent
= parent
->GetParent();
1220 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1223 event
.m_uniChar
= *pstr
;
1224 // Backward compatible for ISO-8859-1
1225 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1226 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1228 event
.m_keyCode
= *pstr
;
1229 #endif // wxUSE_UNICODE
1231 // To conform to the docs we need to translate Ctrl-alpha
1232 // characters to values in the range 1-26.
1233 if (event
.ControlDown() && *pstr
>= 'a' && *pstr
<= 'z' )
1235 event
.m_keyCode
= *pstr
- 'a' + 1;
1237 event
.m_uniChar
= event
.m_keyCode
;
1243 event
.SetEventType( wxEVT_CHAR_HOOK
);
1244 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1249 event
.SetEventType(wxEVT_CHAR
);
1250 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1257 //-----------------------------------------------------------------------------
1258 // "key_release_event" from any window
1259 //-----------------------------------------------------------------------------
1263 gtk_window_key_release_callback( GtkWidget
*widget
,
1264 GdkEventKey
*gdk_event
,
1270 wxapp_install_idle_handler();
1275 if (g_blockEventsOnDrag
)
1278 wxKeyEvent
event( wxEVT_KEY_UP
);
1279 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1281 // unknown key pressed, ignore (the event would be useless anyhow)
1285 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1288 g_signal_stop_emission_by_name (widget
, "key_release_event");
1293 // ============================================================================
1295 // ============================================================================
1297 // ----------------------------------------------------------------------------
1298 // mouse event processing helpers
1299 // ----------------------------------------------------------------------------
1301 // init wxMouseEvent with the info from GdkEventXXX struct
1302 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1303 wxMouseEvent
& event
,
1306 event
.SetTimestamp( gdk_event
->time
);
1307 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1308 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1309 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1310 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1311 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1312 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1313 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1314 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1316 event
.m_linesPerAction
= 3;
1317 event
.m_wheelDelta
= 120;
1318 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1319 event
.m_wheelRotation
= 120;
1320 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1321 event
.m_wheelRotation
= -120;
1324 wxPoint pt
= win
->GetClientAreaOrigin();
1325 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1326 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1328 event
.SetEventObject( win
);
1329 event
.SetId( win
->GetId() );
1330 event
.SetTimestamp( gdk_event
->time
);
1333 static void AdjustEventButtonState(wxMouseEvent
& event
)
1335 // GDK reports the old state of the button for a button press event, but
1336 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1337 // for a LEFT_DOWN event, not FALSE, so we will invert
1338 // left/right/middleDown for the corresponding click events
1340 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1341 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1342 (event
.GetEventType() == wxEVT_LEFT_UP
))
1344 event
.m_leftDown
= !event
.m_leftDown
;
1348 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1349 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1350 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1352 event
.m_middleDown
= !event
.m_middleDown
;
1356 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1357 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1358 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1360 event
.m_rightDown
= !event
.m_rightDown
;
1365 // find the window to send the mouse event too
1367 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1372 if (win
->m_wxwindow
)
1374 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1375 xx
+= pizza
->xoffset
;
1376 yy
+= pizza
->yoffset
;
1379 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1382 wxWindowGTK
*child
= node
->GetData();
1384 node
= node
->GetNext();
1385 if (!child
->IsShown())
1388 if (child
->IsTransparentForMouse())
1390 // wxStaticBox is transparent in the box itself
1391 int xx1
= child
->m_x
;
1392 int yy1
= child
->m_y
;
1393 int xx2
= child
->m_x
+ child
->m_width
;
1394 int yy2
= child
->m_y
+ child
->m_height
;
1397 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1399 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1401 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1403 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1414 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1415 (child
->m_x
<= xx
) &&
1416 (child
->m_y
<= yy
) &&
1417 (child
->m_x
+child
->m_width
>= xx
) &&
1418 (child
->m_y
+child
->m_height
>= yy
))
1431 //-----------------------------------------------------------------------------
1432 // "button_press_event"
1433 //-----------------------------------------------------------------------------
1437 gtk_window_button_press_callback( GtkWidget
*widget
,
1438 GdkEventButton
*gdk_event
,
1444 wxapp_install_idle_handler();
1447 wxPrintf( wxT("1) OnButtonPress from ") );
1448 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1449 wxPrintf( win->GetClassInfo()->GetClassName() );
1450 wxPrintf( wxT(".\n") );
1452 if (!win
->m_hasVMT
) return FALSE
;
1453 if (g_blockEventsOnDrag
) return TRUE
;
1454 if (g_blockEventsOnScroll
) return TRUE
;
1456 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1458 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1460 gtk_widget_grab_focus( win
->m_wxwindow
);
1462 wxPrintf( wxT("GrabFocus from ") );
1463 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1464 wxPrintf( win->GetClassInfo()->GetClassName() );
1465 wxPrintf( wxT(".\n") );
1469 // GDK sends surplus button down events
1470 // before a double click event. We
1471 // need to filter these out.
1472 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1474 GdkEvent
*peek_event
= gdk_event_peek();
1477 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1478 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1480 gdk_event_free( peek_event
);
1485 gdk_event_free( peek_event
);
1490 wxEventType event_type
= wxEVT_NULL
;
1492 // GdkDisplay is a GTK+ 2.2.0 thing
1493 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1494 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1495 !gtk_check_version(2,2,0) &&
1496 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1498 // Reset GDK internal timestamp variables in order to disable GDK
1499 // triple click events. GDK will then next time believe no button has
1500 // been clicked just before, and send a normal button click event.
1501 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1502 display
->button_click_time
[1] = 0;
1503 display
->button_click_time
[0] = 0;
1507 if (gdk_event
->button
== 1)
1509 // note that GDK generates triple click events which are not supported
1510 // by wxWidgets but still have to be passed to the app as otherwise
1511 // clicks would simply go missing
1512 switch (gdk_event
->type
)
1514 // we shouldn't get triple clicks at all for GTK2 because we
1515 // suppress them artificially using the code above but we still
1516 // should map them to something for GTK1 and not just ignore them
1517 // as this would lose clicks
1518 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1519 case GDK_BUTTON_PRESS
:
1520 event_type
= wxEVT_LEFT_DOWN
;
1523 case GDK_2BUTTON_PRESS
:
1524 event_type
= wxEVT_LEFT_DCLICK
;
1528 // just to silence gcc warnings
1532 else if (gdk_event
->button
== 2)
1534 switch (gdk_event
->type
)
1536 case GDK_3BUTTON_PRESS
:
1537 case GDK_BUTTON_PRESS
:
1538 event_type
= wxEVT_MIDDLE_DOWN
;
1541 case GDK_2BUTTON_PRESS
:
1542 event_type
= wxEVT_MIDDLE_DCLICK
;
1549 else if (gdk_event
->button
== 3)
1551 switch (gdk_event
->type
)
1553 case GDK_3BUTTON_PRESS
:
1554 case GDK_BUTTON_PRESS
:
1555 event_type
= wxEVT_RIGHT_DOWN
;
1558 case GDK_2BUTTON_PRESS
:
1559 event_type
= wxEVT_RIGHT_DCLICK
;
1566 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1568 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1570 event_type
= wxEVT_MOUSEWHEEL
;
1574 if ( event_type
== wxEVT_NULL
)
1576 // unknown mouse button or click type
1580 wxMouseEvent
event( event_type
);
1581 InitMouseEvent( win
, event
, gdk_event
);
1583 AdjustEventButtonState(event
);
1585 // wxListBox actually gets mouse events from the item, so we need to give it
1586 // a chance to correct this
1587 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1589 // find the correct window to send the event to: it may be a different one
1590 // from the one which got it at GTK+ level because some controls don't have
1591 // their own X window and thus cannot get any events.
1592 if ( !g_captureWindow
)
1593 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1595 if (win
->GetEventHandler()->ProcessEvent( event
))
1597 g_signal_stop_emission_by_name (widget
, "button_press_event");
1601 if (event_type
== wxEVT_RIGHT_DOWN
)
1603 // generate a "context menu" event: this is similar to right mouse
1604 // click under many GUIs except that it is generated differently
1605 // (right up under MSW, ctrl-click under Mac, right down here) and
1607 // (a) it's a command event and so is propagated to the parent
1608 // (b) under some ports it can be generated from kbd too
1609 // (c) it uses screen coords (because of (a))
1610 wxContextMenuEvent
evtCtx(
1613 win
->ClientToScreen(event
.GetPosition()));
1614 evtCtx
.SetEventObject(win
);
1615 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1622 //-----------------------------------------------------------------------------
1623 // "button_release_event"
1624 //-----------------------------------------------------------------------------
1628 gtk_window_button_release_callback( GtkWidget
*widget
,
1629 GdkEventButton
*gdk_event
,
1635 wxapp_install_idle_handler();
1637 if (!win
->m_hasVMT
) return FALSE
;
1638 if (g_blockEventsOnDrag
) return FALSE
;
1639 if (g_blockEventsOnScroll
) return FALSE
;
1641 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1643 wxEventType event_type
= wxEVT_NULL
;
1645 switch (gdk_event
->button
)
1648 event_type
= wxEVT_LEFT_UP
;
1652 event_type
= wxEVT_MIDDLE_UP
;
1656 event_type
= wxEVT_RIGHT_UP
;
1660 // unknwon button, don't process
1664 wxMouseEvent
event( event_type
);
1665 InitMouseEvent( win
, event
, gdk_event
);
1667 AdjustEventButtonState(event
);
1669 // same wxListBox hack as above
1670 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1672 if ( !g_captureWindow
)
1673 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1675 if (win
->GetEventHandler()->ProcessEvent( event
))
1677 g_signal_stop_emission_by_name (widget
, "button_release_event");
1685 //-----------------------------------------------------------------------------
1686 // "motion_notify_event"
1687 //-----------------------------------------------------------------------------
1691 gtk_window_motion_notify_callback( GtkWidget
*widget
,
1692 GdkEventMotion
*gdk_event
,
1698 wxapp_install_idle_handler();
1700 if (!win
->m_hasVMT
) return FALSE
;
1701 if (g_blockEventsOnDrag
) return FALSE
;
1702 if (g_blockEventsOnScroll
) return FALSE
;
1704 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1706 if (gdk_event
->is_hint
)
1710 GdkModifierType state
;
1711 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1717 printf( "OnMotion from " );
1718 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1719 printf( win->GetClassInfo()->GetClassName() );
1723 wxMouseEvent
event( wxEVT_MOTION
);
1724 InitMouseEvent(win
, event
, gdk_event
);
1726 if ( g_captureWindow
)
1728 // synthetize a mouse enter or leave event if needed
1729 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1730 // This seems to be necessary and actually been added to
1731 // GDK itself in version 2.0.X
1734 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1735 if ( hasMouse
!= g_captureWindowHasMouse
)
1737 // the mouse changed window
1738 g_captureWindowHasMouse
= hasMouse
;
1740 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1741 : wxEVT_LEAVE_WINDOW
);
1742 InitMouseEvent(win
, eventM
, gdk_event
);
1743 eventM
.SetEventObject(win
);
1744 win
->GetEventHandler()->ProcessEvent(eventM
);
1749 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1752 if ( !g_captureWindow
)
1754 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
1755 if (win
->GetEventHandler()->ProcessEvent( cevent
))
1757 // Rewrite cursor handling here (away from idle).
1761 if (win
->GetEventHandler()->ProcessEvent( event
))
1763 g_signal_stop_emission_by_name (widget
, "motion_notify_event");
1771 //-----------------------------------------------------------------------------
1772 // "mouse_wheel_event"
1773 //-----------------------------------------------------------------------------
1777 gtk_window_wheel_callback (GtkWidget
* widget
,
1778 GdkEventScroll
* gdk_event
,
1784 wxapp_install_idle_handler();
1786 wxEventType event_type
= wxEVT_NULL
;
1787 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1788 event_type
= wxEVT_MOUSEWHEEL
;
1789 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1790 event_type
= wxEVT_MOUSEWHEEL
;
1794 wxMouseEvent
event( event_type
);
1795 // Can't use InitMouse macro because scroll events don't have button
1796 event
.SetTimestamp( gdk_event
->time
);
1797 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1798 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1799 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1800 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1801 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1802 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1803 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1804 event
.m_linesPerAction
= 3;
1805 event
.m_wheelDelta
= 120;
1806 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1807 event
.m_wheelRotation
= 120;
1809 event
.m_wheelRotation
= -120;
1811 wxPoint pt
= win
->GetClientAreaOrigin();
1812 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1813 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1815 event
.SetEventObject( win
);
1816 event
.SetId( win
->GetId() );
1817 event
.SetTimestamp( gdk_event
->time
);
1819 if (win
->GetEventHandler()->ProcessEvent( event
))
1821 g_signal_stop_emission_by_name (widget
, "scroll_event");
1829 //-----------------------------------------------------------------------------
1831 //-----------------------------------------------------------------------------
1833 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1835 wxContextMenuEvent
event(
1839 event
.SetEventObject(win
);
1840 return win
->GetEventHandler()->ProcessEvent(event
);
1844 //-----------------------------------------------------------------------------
1846 //-----------------------------------------------------------------------------
1848 // send the wxChildFocusEvent and wxFocusEvent, common code of
1849 // gtk_window_focus_in_callback() and SetFocus()
1850 static bool DoSendFocusEvents(wxWindow
*win
)
1852 // Notify the parent keeping track of focus for the kbd navigation
1853 // purposes that we got it.
1854 wxChildFocusEvent
eventChildFocus(win
);
1855 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1857 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1858 eventFocus
.SetEventObject(win
);
1860 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1865 gtk_window_focus_in_callback( GtkWidget
*widget
,
1866 GdkEventFocus
*WXUNUSED(event
),
1872 wxapp_install_idle_handler();
1875 gtk_im_context_focus_in(win
->m_imData
->context
);
1878 g_focusWindow
= win
;
1880 wxLogTrace(TRACE_FOCUS
,
1881 _T("%s: focus in"), win
->GetName().c_str());
1885 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1889 // caret needs to be informed about focus change
1890 wxCaret
*caret
= win
->GetCaret();
1893 caret
->OnSetFocus();
1895 #endif // wxUSE_CARET
1897 gboolean ret
= FALSE
;
1899 // does the window itself think that it has the focus?
1900 if ( !win
->m_hasFocus
)
1902 // not yet, notify it
1903 win
->m_hasFocus
= true;
1905 (void)DoSendFocusEvents(win
);
1910 // Disable default focus handling for custom windows
1911 // since the default GTK+ handler issues a repaint
1912 if (win
->m_wxwindow
)
1919 //-----------------------------------------------------------------------------
1920 // "focus_out_event"
1921 //-----------------------------------------------------------------------------
1925 gtk_window_focus_out_callback( GtkWidget
*widget
,
1926 GdkEventFocus
*gdk_event
,
1932 wxapp_install_idle_handler();
1935 gtk_im_context_focus_out(win
->m_imData
->context
);
1937 wxLogTrace( TRACE_FOCUS
,
1938 _T("%s: focus out"), win
->GetName().c_str() );
1941 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1945 g_focusWindow
= (wxWindowGTK
*)NULL
;
1953 // caret needs to be informed about focus change
1954 wxCaret
*caret
= win
->GetCaret();
1957 caret
->OnKillFocus();
1959 #endif // wxUSE_CARET
1961 gboolean ret
= FALSE
;
1963 // don't send the window a kill focus event if it thinks that it doesn't
1964 // have focus already
1965 if ( win
->m_hasFocus
)
1967 win
->m_hasFocus
= false;
1969 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1970 event
.SetEventObject( win
);
1972 (void)win
->GetEventHandler()->ProcessEvent( event
);
1977 // Disable default focus handling for custom windows
1978 // since the default GTK+ handler issues a repaint
1979 if (win
->m_wxwindow
)
1986 //-----------------------------------------------------------------------------
1987 // "enter_notify_event"
1988 //-----------------------------------------------------------------------------
1992 gtk_window_enter_callback( GtkWidget
*widget
,
1993 GdkEventCrossing
*gdk_event
,
1999 wxapp_install_idle_handler();
2001 if (!win
->m_hasVMT
) return FALSE
;
2002 if (g_blockEventsOnDrag
) return FALSE
;
2004 // Event was emitted after a grab
2005 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2007 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2011 GdkModifierType state
= (GdkModifierType
)0;
2013 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2015 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2016 InitMouseEvent(win
, event
, gdk_event
);
2017 wxPoint pt
= win
->GetClientAreaOrigin();
2018 event
.m_x
= x
+ pt
.x
;
2019 event
.m_y
= y
+ pt
.y
;
2021 if ( !g_captureWindow
)
2023 wxSetCursorEvent
cevent( event
.m_x
, event
.m_y
);
2024 if (win
->GetEventHandler()->ProcessEvent( cevent
))
2026 // Rewrite cursor handling here (away from idle).
2030 if (win
->GetEventHandler()->ProcessEvent( event
))
2032 g_signal_stop_emission_by_name (widget
, "enter_notify_event");
2040 //-----------------------------------------------------------------------------
2041 // "leave_notify_event"
2042 //-----------------------------------------------------------------------------
2046 gtk_window_leave_callback( GtkWidget
*widget
,
2047 GdkEventCrossing
*gdk_event
,
2053 wxapp_install_idle_handler();
2055 if (!win
->m_hasVMT
) return FALSE
;
2056 if (g_blockEventsOnDrag
) return FALSE
;
2058 // Event was emitted after an ungrab
2059 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2061 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2063 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2064 event
.SetTimestamp( gdk_event
->time
);
2065 event
.SetEventObject( win
);
2069 GdkModifierType state
= (GdkModifierType
)0;
2071 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2073 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2074 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2075 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2076 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2077 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2078 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2079 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2081 wxPoint pt
= win
->GetClientAreaOrigin();
2082 event
.m_x
= x
+ pt
.x
;
2083 event
.m_y
= y
+ pt
.y
;
2085 if (win
->GetEventHandler()->ProcessEvent( event
))
2087 g_signal_stop_emission_by_name (widget
, "leave_notify_event");
2095 //-----------------------------------------------------------------------------
2096 // "value_changed" from m_vAdjust
2097 //-----------------------------------------------------------------------------
2100 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2106 wxapp_install_idle_handler();
2108 if (g_blockEventsOnDrag
) return;
2110 if (!win
->m_hasVMT
) return;
2112 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2113 if (fabs(diff
) < 0.2) return;
2115 win
->m_oldVerticalPos
= adjust
->value
;
2117 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2119 int value
= (int)(adjust
->value
+0.5);
2121 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2122 event
.SetEventObject( win
);
2123 win
->GetEventHandler()->ProcessEvent( event
);
2127 //-----------------------------------------------------------------------------
2128 // "value_changed" from m_hAdjust
2129 //-----------------------------------------------------------------------------
2132 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2138 wxapp_install_idle_handler();
2140 if (g_blockEventsOnDrag
) return;
2141 if (!win
->m_hasVMT
) return;
2143 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2144 if (fabs(diff
) < 0.2) return;
2146 wxEventType command
= GtkScrollWinTypeToWx(GTK_SCROLL_JUMP
);
2148 win
->m_oldHorizontalPos
= adjust
->value
;
2150 int value
= (int)(adjust
->value
+0.5);
2152 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2153 event
.SetEventObject( win
);
2154 win
->GetEventHandler()->ProcessEvent( event
);
2158 //-----------------------------------------------------------------------------
2159 // "button_press_event" from scrollbar
2160 //-----------------------------------------------------------------------------
2164 gtk_scrollbar_button_press_callback( GtkWidget
*widget
,
2165 GdkEventButton
*gdk_event
,
2171 wxapp_install_idle_handler();
2174 g_blockEventsOnScroll
= true;
2176 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2178 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2185 //-----------------------------------------------------------------------------
2186 // "button_release_event" from scrollbar
2187 //-----------------------------------------------------------------------------
2191 gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2192 GdkEventButton
*WXUNUSED(gdk_event
),
2197 // don't test here as we can release the mouse while being over
2198 // a different window than the slider
2200 // if (gdk_event->window != widget->slider) return FALSE;
2202 g_blockEventsOnScroll
= false;
2204 if (win
->m_isScrolling
)
2206 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2210 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2211 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2213 value
= (int)(win
->m_hAdjust
->value
+0.5);
2216 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2218 value
= (int)(win
->m_vAdjust
->value
+0.5);
2222 wxScrollWinEvent
event( command
, value
, dir
);
2223 event
.SetEventObject( win
);
2224 win
->GetEventHandler()->ProcessEvent( event
);
2227 win
->m_isScrolling
= false;
2233 // ----------------------------------------------------------------------------
2234 // this wxWindowBase function is implemented here (in platform-specific file)
2235 // because it is static and so couldn't be made virtual
2236 // ----------------------------------------------------------------------------
2238 wxWindow
*wxWindowBase::DoFindFocus()
2240 // the cast is necessary when we compile in wxUniversal mode
2241 return (wxWindow
*)g_focusWindow
;
2244 //-----------------------------------------------------------------------------
2245 // "realize" from m_widget
2246 //-----------------------------------------------------------------------------
2248 /* We cannot set colours and fonts before the widget has
2249 been realized, so we do this directly after realization. */
2253 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2258 wxapp_install_idle_handler();
2262 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2263 gtk_im_context_set_client_window( win
->m_imData
->context
,
2264 pizza
->bin_window
);
2267 wxWindowCreateEvent
event( win
);
2268 event
.SetEventObject( win
);
2269 win
->GetEventHandler()->ProcessEvent( event
);
2273 //-----------------------------------------------------------------------------
2275 //-----------------------------------------------------------------------------
2279 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2280 GtkAllocation
*WXUNUSED(alloc
),
2284 wxapp_install_idle_handler();
2286 if (!win
->m_hasScrolling
) return;
2288 int client_width
= 0;
2289 int client_height
= 0;
2290 win
->GetClientSize( &client_width
, &client_height
);
2291 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2294 win
->m_oldClientWidth
= client_width
;
2295 win
->m_oldClientHeight
= client_height
;
2297 if (!win
->m_nativeSizeEvent
)
2299 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2300 event
.SetEventObject( win
);
2301 win
->GetEventHandler()->ProcessEvent( event
);
2308 #define WXUNUSED_UNLESS_XIM(param) param
2310 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2313 /* Resize XIM window */
2317 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2318 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2319 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2322 wxapp_install_idle_handler();
2328 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2332 gdk_window_get_size (widget
->window
, &width
, &height
);
2333 win
->m_icattr
->preedit_area
.width
= width
;
2334 win
->m_icattr
->preedit_area
.height
= height
;
2335 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2341 //-----------------------------------------------------------------------------
2342 // "realize" from m_wxwindow
2343 //-----------------------------------------------------------------------------
2345 /* Initialize XIM support */
2349 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2350 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2353 wxapp_install_idle_handler();
2356 if (win
->m_ic
) return;
2357 if (!widget
) return;
2358 if (!gdk_im_ready()) return;
2360 win
->m_icattr
= gdk_ic_attr_new();
2361 if (!win
->m_icattr
) return;
2365 GdkColormap
*colormap
;
2366 GdkICAttr
*attr
= win
->m_icattr
;
2367 unsigned attrmask
= GDK_IC_ALL_REQ
;
2369 GdkIMStyle supported_style
= (GdkIMStyle
)
2370 (GDK_IM_PREEDIT_NONE
|
2371 GDK_IM_PREEDIT_NOTHING
|
2372 GDK_IM_PREEDIT_POSITION
|
2373 GDK_IM_STATUS_NONE
|
2374 GDK_IM_STATUS_NOTHING
);
2376 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2377 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2379 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2380 attr
->client_window
= widget
->window
;
2382 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2383 gtk_widget_get_default_colormap ())
2385 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2386 attr
->preedit_colormap
= colormap
;
2389 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2390 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2391 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2392 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2394 switch (style
& GDK_IM_PREEDIT_MASK
)
2396 case GDK_IM_PREEDIT_POSITION
:
2397 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2399 g_warning ("over-the-spot style requires fontset");
2403 gdk_window_get_size (widget
->window
, &width
, &height
);
2405 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2406 attr
->spot_location
.x
= 0;
2407 attr
->spot_location
.y
= height
;
2408 attr
->preedit_area
.x
= 0;
2409 attr
->preedit_area
.y
= 0;
2410 attr
->preedit_area
.width
= width
;
2411 attr
->preedit_area
.height
= height
;
2412 attr
->preedit_fontset
= widget
->style
->font
;
2417 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2419 if (win
->m_ic
== NULL
)
2420 g_warning ("Can't create input context.");
2423 mask
= gdk_window_get_events (widget
->window
);
2424 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2425 gdk_window_set_events (widget
->window
, mask
);
2427 if (GTK_WIDGET_HAS_FOCUS(widget
))
2428 gdk_im_begin (win
->m_ic
, widget
->window
);
2434 //-----------------------------------------------------------------------------
2435 // InsertChild for wxWindowGTK.
2436 //-----------------------------------------------------------------------------
2438 /* Callback for wxWindowGTK. This very strange beast has to be used because
2439 * C++ has no virtual methods in a constructor. We have to emulate a
2440 * virtual function here as wxNotebook requires a different way to insert
2441 * a child in it. I had opted for creating a wxNotebookPage window class
2442 * which would have made this superfluous (such in the MDI window system),
2443 * but no-one was listening to me... */
2445 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2447 /* the window might have been scrolled already, do we
2448 have to adapt the position */
2449 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2450 child
->m_x
+= pizza
->xoffset
;
2451 child
->m_y
+= pizza
->yoffset
;
2453 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2454 GTK_WIDGET(child
->m_widget
),
2461 //-----------------------------------------------------------------------------
2463 //-----------------------------------------------------------------------------
2465 wxWindow
*wxGetActiveWindow()
2467 return wxWindow::FindFocus();
2471 wxMouseState
wxGetMouseState()
2477 GdkModifierType mask
;
2479 gdk_window_get_pointer(NULL
, &x
, &y
, &mask
);
2483 ms
.SetLeftDown(mask
& GDK_BUTTON1_MASK
);
2484 ms
.SetMiddleDown(mask
& GDK_BUTTON2_MASK
);
2485 ms
.SetRightDown(mask
& GDK_BUTTON3_MASK
);
2487 ms
.SetControlDown(mask
& GDK_CONTROL_MASK
);
2488 ms
.SetShiftDown(mask
& GDK_SHIFT_MASK
);
2489 ms
.SetAltDown(mask
& GDK_MOD1_MASK
);
2490 ms
.SetMetaDown(mask
& GDK_MOD2_MASK
);
2495 //-----------------------------------------------------------------------------
2497 //-----------------------------------------------------------------------------
2499 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2501 #ifdef __WXUNIVERSAL__
2502 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2504 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2505 #endif // __WXUNIVERSAL__/__WXGTK__
2507 void wxWindowGTK::Init()
2510 m_widget
= (GtkWidget
*) NULL
;
2511 m_wxwindow
= (GtkWidget
*) NULL
;
2512 m_focusWidget
= (GtkWidget
*) NULL
;
2522 m_needParent
= true;
2523 m_isBeingDeleted
= false;
2526 m_nativeSizeEvent
= false;
2528 m_hasScrolling
= false;
2529 m_isScrolling
= false;
2531 m_hAdjust
= (GtkAdjustment
*) NULL
;
2532 m_vAdjust
= (GtkAdjustment
*) NULL
;
2533 m_oldHorizontalPos
=
2534 m_oldVerticalPos
= 0.0;
2536 m_oldClientHeight
= 0;
2540 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2542 m_acceptsFocus
= false;
2545 m_clipPaintRegion
= false;
2547 m_needsStyleChange
= false;
2549 m_cursor
= *wxSTANDARD_CURSOR
;
2552 m_dirtyTabOrder
= false;
2555 wxWindowGTK::wxWindowGTK()
2560 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2565 const wxString
&name
)
2569 Create( parent
, id
, pos
, size
, style
, name
);
2572 bool wxWindowGTK::Create( wxWindow
*parent
,
2577 const wxString
&name
)
2579 if (!PreCreation( parent
, pos
, size
) ||
2580 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2582 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2586 m_insertCallback
= wxInsertChildInWindow
;
2588 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2589 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2591 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2593 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2594 scroll_class
->scrollbar_spacing
= 0;
2596 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2598 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2599 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2601 m_wxwindow
= gtk_pizza_new();
2603 #ifndef __WXUNIVERSAL__
2604 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2606 if (HasFlag(wxRAISED_BORDER
))
2608 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2610 else if (HasFlag(wxSUNKEN_BORDER
))
2612 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2614 else if (HasFlag(wxSIMPLE_BORDER
))
2616 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2620 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2622 #endif // __WXUNIVERSAL__
2624 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2626 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2627 m_acceptsFocus
= true;
2629 // I _really_ don't want scrollbars in the beginning
2630 m_vAdjust
->lower
= 0.0;
2631 m_vAdjust
->upper
= 1.0;
2632 m_vAdjust
->value
= 0.0;
2633 m_vAdjust
->step_increment
= 1.0;
2634 m_vAdjust
->page_increment
= 1.0;
2635 m_vAdjust
->page_size
= 5.0;
2636 g_signal_emit_by_name (m_vAdjust
, "changed");
2637 m_hAdjust
->lower
= 0.0;
2638 m_hAdjust
->upper
= 1.0;
2639 m_hAdjust
->value
= 0.0;
2640 m_hAdjust
->step_increment
= 1.0;
2641 m_hAdjust
->page_increment
= 1.0;
2642 m_hAdjust
->page_size
= 5.0;
2643 g_signal_emit_by_name (m_hAdjust
, "changed");
2645 // these handlers block mouse events to any window during scrolling such as
2646 // motion events and prevent GTK and wxWidgets from fighting over where the
2648 g_signal_connect (scrolledWindow
->vscrollbar
, "button_press_event",
2649 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2650 g_signal_connect (scrolledWindow
->hscrollbar
, "button_press_event",
2651 G_CALLBACK (gtk_scrollbar_button_press_callback
), this);
2652 g_signal_connect (scrolledWindow
->vscrollbar
, "button_release_event",
2653 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2654 g_signal_connect (scrolledWindow
->hscrollbar
, "button_release_event",
2655 G_CALLBACK (gtk_scrollbar_button_release_callback
), this);
2657 // these handlers get notified when screen updates are required either when
2658 // scrolling or when the window size (and therefore scrollbar configuration)
2661 g_signal_connect (m_hAdjust
, "value_changed",
2662 G_CALLBACK (gtk_window_hscroll_callback
), this);
2663 g_signal_connect (m_vAdjust
, "value_changed",
2664 G_CALLBACK (gtk_window_vscroll_callback
), this);
2666 gtk_widget_show( m_wxwindow
);
2669 m_parent
->DoAddChild( this );
2671 m_focusWidget
= m_wxwindow
;
2678 wxWindowGTK::~wxWindowGTK()
2682 if (g_focusWindow
== this)
2683 g_focusWindow
= NULL
;
2685 if ( g_delayedFocus
== this )
2686 g_delayedFocus
= NULL
;
2688 m_isBeingDeleted
= true;
2691 // destroy children before destroying this window itself
2694 // unhook focus handlers to prevent stray events being
2695 // propagated to this (soon to be) dead object
2696 if (m_focusWidget
!= NULL
)
2698 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2699 (gpointer
) gtk_window_focus_in_callback
,
2701 g_signal_handlers_disconnect_by_func (m_focusWidget
,
2702 (gpointer
) gtk_window_focus_out_callback
,
2711 gdk_ic_destroy (m_ic
);
2713 gdk_ic_attr_destroy (m_icattr
);
2716 // delete before the widgets to avoid a crash on solaris
2721 gtk_widget_destroy( m_wxwindow
);
2722 m_wxwindow
= (GtkWidget
*) NULL
;
2727 gtk_widget_destroy( m_widget
);
2728 m_widget
= (GtkWidget
*) NULL
;
2732 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2734 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2736 // Use either the given size, or the default if -1 is given.
2737 // See wxWindowBase for these functions.
2738 m_width
= WidthDefault(size
.x
) ;
2739 m_height
= HeightDefault(size
.y
);
2747 void wxWindowGTK::PostCreation()
2749 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2755 // these get reported to wxWidgets -> wxPaintEvent
2757 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2759 g_signal_connect (m_wxwindow
, "expose_event",
2760 G_CALLBACK (gtk_window_expose_callback
), this);
2762 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxFULL_REPAINT_ON_RESIZE
) );
2765 // Create input method handler
2766 m_imData
= new wxGtkIMData
;
2768 // Cannot handle drawing preedited text yet
2769 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2771 g_signal_connect (m_imData
->context
, "commit",
2772 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2774 // these are called when the "sunken" or "raised" borders are drawn
2775 g_signal_connect (m_widget
, "expose_event",
2776 G_CALLBACK (gtk_window_own_expose_callback
), this);
2781 if (!GTK_IS_WINDOW(m_widget
))
2783 if (m_focusWidget
== NULL
)
2784 m_focusWidget
= m_widget
;
2788 g_signal_connect (m_focusWidget
, "focus_in_event",
2789 G_CALLBACK (gtk_window_focus_in_callback
), this);
2790 g_signal_connect (m_focusWidget
, "focus_out_event",
2791 G_CALLBACK (gtk_window_focus_out_callback
), this);
2795 g_signal_connect_after (m_focusWidget
, "focus_in_event",
2796 G_CALLBACK (gtk_window_focus_in_callback
), this);
2797 g_signal_connect_after (m_focusWidget
, "focus_out_event",
2798 G_CALLBACK (gtk_window_focus_out_callback
), this);
2802 // connect to the various key and mouse handlers
2804 GtkWidget
*connect_widget
= GetConnectWidget();
2806 ConnectWidget( connect_widget
);
2808 /* We cannot set colours, fonts and cursors before the widget has
2809 been realized, so we do this directly after realization */
2810 g_signal_connect (connect_widget
, "realize",
2811 G_CALLBACK (gtk_window_realized_callback
), this);
2815 // Catch native resize events
2816 g_signal_connect (m_wxwindow
, "size_allocate",
2817 G_CALLBACK (gtk_window_size_callback
), this);
2819 // Initialize XIM support
2820 g_signal_connect (m_wxwindow
, "realize",
2821 G_CALLBACK (gtk_wxwindow_realized_callback
), this);
2823 // And resize XIM window
2824 g_signal_connect (m_wxwindow
, "size_allocate",
2825 G_CALLBACK (gtk_wxwindow_size_callback
), this);
2828 if (GTK_IS_COMBO(m_widget
))
2830 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2832 g_signal_connect (gcombo
->entry
, "size_request",
2833 G_CALLBACK (wxgtk_combo_size_request_callback
),
2838 // This is needed if we want to add our windows into native
2839 // GTK controls, such as the toolbar. With this callback, the
2840 // toolbar gets to know the correct size (the one set by the
2841 // programmer). Sadly, it misbehaves for wxComboBox.
2842 g_signal_connect (m_widget
, "size_request",
2843 G_CALLBACK (wxgtk_window_size_request_callback
),
2847 InheritAttributes();
2851 // unless the window was created initially hidden (i.e. Hide() had been
2852 // called before Create()), we should show it at GTK+ level as well
2854 gtk_widget_show( m_widget
);
2857 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2859 g_signal_connect (widget
, "key_press_event",
2860 G_CALLBACK (gtk_window_key_press_callback
), this);
2861 g_signal_connect (widget
, "key_release_event",
2862 G_CALLBACK (gtk_window_key_release_callback
), this);
2863 g_signal_connect (widget
, "button_press_event",
2864 G_CALLBACK (gtk_window_button_press_callback
), this);
2865 g_signal_connect (widget
, "button_release_event",
2866 G_CALLBACK (gtk_window_button_release_callback
), this);
2867 g_signal_connect (widget
, "motion_notify_event",
2868 G_CALLBACK (gtk_window_motion_notify_callback
), this);
2869 g_signal_connect (widget
, "scroll_event",
2870 G_CALLBACK (gtk_window_wheel_callback
), this);
2871 g_signal_connect (widget
, "popup_menu",
2872 G_CALLBACK (wxgtk_window_popup_menu_callback
), this);
2873 g_signal_connect (widget
, "enter_notify_event",
2874 G_CALLBACK (gtk_window_enter_callback
), this);
2875 g_signal_connect (widget
, "leave_notify_event",
2876 G_CALLBACK (gtk_window_leave_callback
), this);
2879 bool wxWindowGTK::Destroy()
2881 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2885 return wxWindowBase::Destroy();
2888 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2890 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2893 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2895 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2896 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2899 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2902 if (m_resizing
) return; /* I don't like recursions */
2905 int currentX
, currentY
;
2906 GetPosition(¤tX
, ¤tY
);
2907 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2909 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2911 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2913 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2915 /* don't set the size for children of wxNotebook, just take the values. */
2923 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2924 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2926 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2927 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2931 m_x
= x
+ pizza
->xoffset
;
2932 m_y
= y
+ pizza
->yoffset
;
2935 // calculate the best size if we should auto size the window
2936 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2937 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2939 const wxSize sizeBest
= GetBestSize();
2940 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2942 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2943 height
= sizeBest
.y
;
2951 int minWidth
= GetMinWidth(),
2952 minHeight
= GetMinHeight(),
2953 maxWidth
= GetMaxWidth(),
2954 maxHeight
= GetMaxHeight();
2956 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2957 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2958 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2959 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2961 int left_border
= 0;
2962 int right_border
= 0;
2964 int bottom_border
= 0;
2966 /* the default button has a border around it */
2967 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2969 GtkBorder
*default_border
= NULL
;
2970 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
2973 left_border
+= default_border
->left
;
2974 right_border
+= default_border
->right
;
2975 top_border
+= default_border
->top
;
2976 bottom_border
+= default_border
->bottom
;
2977 g_free( default_border
);
2981 DoMoveWindow( m_x
-top_border
,
2983 m_width
+left_border
+right_border
,
2984 m_height
+top_border
+bottom_border
);
2989 /* Sometimes the client area changes size without the
2990 whole windows's size changing, but if the whole
2991 windows's size doesn't change, no wxSizeEvent will
2992 normally be sent. Here we add an extra test if
2993 the client test has been changed and this will
2995 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2999 wxPrintf( "OnSize sent from " );
3000 if (GetClassInfo() && GetClassInfo()->GetClassName())
3001 wxPrintf( GetClassInfo()->GetClassName() );
3002 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3005 if (!m_nativeSizeEvent
)
3007 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3008 event
.SetEventObject( this );
3009 GetEventHandler()->ProcessEvent( event
);
3015 void wxWindowGTK::OnInternalIdle()
3017 if ( m_dirtyTabOrder
)
3019 m_dirtyTabOrder
= false;
3023 // Update style if the window was not yet realized
3024 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3025 if (m_needsStyleChange
)
3027 SetBackgroundStyle(GetBackgroundStyle());
3028 m_needsStyleChange
= false;
3031 // Update invalidated regions.
3034 wxCursor cursor
= m_cursor
;
3035 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3039 /* I now set the cursor anew in every OnInternalIdle call
3040 as setting the cursor in a parent window also effects the
3041 windows above so that checking for the current cursor is
3046 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3048 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3050 if (!g_globalCursor
.Ok())
3051 cursor
= *wxSTANDARD_CURSOR
;
3053 window
= m_widget
->window
;
3054 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3055 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3061 GdkWindow
*window
= m_widget
->window
;
3062 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3063 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3068 if (wxUpdateUIEvent::CanUpdate(this))
3069 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3072 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3074 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3076 if (width
) (*width
) = m_width
;
3077 if (height
) (*height
) = m_height
;
3080 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3082 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3086 SetSize( width
, height
);
3093 #ifndef __WXUNIVERSAL__
3094 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3096 /* when using GTK 1.2 we set the shadow border size to 2 */
3100 if (HasFlag(wxSIMPLE_BORDER
))
3102 /* when using GTK 1.2 we set the simple border size to 1 */
3106 #endif // __WXUNIVERSAL__
3110 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3112 GtkRequisition vscroll_req
;
3113 vscroll_req
.width
= 2;
3114 vscroll_req
.height
= 2;
3115 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3116 (scroll_window
->vscrollbar
, &vscroll_req
);
3118 GtkRequisition hscroll_req
;
3119 hscroll_req
.width
= 2;
3120 hscroll_req
.height
= 2;
3121 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3122 (scroll_window
->hscrollbar
, &hscroll_req
);
3124 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3126 if (scroll_window
->vscrollbar_visible
)
3128 dw
+= vscroll_req
.width
;
3129 dw
+= scroll_class
->scrollbar_spacing
;
3132 if (scroll_window
->hscrollbar_visible
)
3134 dh
+= hscroll_req
.height
;
3135 dh
+= scroll_class
->scrollbar_spacing
;
3139 SetSize( width
+dw
, height
+dh
);
3143 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3145 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3149 if (width
) (*width
) = m_width
;
3150 if (height
) (*height
) = m_height
;
3157 #ifndef __WXUNIVERSAL__
3158 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3160 /* when using GTK 1.2 we set the shadow border size to 2 */
3164 if (HasFlag(wxSIMPLE_BORDER
))
3166 /* when using GTK 1.2 we set the simple border size to 1 */
3170 #endif // __WXUNIVERSAL__
3174 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3176 GtkRequisition vscroll_req
;
3177 vscroll_req
.width
= 2;
3178 vscroll_req
.height
= 2;
3179 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3180 (scroll_window
->vscrollbar
, &vscroll_req
);
3182 GtkRequisition hscroll_req
;
3183 hscroll_req
.width
= 2;
3184 hscroll_req
.height
= 2;
3185 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3186 (scroll_window
->hscrollbar
, &hscroll_req
);
3188 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3190 if (scroll_window
->vscrollbar_visible
)
3192 dw
+= vscroll_req
.width
;
3193 dw
+= scroll_class
->scrollbar_spacing
;
3196 if (scroll_window
->hscrollbar_visible
)
3198 dh
+= hscroll_req
.height
;
3199 dh
+= scroll_class
->scrollbar_spacing
;
3203 if (width
) (*width
) = m_width
- dw
;
3204 if (height
) (*height
) = m_height
- dh
;
3208 printf( "GetClientSize, name %s ", GetName().c_str() );
3209 if (width) printf( " width = %d", (*width) );
3210 if (height) printf( " height = %d", (*height) );
3215 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3217 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3221 if (m_parent
&& m_parent
->m_wxwindow
)
3223 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3224 dx
= pizza
->xoffset
;
3225 dy
= pizza
->yoffset
;
3228 if (x
) (*x
) = m_x
- dx
;
3229 if (y
) (*y
) = m_y
- dy
;
3232 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3234 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3236 if (!m_widget
->window
) return;
3238 GdkWindow
*source
= (GdkWindow
*) NULL
;
3240 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3242 source
= m_widget
->window
;
3246 gdk_window_get_origin( source
, &org_x
, &org_y
);
3250 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3252 org_x
+= m_widget
->allocation
.x
;
3253 org_y
+= m_widget
->allocation
.y
;
3261 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3263 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3265 if (!m_widget
->window
) return;
3267 GdkWindow
*source
= (GdkWindow
*) NULL
;
3269 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3271 source
= m_widget
->window
;
3275 gdk_window_get_origin( source
, &org_x
, &org_y
);
3279 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3281 org_x
+= m_widget
->allocation
.x
;
3282 org_y
+= m_widget
->allocation
.y
;
3290 bool wxWindowGTK::Show( bool show
)
3292 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3294 if (!wxWindowBase::Show(show
))
3301 gtk_widget_show( m_widget
);
3303 gtk_widget_hide( m_widget
);
3305 wxShowEvent
eventShow(GetId(), show
);
3306 eventShow
.SetEventObject(this);
3308 GetEventHandler()->ProcessEvent(eventShow
);
3313 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3315 win
->OnParentEnable(enable
);
3317 // Recurse, so that children have the opportunity to Do The Right Thing
3318 // and reset colours that have been messed up by a parent's (really ancestor's)
3320 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3322 node
= node
->GetNext() )
3324 wxWindow
*child
= node
->GetData();
3325 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3326 wxWindowNotifyEnable(child
, enable
);
3330 bool wxWindowGTK::Enable( bool enable
)
3332 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3334 if (!wxWindowBase::Enable(enable
))
3340 gtk_widget_set_sensitive( m_widget
, enable
);
3342 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3344 wxWindowNotifyEnable(this, enable
);
3349 int wxWindowGTK::GetCharHeight() const
3351 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3353 wxFont font
= GetFont();
3354 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3356 PangoContext
*context
= NULL
;
3358 context
= gtk_widget_get_pango_context( m_widget
);
3363 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3364 PangoLayout
*layout
= pango_layout_new(context
);
3365 pango_layout_set_font_description(layout
, desc
);
3366 pango_layout_set_text(layout
, "H", 1);
3367 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3369 PangoRectangle rect
;
3370 pango_layout_line_get_extents(line
, NULL
, &rect
);
3372 g_object_unref( G_OBJECT( layout
) );
3374 return (int) PANGO_PIXELS(rect
.height
);
3377 int wxWindowGTK::GetCharWidth() const
3379 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3381 wxFont font
= GetFont();
3382 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3384 PangoContext
*context
= NULL
;
3386 context
= gtk_widget_get_pango_context( m_widget
);
3391 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3392 PangoLayout
*layout
= pango_layout_new(context
);
3393 pango_layout_set_font_description(layout
, desc
);
3394 pango_layout_set_text(layout
, "g", 1);
3395 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3397 PangoRectangle rect
;
3398 pango_layout_line_get_extents(line
, NULL
, &rect
);
3400 g_object_unref( G_OBJECT( layout
) );
3402 return (int) PANGO_PIXELS(rect
.width
);
3405 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3409 int *externalLeading
,
3410 const wxFont
*theFont
) const
3412 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3414 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3423 PangoContext
*context
= NULL
;
3425 context
= gtk_widget_get_pango_context( m_widget
);
3434 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3435 PangoLayout
*layout
= pango_layout_new(context
);
3436 pango_layout_set_font_description(layout
, desc
);
3439 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3440 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3442 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3443 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3444 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3448 PangoRectangle rect
;
3449 pango_layout_get_extents(layout
, NULL
, &rect
);
3451 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3452 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3455 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3456 int baseline
= pango_layout_iter_get_baseline(iter
);
3457 pango_layout_iter_free(iter
);
3458 *descent
= *y
- PANGO_PIXELS(baseline
);
3460 if (externalLeading
) (*externalLeading
) = 0; // ??
3462 g_object_unref( G_OBJECT( layout
) );
3465 void wxWindowGTK::SetFocus()
3467 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3470 // don't do anything if we already have focus
3476 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3478 gtk_widget_grab_focus (m_wxwindow
);
3483 if (GTK_IS_CONTAINER(m_widget
))
3485 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3488 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3491 if (!GTK_WIDGET_REALIZED(m_widget
))
3493 // we can't set the focus to the widget now so we remember that
3494 // it should be focused and will do it later, during the idle
3495 // time, as soon as we can
3496 wxLogTrace(TRACE_FOCUS
,
3497 _T("Delaying setting focus to %s(%s)"),
3498 GetClassInfo()->GetClassName(), GetLabel().c_str());
3500 g_delayedFocus
= this;
3504 wxLogTrace(TRACE_FOCUS
,
3505 _T("Setting focus to %s(%s)"),
3506 GetClassInfo()->GetClassName(), GetLabel().c_str());
3508 gtk_widget_grab_focus (m_widget
);
3513 wxLogTrace(TRACE_FOCUS
,
3514 _T("Can't set focus to %s(%s)"),
3515 GetClassInfo()->GetClassName(), GetLabel().c_str());
3520 bool wxWindowGTK::AcceptsFocus() const
3522 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3525 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3527 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3529 wxWindowGTK
*oldParent
= m_parent
,
3530 *newParent
= (wxWindowGTK
*)newParentBase
;
3532 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3534 if ( !wxWindowBase::Reparent(newParent
) )
3537 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3539 /* prevent GTK from deleting the widget arbitrarily */
3540 gtk_widget_ref( m_widget
);
3544 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3547 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3551 /* insert GTK representation */
3552 (*(newParent
->m_insertCallback
))(newParent
, this);
3555 /* reverse: prevent GTK from deleting the widget arbitrarily */
3556 gtk_widget_unref( m_widget
);
3561 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3563 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3565 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3567 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3572 /* insert GTK representation */
3573 (*m_insertCallback
)(this, child
);
3576 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3578 wxWindowBase::AddChild(child
);
3579 m_dirtyTabOrder
= true;
3581 wxapp_install_idle_handler();
3584 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3586 wxWindowBase::RemoveChild(child
);
3587 m_dirtyTabOrder
= true;
3589 wxapp_install_idle_handler();
3592 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3594 wxWindowBase::DoMoveInTabOrder(win
, move
);
3595 m_dirtyTabOrder
= true;
3597 wxapp_install_idle_handler();
3600 void wxWindowGTK::RealizeTabOrder()
3604 if ( !m_children
.empty() )
3607 // we don't only construct the correct focus chain but also use
3608 // this opportunity to update the mnemonic widgets for all labels
3610 // it would be nice to extract this code from here and put it in
3611 // stattext.cpp to reduce dependencies but there is no really easy
3612 // way to do it unfortunately
3613 wxStaticText
*lastLabel
= NULL
;
3614 #endif // wxUSE_STATTEXT
3616 GList
*chain
= NULL
;
3618 for ( wxWindowList::const_iterator i
= m_children
.begin();
3619 i
!= m_children
.end();
3622 wxWindowGTK
*win
= *i
;
3626 if ( win
->AcceptsFocusFromKeyboard() )
3628 GtkLabel
*l
= GTK_LABEL(lastLabel
->m_widget
);
3629 gtk_label_set_mnemonic_widget(l
, win
->m_widget
);
3633 else // check if this one is a label
3635 lastLabel
= wxDynamicCast(win
, wxStaticText
);
3637 #endif // wxUSE_STATTEXT
3639 chain
= g_list_prepend(chain
, win
->m_widget
);
3642 chain
= g_list_reverse(chain
);
3644 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3649 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3654 void wxWindowGTK::Raise()
3656 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3658 if (m_wxwindow
&& m_wxwindow
->window
)
3660 gdk_window_raise( m_wxwindow
->window
);
3662 else if (m_widget
->window
)
3664 gdk_window_raise( m_widget
->window
);
3668 void wxWindowGTK::Lower()
3670 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3672 if (m_wxwindow
&& m_wxwindow
->window
)
3674 gdk_window_lower( m_wxwindow
->window
);
3676 else if (m_widget
->window
)
3678 gdk_window_lower( m_widget
->window
);
3682 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3684 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3686 if (cursor
== m_cursor
)
3690 wxapp_install_idle_handler();
3692 if (cursor
== wxNullCursor
)
3693 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3695 return wxWindowBase::SetCursor( cursor
);
3698 void wxWindowGTK::WarpPointer( int x
, int y
)
3700 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3702 // We provide this function ourselves as it is
3703 // missing in GDK (top of this file).
3705 GdkWindow
*window
= (GdkWindow
*) NULL
;
3707 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3709 window
= GetConnectWidget()->window
;
3712 gdk_window_warp_pointer( window
, x
, y
);
3715 static bool wxScrollAdjust(GtkAdjustment
* adj
, double change
)
3717 double value_start
= adj
->value
;
3718 double value
= value_start
+ change
;
3719 double upper
= adj
->upper
- adj
->page_size
;
3724 // Lower bound will be checked by gtk_adjustment_set_value
3725 gtk_adjustment_set_value(adj
, value
);
3726 return adj
->value
!= value_start
;
3729 bool wxWindowGTK::ScrollLines(int lines
)
3732 m_vAdjust
!= NULL
&&
3733 wxScrollAdjust(m_vAdjust
, lines
* m_vAdjust
->step_increment
);
3736 bool wxWindowGTK::ScrollPages(int pages
)
3739 m_vAdjust
!= NULL
&&
3740 wxScrollAdjust(m_vAdjust
, pages
* m_vAdjust
->page_increment
);
3743 void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment
* adj
)
3745 wxASSERT(m_vAdjust
== NULL
);
3749 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3753 if (!m_widget
->window
)
3758 GdkRectangle gdk_rect
,
3762 gdk_rect
.x
= rect
->x
;
3763 gdk_rect
.y
= rect
->y
;
3764 gdk_rect
.width
= rect
->width
;
3765 gdk_rect
.height
= rect
->height
;
3768 else // invalidate everything
3773 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
3777 void wxWindowGTK::Update()
3781 // when we call Update() we really want to update the window immediately on
3782 // screen, even if it means flushing the entire queue and hence slowing down
3783 // everything -- but it should still be done, it's just that Update() should
3784 // be called very rarely
3788 void wxWindowGTK::GtkUpdate()
3790 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3791 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3793 // for consistency with other platforms (and also because it's convenient
3794 // to be able to update an entire TLW by calling Update() only once), we
3795 // should also update all our children here
3796 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3798 node
= node
->GetNext() )
3800 node
->GetData()->GtkUpdate();
3804 void wxWindowGTK::GtkSendPaintEvents()
3808 m_updateRegion
.Clear();
3812 // Clip to paint region in wxClientDC
3813 m_clipPaintRegion
= true;
3815 // widget to draw on
3816 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3818 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3820 // find ancestor from which to steal background
3821 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
3823 parent
= (wxWindow
*)this;
3825 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3827 wxRegionIterator
upd( m_updateRegion
);
3831 rect
.x
= upd
.GetX();
3832 rect
.y
= upd
.GetY();
3833 rect
.width
= upd
.GetWidth();
3834 rect
.height
= upd
.GetHeight();
3836 gtk_paint_flat_box( parent
->m_widget
->style
,
3838 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3852 wxWindowDC
dc( (wxWindow
*)this );
3853 dc
.SetClippingRegion( m_updateRegion
);
3855 wxEraseEvent
erase_event( GetId(), &dc
);
3856 erase_event
.SetEventObject( this );
3858 GetEventHandler()->ProcessEvent(erase_event
);
3861 wxNcPaintEvent
nc_paint_event( GetId() );
3862 nc_paint_event
.SetEventObject( this );
3863 GetEventHandler()->ProcessEvent( nc_paint_event
);
3865 wxPaintEvent
paint_event( GetId() );
3866 paint_event
.SetEventObject( this );
3867 GetEventHandler()->ProcessEvent( paint_event
);
3869 m_clipPaintRegion
= false;
3871 m_updateRegion
.Clear();
3874 void wxWindowGTK::ClearBackground()
3876 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3880 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3882 wxWindowBase::DoSetToolTip(tip
);
3885 m_tooltip
->Apply( (wxWindow
*)this );
3888 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3890 wxString
tmp( tip
);
3891 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3893 #endif // wxUSE_TOOLTIPS
3895 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3897 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3899 if (!wxWindowBase::SetBackgroundColour(colour
))
3904 // We need the pixel value e.g. for background clearing.
3905 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3908 // apply style change (forceStyle=true so that new style is applied
3909 // even if the bg colour changed from valid to wxNullColour)
3910 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3911 ApplyWidgetStyle(true);
3916 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3918 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
3920 if (!wxWindowBase::SetForegroundColour(colour
))
3927 // We need the pixel value e.g. for background clearing.
3928 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3931 // apply style change (forceStyle=true so that new style is applied
3932 // even if the bg colour changed from valid to wxNullColour):
3933 ApplyWidgetStyle(true);
3938 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3940 return gtk_widget_get_pango_context( m_widget
);
3943 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
3945 // do we need to apply any changes at all?
3948 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
3953 GtkRcStyle
*style
= gtk_rc_style_new();
3958 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
3961 if ( m_foregroundColour
.Ok() )
3963 GdkColor
*fg
= m_foregroundColour
.GetColor();
3965 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
3966 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
3968 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
3969 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
3971 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
3972 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
3975 if ( m_backgroundColour
.Ok() )
3977 GdkColor
*bg
= m_backgroundColour
.GetColor();
3979 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
3980 style
->base
[GTK_STATE_NORMAL
] = *bg
;
3981 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
3982 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
3984 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
3985 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
3986 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
3987 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
3989 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
3990 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
3991 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
3992 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
3994 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
3995 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
3996 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
3997 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4003 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4005 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4008 DoApplyWidgetStyle(style
);
4009 gtk_rc_style_unref(style
);
4012 // Style change may affect GTK+'s size calculation:
4013 InvalidateBestSize();
4016 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4019 gtk_widget_modify_style(m_wxwindow
, style
);
4021 gtk_widget_modify_style(m_widget
, style
);
4024 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4026 wxWindowBase::SetBackgroundStyle(style
);
4028 if (style
== wxBG_STYLE_CUSTOM
)
4030 GdkWindow
*window
= (GdkWindow
*) NULL
;
4032 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4034 window
= GetConnectWidget()->window
;
4038 // Make sure GDK/X11 doesn't refresh the window
4040 gdk_window_set_back_pixmap( window
, None
, False
);
4042 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4045 m_needsStyleChange
= false;
4048 // Do in OnIdle, because the window is not yet available
4049 m_needsStyleChange
= true;
4051 // Don't apply widget style, or we get a grey background
4055 // apply style change (forceStyle=true so that new style is applied
4056 // even if the bg colour changed from valid to wxNullColour):
4057 ApplyWidgetStyle(true);
4062 #if wxUSE_DRAG_AND_DROP
4064 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4066 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4068 GtkWidget
*dnd_widget
= GetConnectWidget();
4070 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4072 if (m_dropTarget
) delete m_dropTarget
;
4073 m_dropTarget
= dropTarget
;
4075 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4078 #endif // wxUSE_DRAG_AND_DROP
4080 GtkWidget
* wxWindowGTK::GetConnectWidget()
4082 GtkWidget
*connect_widget
= m_widget
;
4083 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4085 return connect_widget
;
4088 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4091 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4093 return (window
== m_widget
->window
);
4096 bool wxWindowGTK::SetFont( const wxFont
&font
)
4098 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4100 if (!wxWindowBase::SetFont(font
))
4103 // apply style change (forceStyle=true so that new style is applied
4104 // even if the font changed from valid to wxNullFont):
4105 ApplyWidgetStyle(true);
4110 void wxWindowGTK::DoCaptureMouse()
4112 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4114 GdkWindow
*window
= (GdkWindow
*) NULL
;
4116 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4118 window
= GetConnectWidget()->window
;
4120 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4122 wxCursor
* cursor
= & m_cursor
;
4124 cursor
= wxSTANDARD_CURSOR
;
4126 gdk_pointer_grab( window
, FALSE
,
4128 (GDK_BUTTON_PRESS_MASK
|
4129 GDK_BUTTON_RELEASE_MASK
|
4130 GDK_POINTER_MOTION_HINT_MASK
|
4131 GDK_POINTER_MOTION_MASK
),
4133 cursor
->GetCursor(),
4134 (guint32
)GDK_CURRENT_TIME
);
4135 g_captureWindow
= this;
4136 g_captureWindowHasMouse
= true;
4139 void wxWindowGTK::DoReleaseMouse()
4141 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4143 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4145 g_captureWindow
= (wxWindowGTK
*) NULL
;
4147 GdkWindow
*window
= (GdkWindow
*) NULL
;
4149 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4151 window
= GetConnectWidget()->window
;
4156 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4160 wxWindow
*wxWindowBase::GetCapture()
4162 return (wxWindow
*)g_captureWindow
;
4165 bool wxWindowGTK::IsRetained() const
4170 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4171 int range
, bool refresh
)
4173 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4175 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4177 m_hasScrolling
= true;
4179 if (orient
== wxHORIZONTAL
)
4181 float fpos
= (float)pos
;
4182 float frange
= (float)range
;
4183 float fthumb
= (float)thumbVisible
;
4184 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4185 if (fpos
< 0.0) fpos
= 0.0;
4187 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4188 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4190 SetScrollPos( orient
, pos
, refresh
);
4194 m_oldHorizontalPos
= fpos
;
4196 m_hAdjust
->lower
= 0.0;
4197 m_hAdjust
->upper
= frange
;
4198 m_hAdjust
->value
= fpos
;
4199 m_hAdjust
->step_increment
= 1.0;
4200 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4201 m_hAdjust
->page_size
= fthumb
;
4205 float fpos
= (float)pos
;
4206 float frange
= (float)range
;
4207 float fthumb
= (float)thumbVisible
;
4208 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4209 if (fpos
< 0.0) fpos
= 0.0;
4211 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4212 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4214 SetScrollPos( orient
, pos
, refresh
);
4218 m_oldVerticalPos
= fpos
;
4220 m_vAdjust
->lower
= 0.0;
4221 m_vAdjust
->upper
= frange
;
4222 m_vAdjust
->value
= fpos
;
4223 m_vAdjust
->step_increment
= 1.0;
4224 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4225 m_vAdjust
->page_size
= fthumb
;
4228 if (orient
== wxHORIZONTAL
)
4229 g_signal_emit_by_name (m_hAdjust
, "changed");
4231 g_signal_emit_by_name (m_vAdjust
, "changed");
4234 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4236 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4237 gpointer fn
= orient
== wxHORIZONTAL
4238 ? (gpointer
) gtk_window_hscroll_callback
4239 : (gpointer
) gtk_window_vscroll_callback
;
4241 g_signal_handlers_disconnect_by_func (adj
, fn
, this);
4242 g_signal_emit_by_name (adj
, "value_changed");
4243 g_signal_connect (adj
, "value_changed", G_CALLBACK (fn
), this);
4246 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4248 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4249 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4251 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4253 float fpos
= (float)pos
;
4254 if (fpos
> adj
->upper
- adj
->page_size
)
4255 fpos
= adj
->upper
- adj
->page_size
;
4258 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4260 if (fabs(fpos
-adj
->value
) < 0.2)
4264 if ( m_wxwindow
->window
)
4269 int wxWindowGTK::GetScrollThumb( int orient
) const
4271 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4273 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4275 if (orient
== wxHORIZONTAL
)
4276 return (int)(m_hAdjust
->page_size
+0.5);
4278 return (int)(m_vAdjust
->page_size
+0.5);
4281 int wxWindowGTK::GetScrollPos( int orient
) const
4283 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4285 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4287 if (orient
== wxHORIZONTAL
)
4288 return (int)(m_hAdjust
->value
+0.5);
4290 return (int)(m_vAdjust
->value
+0.5);
4293 int wxWindowGTK::GetScrollRange( int orient
) const
4295 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4297 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4299 if (orient
== wxHORIZONTAL
)
4300 return (int)(m_hAdjust
->upper
+0.5);
4302 return (int)(m_vAdjust
->upper
+0.5);
4305 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4307 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4309 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4311 // No scrolling requested.
4312 if ((dx
== 0) && (dy
== 0)) return;
4314 m_clipPaintRegion
= true;
4316 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4318 m_clipPaintRegion
= false;
4321 void wxWindowGTK::SetWindowStyleFlag( long style
)
4323 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4324 wxWindowBase::SetWindowStyleFlag(style
);
4327 // Find the wxWindow at the current mouse position, also returning the mouse
4329 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4331 pt
= wxGetMousePosition();
4332 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4336 // Get the current mouse position.
4337 wxPoint
wxGetMousePosition()
4339 /* This crashes when used within wxHelpContext,
4340 so we have to use the X-specific implementation below.
4342 GdkModifierType *mask;
4343 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4345 return wxPoint(x, y);
4349 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4351 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4352 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4353 Window rootReturn
, childReturn
;
4354 int rootX
, rootY
, winX
, winY
;
4355 unsigned int maskReturn
;
4357 XQueryPointer (display
,
4361 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4362 return wxPoint(rootX
, rootY
);
4366 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4367 void wxAddGrab(wxWindow
* window
)
4369 gtk_grab_add( (GtkWidget
*) window
->GetHandle() );
4372 void wxRemoveGrab(wxWindow
* window
)
4374 gtk_grab_remove( (GtkWidget
*) window
->GetHandle() );
4377 // ----------------------------------------------------------------------------
4379 // ----------------------------------------------------------------------------
4381 class wxWinModule
: public wxModule
4388 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4391 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4393 bool wxWinModule::OnInit()
4395 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4396 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4401 void wxWinModule::OnExit()
4404 gdk_gc_unref( g_eraseGC
);