1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
19 #define XWarpPointer XWARPPOINTER
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
26 #include "wx/layout.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
32 #if wxUSE_DRAG_AND_DROP
37 #include "wx/tooltip.h"
45 #include "wx/textctrl.h"
49 #include "wx/statusbr.h"
51 #include "wx/settings.h"
53 #include "wx/fontutil.h"
56 #include "wx/thread.h"
62 #include "wx/gtk/private.h"
63 #include <gdk/gdkprivate.h>
64 #include <gdk/gdkkeysyms.h>
68 #include <gtk/gtkprivate.h>
70 #include "wx/gtk/win_gtk.h"
73 #include <pango/pangox.h>
77 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
79 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
89 extern GtkContainerClass
*pizza_parent_class
;
92 //-----------------------------------------------------------------------------
93 // documentation on internals
94 //-----------------------------------------------------------------------------
97 I have been asked several times about writing some documentation about
98 the GTK port of wxWidgets, especially its internal structures. Obviously,
99 you cannot understand wxGTK without knowing a little about the GTK, but
100 some more information about what the wxWindow, which is the base class
101 for all other window classes, does seems required as well.
105 What does wxWindow do? It contains the common interface for the following
106 jobs of its descendants:
108 1) Define the rudimentary behaviour common to all window classes, such as
109 resizing, intercepting user input (so as to make it possible to use these
110 events for special purposes in a derived class), window names etc.
112 2) Provide the possibility to contain and manage children, if the derived
113 class is allowed to contain children, which holds true for those window
114 classes which do not display a native GTK widget. To name them, these
115 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
116 work classes are a special case and are handled a bit differently from
117 the rest. The same holds true for the wxNotebook class.
119 3) Provide the possibility to draw into a client area of a window. This,
120 too, only holds true for classes that do not display a native GTK widget
123 4) Provide the entire mechanism for scrolling widgets. This actual inter-
124 face for this is usually in wxScrolledWindow, but the GTK implementation
127 5) A multitude of helper or extra methods for special purposes, such as
128 Drag'n'Drop, managing validators etc.
130 6) Display a border (sunken, raised, simple or none).
132 Normally one might expect, that one wxWidgets window would always correspond
133 to one GTK widget. Under GTK, there is no such allround widget that has all
134 the functionality. Moreover, the GTK defines a client area as a different
135 widget from the actual widget you are handling. Last but not least some
136 special classes (e.g. wxFrame) handle different categories of widgets and
137 still have the possibility to draw something in the client area.
138 It was therefore required to write a special purpose GTK widget, that would
139 represent a client area in the sense of wxWidgets capable to do the jobs
140 2), 3) and 4). I have written this class and it resides in win_gtk.c of
143 All windows must have a widget, with which they interact with other under-
144 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
145 thw wxWindow class has a member variable called m_widget which holds a
146 pointer to this widget. When the window class represents a GTK native widget,
147 this is (in most cases) the only GTK widget the class manages. E.g. the
148 wxStaticText class handles only a GtkLabel widget a pointer to which you
149 can find in m_widget (defined in wxWindow)
151 When the class has a client area for drawing into and for containing children
152 it has to handle the client area widget (of the type GtkPizza, defined in
153 win_gtk.c), but there could be any number of widgets, handled by a class
154 The common rule for all windows is only, that the widget that interacts with
155 the rest of GTK must be referenced in m_widget and all other widgets must be
156 children of this widget on the GTK level. The top-most widget, which also
157 represents the client area, must be in the m_wxwindow field and must be of
160 As I said, the window classes that display a GTK native widget only have
161 one widget, so in the case of e.g. the wxButton class m_widget holds a
162 pointer to a GtkButton widget. But windows with client areas (for drawing
163 and children) have a m_widget field that is a pointer to a GtkScrolled-
164 Window and a m_wxwindow field that is pointer to a GtkPizza and this
165 one is (in the GTK sense) a child of the GtkScrolledWindow.
167 If the m_wxwindow field is set, then all input to this widget is inter-
168 cepted and sent to the wxWidgets class. If not, all input to the widget
169 that gets pointed to by m_widget gets intercepted and sent to the class.
173 The design of scrolling in wxWidgets is markedly different from that offered
174 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
175 clicking on a scrollbar belonging to scrolled window will inevitably move
176 the window. In wxWidgets, the scrollbar will only emit an event, send this
177 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
178 which actually moves the window and its subchildren. Note that GtkPizza
179 memorizes how much it has been scrolled but that wxWidgets forgets this
180 so that the two coordinates systems have to be kept in synch. This is done
181 in various places using the pizza->xoffset and pizza->yoffset values.
185 Singularily the most broken code in GTK is the code that is supposes to
186 inform subwindows (child windows) about new positions. Very often, duplicate
187 events are sent without changes in size or position, equally often no
188 events are sent at all (All this is due to a bug in the GtkContainer code
189 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
190 GTK's own system and it simply waits for size events for toplevel windows
191 and then iterates down the respective size events to all window. This has
192 the disadvantage, that windows might get size events before the GTK widget
193 actually has the reported size. This doesn't normally pose any problem, but
194 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
195 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
196 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
197 window that is used for OpenGl output really has that size (as reported by
202 If someone at some point of time feels the immense desire to have a look at,
203 change or attempt to optimse the Refresh() logic, this person will need an
204 intimate understanding of what a "draw" and what an "expose" events are and
205 what there are used for, in particular when used in connection with GTK's
206 own windowless widgets. Beware.
210 Cursors, too, have been a constant source of pleasure. The main difficulty
211 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
212 for the parent. To prevent this from doing too much harm, I use idle time
213 to set the cursor over and over again, starting from the toplevel windows
214 and ending with the youngest generation (speaking of parent and child windows).
215 Also don't forget that cursors (like much else) are connected to GdkWindows,
216 not GtkWidgets and that the "window" field of a GtkWidget might very well
217 point to the GdkWindow of the parent widget (-> "window less widget") and
218 that the two obviously have very different meanings.
222 //-----------------------------------------------------------------------------
224 //-----------------------------------------------------------------------------
226 extern wxList wxPendingDelete
;
227 extern bool g_blockEventsOnDrag
;
228 extern bool g_blockEventsOnScroll
;
229 extern wxCursor g_globalCursor
;
231 static GdkGC
*g_eraseGC
= NULL
;
233 // mouse capture state: the window which has it and if the mouse is currently
235 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
236 static bool g_captureWindowHasMouse
= FALSE
;
238 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
240 // the last window which had the focus - this is normally never NULL (except
241 // if we never had focus at all) as even when g_focusWindow is NULL it still
242 // keeps its previous value
243 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
245 // the frame that is currently active (i.e. its child has focus). It is
246 // used to generate wxActivateEvents
247 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
248 static bool g_activeFrameLostFocus
= FALSE
;
250 // If a window get the focus set but has not been realized
251 // yet, defer setting the focus to idle time.
252 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
254 // if we detect that the app has got/lost the focus, we set this variable to
255 // either TRUE or FALSE and an activate event will be sent during the next
256 // OnIdle() call and it is reset to -1: this value means that we shouldn't
257 // send any activate events at all
258 static int g_sendActivateEvent
= -1;
260 // hack: we need something to pass to gtk_menu_popup, so we store the time of
261 // the last click here
262 static guint32 gs_timeLastClick
= 0;
264 extern bool g_mainThreadLocked
;
266 //-----------------------------------------------------------------------------
268 //-----------------------------------------------------------------------------
273 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
275 # define DEBUG_MAIN_THREAD
278 #define DEBUG_MAIN_THREAD
281 // the trace mask used for the focus debugging messages
282 #define TRACE_FOCUS _T("focus")
284 //-----------------------------------------------------------------------------
285 // missing gdk functions
286 //-----------------------------------------------------------------------------
289 gdk_window_warp_pointer (GdkWindow
*window
,
294 GdkWindowPrivate
*priv
;
298 window
= GDK_ROOT_PARENT();
301 if (!GDK_WINDOW_DESTROYED(window
))
303 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
304 None
, /* not source window -> move from anywhere */
305 GDK_WINDOW_XID(window
), /* dest window */
306 0, 0, 0, 0, /* not source window -> move from anywhere */
310 priv
= (GdkWindowPrivate
*) window
;
312 if (!priv
->destroyed
)
314 XWarpPointer (priv
->xdisplay
,
315 None
, /* not source window -> move from anywhere */
316 priv
->xwindow
, /* dest window */
317 0, 0, 0, 0, /* not source window -> move from anywhere */
323 //-----------------------------------------------------------------------------
325 //-----------------------------------------------------------------------------
327 extern void wxapp_install_idle_handler();
328 extern bool g_isIdle
;
330 //-----------------------------------------------------------------------------
331 // local code (see below)
332 //-----------------------------------------------------------------------------
334 // returns the child of win which currently has focus or NULL if not found
336 // Note: can't be static, needed by textctrl.cpp.
337 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
339 wxWindow
*winFocus
= wxWindowGTK
::FindFocus();
341 return (wxWindow
*)NULL
;
343 if ( winFocus
== win
)
344 return (wxWindow
*)win
;
346 for ( wxWindowList
::compatibility_iterator node
= win
->GetChildren().GetFirst();
348 node
= node
->GetNext() )
350 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
355 return (wxWindow
*)NULL
;
358 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
360 // wxUniversal widgets draw the borders and scrollbars themselves
361 #ifndef __WXUNIVERSAL__
368 if (win
->m_hasScrolling
)
370 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
372 GtkRequisition vscroll_req
;
373 vscroll_req
.width
= 2;
374 vscroll_req
.height
= 2;
375 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
376 (scroll_window
->vscrollbar
, &vscroll_req
);
378 GtkRequisition hscroll_req
;
379 hscroll_req
.width
= 2;
380 hscroll_req
.height
= 2;
381 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
382 (scroll_window
->hscrollbar
, &hscroll_req
);
384 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
386 if (scroll_window
->vscrollbar_visible
)
388 dw
+= vscroll_req
.width
;
389 dw
+= scroll_class
->scrollbar_spacing
;
392 if (scroll_window
->hscrollbar_visible
)
394 dh
+= hscroll_req
.height
;
395 dh
+= scroll_class
->scrollbar_spacing
;
401 if (GTK_WIDGET_NO_WINDOW (widget
))
403 dx
+= widget
->allocation
.x
;
404 dy
+= widget
->allocation
.y
;
407 if (win
->HasFlag(wxRAISED_BORDER
))
409 gtk_draw_shadow( widget
->style
,
414 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
418 if (win
->HasFlag(wxSUNKEN_BORDER
))
420 gtk_draw_shadow( widget
->style
,
425 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
429 if (win
->HasFlag(wxSIMPLE_BORDER
))
432 gc
= gdk_gc_new( widget
->window
);
433 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
434 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
436 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
440 #endif // __WXUNIVERSAL__
443 //-----------------------------------------------------------------------------
444 // "expose_event" of m_widget
445 //-----------------------------------------------------------------------------
447 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
449 if (gdk_event
->count
> 0) return FALSE
;
451 draw_frame( widget
, win
);
455 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
461 //-----------------------------------------------------------------------------
462 // "draw" of m_widget
463 //-----------------------------------------------------------------------------
467 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
469 draw_frame( widget
, win
);
474 //-----------------------------------------------------------------------------
475 // "size_request" of m_widget
476 //-----------------------------------------------------------------------------
478 // make it extern because wxStatitText needs to disconnect this one
480 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
481 GtkRequisition
*requisition
,
485 win
->GetSize( &w
, &h
);
491 requisition
->height
= h
;
492 requisition
->width
= w
;
495 //-----------------------------------------------------------------------------
496 // "expose_event" of m_wxwindow
497 //-----------------------------------------------------------------------------
499 static int gtk_window_expose_callback( GtkWidget
*widget
,
500 GdkEventExpose
*gdk_event
,
506 wxapp_install_idle_handler();
509 // This callback gets called in drawing-idle time under
510 // GTK 2.0, so we don't need to defer anything to idle
513 GtkPizza
*pizza
= GTK_PIZZA( widget
);
514 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
519 wxPrintf( wxT("OnExpose from ") );
520 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
521 wxPrintf( win
->GetClassInfo()->GetClassName() );
522 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
523 (int)gdk_event
->area
.y
,
524 (int)gdk_event
->area
.width
,
525 (int)gdk_event
->area
.height
);
530 win
->m_wxwindow
->style
,
534 (GdkRectangle
*) NULL
,
536 (char *)"button", // const_cast
541 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
543 win
->GtkSendPaintEvents();
546 // Let parent window draw window less widgets
547 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
549 // This gets called immediately after an expose event
550 // under GTK 1.2 so we collect the calls and wait for
551 // the idle handler to pick things up.
553 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
555 gdk_event
->area
.width
,
556 gdk_event
->area
.height
);
557 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
559 gdk_event
->area
.width
,
560 gdk_event
->area
.height
);
562 // Actual redrawing takes place in idle time.
569 //-----------------------------------------------------------------------------
570 // "event" of m_wxwindow
571 //-----------------------------------------------------------------------------
573 // GTK thinks it is clever and filters out a certain amount of "unneeded"
574 // expose events. We need them, of course, so we override the main event
575 // procedure in GtkWidget by giving our own handler for all system events.
576 // There, we look for expose events ourselves whereas all other events are
579 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
580 GdkEventExpose
*event
,
583 if (event
->type
== GDK_EXPOSE
)
585 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
592 //-----------------------------------------------------------------------------
593 // "draw" of m_wxwindow
594 //-----------------------------------------------------------------------------
598 // This callback is a complete replacement of the gtk_pizza_draw() function,
599 // which is disabled.
601 static void gtk_window_draw_callback( GtkWidget
*widget
,
608 wxapp_install_idle_handler();
610 // if there are any children we must refresh everything
613 if ( !win
->HasFlag(wxFULL_REPAINT_ON_RESIZE
) &&
614 win
->GetChildren().IsEmpty() )
622 wxPrintf( wxT("OnDraw from ") );
623 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
624 wxPrintf( win
->GetClassInfo()->GetClassName() );
625 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
632 #ifndef __WXUNIVERSAL__
633 GtkPizza
*pizza
= GTK_PIZZA (widget
);
635 if (win
->GetThemeEnabled())
637 wxWindow
*parent
= win
->GetParent();
638 while (parent
&& !parent
->IsTopLevel())
639 parent
= parent
->GetParent();
643 gtk_paint_flat_box (parent
->m_widget
->style
,
654 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
655 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
657 // Update immediately, not in idle time.
660 #ifndef __WXUNIVERSAL__
661 // Redraw child widgets
662 GList
*children
= pizza
->children
;
665 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
666 children
= children
->next
;
668 GdkRectangle child_area
;
669 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
671 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
679 //-----------------------------------------------------------------------------
680 // "key_press_event" from any window
681 //-----------------------------------------------------------------------------
683 // set WXTRACE to this to see the key event codes on the console
684 #define TRACE_KEYS _T("keyevent")
686 // translates an X key symbol to WXK_XXX value
688 // if isChar is true it means that the value returned will be used for EVT_CHAR
689 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
690 // for example, while if it is false it means that the value is going to be
691 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
693 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
699 // Shift, Control and Alt don't generate the CHAR events at all
702 key_code
= isChar ?
0 : WXK_SHIFT
;
706 key_code
= isChar ?
0 : WXK_CONTROL
;
714 key_code
= isChar ?
0 : WXK_ALT
;
717 // neither do the toggle modifies
718 case GDK_Scroll_Lock
:
719 key_code
= isChar ?
0 : WXK_SCROLL
;
723 key_code
= isChar ?
0 : WXK_CAPITAL
;
727 key_code
= isChar ?
0 : WXK_NUMLOCK
;
731 // various other special keys
744 case GDK_ISO_Left_Tab
:
751 key_code
= WXK_RETURN
;
755 key_code
= WXK_CLEAR
;
759 key_code
= WXK_PAUSE
;
763 key_code
= WXK_SELECT
;
767 key_code
= WXK_PRINT
;
771 key_code
= WXK_EXECUTE
;
775 key_code
= WXK_ESCAPE
;
778 // cursor and other extended keyboard keys
780 key_code
= WXK_DELETE
;
796 key_code
= WXK_RIGHT
;
803 case GDK_Prior
: // == GDK_Page_Up
804 key_code
= WXK_PRIOR
;
807 case GDK_Next
: // == GDK_Page_Down
820 key_code
= WXK_INSERT
;
835 key_code
= (isChar ?
'0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
839 key_code
= isChar ?
' ' : WXK_NUMPAD_SPACE
;
843 key_code
= isChar ? WXK_TAB
: WXK_NUMPAD_TAB
;
847 key_code
= isChar ? WXK_RETURN
: WXK_NUMPAD_ENTER
;
851 key_code
= isChar ? WXK_F1
: WXK_NUMPAD_F1
;
855 key_code
= isChar ? WXK_F2
: WXK_NUMPAD_F2
;
859 key_code
= isChar ? WXK_F3
: WXK_NUMPAD_F3
;
863 key_code
= isChar ? WXK_F4
: WXK_NUMPAD_F4
;
867 key_code
= isChar ? WXK_HOME
: WXK_NUMPAD_HOME
;
871 key_code
= isChar ? WXK_LEFT
: WXK_NUMPAD_LEFT
;
875 key_code
= isChar ? WXK_UP
: WXK_NUMPAD_UP
;
879 key_code
= isChar ? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
883 key_code
= isChar ? WXK_DOWN
: WXK_NUMPAD_DOWN
;
886 case GDK_KP_Prior
: // == GDK_KP_Page_Up
887 key_code
= isChar ? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
890 case GDK_KP_Next
: // == GDK_KP_Page_Down
891 key_code
= isChar ? WXK_NEXT
: WXK_NUMPAD_NEXT
;
895 key_code
= isChar ? WXK_END
: WXK_NUMPAD_END
;
899 key_code
= isChar ? WXK_HOME
: WXK_NUMPAD_BEGIN
;
903 key_code
= isChar ? WXK_INSERT
: WXK_NUMPAD_INSERT
;
907 key_code
= isChar ? WXK_DELETE
: WXK_NUMPAD_DELETE
;
911 key_code
= isChar ?
'=' : WXK_NUMPAD_EQUAL
;
914 case GDK_KP_Multiply
:
915 key_code
= isChar ?
'*' : WXK_NUMPAD_MULTIPLY
;
919 key_code
= isChar ?
'+' : WXK_NUMPAD_ADD
;
922 case GDK_KP_Separator
:
923 // FIXME: what is this?
924 key_code
= isChar ?
'.' : WXK_NUMPAD_SEPARATOR
;
927 case GDK_KP_Subtract
:
928 key_code
= isChar ?
'-' : WXK_NUMPAD_SUBTRACT
;
932 key_code
= isChar ?
'.' : WXK_NUMPAD_DECIMAL
;
936 key_code
= isChar ?
'/' : WXK_NUMPAD_DIVIDE
;
953 key_code
= WXK_F1
+ keysym
- GDK_F1
;
963 static inline bool wxIsAsciiKeysym(KeySym ks
)
969 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
971 GdkEventKey
*gdk_event
)
973 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
974 // but only event->keyval which is quite useless to us, so remember
975 // the last character from GDK_KEY_PRESS and reuse it as last resort
977 // NB: should be MT-safe as we're always called from the main thread only
982 } s_lastKeyPress
= { 0, 0 };
984 KeySym keysym
= gdk_event
->keyval
;
986 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
987 event
.GetEventType() == wxEVT_KEY_UP ?
_T("release")
991 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
995 // do we have the translation or is it a plain ASCII character?
996 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
998 // we should use keysym if it is ASCII as X does some translations
999 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1000 // which we don't want here (but which we do use for OnChar())
1001 if ( !wxIsAsciiKeysym(keysym
) )
1003 keysym
= (KeySym
)gdk_event
->string
[0];
1006 // we want to always get the same key code when the same key is
1007 // pressed regardless of the state of the modifies, i.e. on a
1008 // standard US keyboard pressing '5' or '%' ('5' key with
1009 // Shift) should result in the same key code in OnKeyDown():
1010 // '5' (although OnChar() will get either '5' or '%').
1012 // to do it we first translate keysym to keycode (== scan code)
1013 // and then back but always using the lower register
1014 Display
*dpy
= (Display
*)wxGetDisplay();
1015 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1017 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1019 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1021 // use the normalized, i.e. lower register, keysym if we've
1023 key_code
= keysymNormalized ? keysymNormalized
: keysym
;
1025 // as explained above, we want to have lower register key codes
1026 // normally but for the letter keys we want to have the upper ones
1028 // NB: don't use XConvertCase() here, we want to do it for letters
1030 key_code
= toupper(key_code
);
1032 else // non ASCII key, what to do?
1034 // by default, ignore it
1037 // but if we have cached information from the last KEY_PRESS
1038 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1041 if ( keysym
== s_lastKeyPress
.keysym
)
1043 key_code
= s_lastKeyPress
.keycode
;
1048 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1050 // remember it to be reused for KEY_UP event later
1051 s_lastKeyPress
.keysym
= keysym
;
1052 s_lastKeyPress
.keycode
= key_code
;
1056 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1058 // sending unknown key events doesn't really make sense
1062 // now fill all the other fields
1065 GdkModifierType state
;
1066 if (gdk_event
->window
)
1067 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1069 event
.SetTimestamp( gdk_event
->time
);
1070 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1071 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1072 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1073 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1074 event
.m_keyCode
= key_code
;
1075 event
.m_scanCode
= gdk_event
->keyval
;
1076 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1077 event
.m_rawFlags
= 0;
1080 event
.SetEventObject( win
);
1086 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1087 GdkEventKey
*gdk_event
,
1093 wxapp_install_idle_handler();
1097 if (g_blockEventsOnDrag
)
1101 if (win
->m_imContext
)
1103 // In GTK 2.0, we need to hand over the key event to an input method
1104 // and the IM will emit a "commit" event containing the actual utf8
1105 // character. In that case the EVT_CHAR events will be sent from
1107 if ( gtk_im_context_filter_keypress(win
->m_imContext
, gdk_event
) )
1112 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1113 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1115 // unknown key pressed, ignore (the event would be useless anyhow)
1119 // Emit KEY_DOWN event
1120 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1125 wxWindowGTK
*ancestor
= win
;
1128 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1131 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1132 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1135 if (ancestor
->IsTopLevel())
1137 ancestor
= ancestor
->GetParent();
1140 #endif // wxUSE_ACCEL
1142 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1143 // will only be sent if it is not in an accelerator table.
1147 KeySym keysym
= gdk_event
->keyval
;
1148 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1149 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1152 if ( gdk_event
->length
== 1 )
1154 key_code
= (unsigned char)gdk_event
->string
[0];
1156 else if ( wxIsAsciiKeysym(keysym
) )
1159 key_code
= (unsigned char)keysym
;
1165 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1167 event
.m_keyCode
= key_code
;
1169 // Implement OnCharHook by checking ancesteror top level windows
1170 wxWindow
*parent
= win
;
1171 while (parent
&& !parent
->IsTopLevel())
1172 parent
= parent
->GetParent();
1175 event
.SetEventType( wxEVT_CHAR_HOOK
);
1176 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1181 event
.SetEventType(wxEVT_CHAR
);
1182 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1187 // win is a control: tab can be propagated up
1189 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1190 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1191 // have this style, yet choose not to process this particular TAB in which
1192 // case TAB must still work as a navigational character
1193 // JS: enabling again to make consistent with other platforms
1194 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1195 // navigation behaviour)
1197 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1199 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1201 wxNavigationKeyEvent new_event
;
1202 new_event
.SetEventObject( win
->GetParent() );
1203 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1204 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1205 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1206 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1207 new_event
.SetCurrentFocus( win
);
1208 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1211 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1213 (gdk_event
->keyval
== GDK_Escape
) )
1215 // however only do it if we have a Cancel button in the dialog,
1216 // otherwise the user code may get confused by the events from a
1217 // non-existing button and, worse, a wxButton might get button event
1218 // from another button which is not really expected
1219 wxWindow
*winForCancel
= win
,
1221 while ( winForCancel
)
1223 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1226 // found a cancel button
1230 if ( winForCancel
->IsTopLevel() )
1232 // no need to look further
1236 // maybe our parent has a cancel button?
1237 winForCancel
= winForCancel
->GetParent();
1242 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1243 event
.SetEventObject(btnCancel
);
1244 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1250 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1258 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1264 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1267 event
.m_uniChar
= g_utf8_get_char( str
);
1269 // Backward compatible for ISO-8859
1270 if (event
.m_uniChar
< 256)
1271 event
.m_keyCode
= event
.m_uniChar
;
1274 unistr
[0] = g_utf8_get_char(str
);
1276 wxCharBuffer
ansistr(wxConvLocal
.cWC2MB(unistr
));
1277 // We cannot handle characters that cannot be represented in
1278 // current locale's charset in non-Unicode mode:
1279 if (ansistr
.data() == NULL
) return;
1281 event
.m_keyCode
= ansistr
[0u];
1285 // TODO: We still need to set all the extra attributes of the
1286 // event, modifiers and such...
1289 // Implement OnCharHook by checking ancestor top level windows
1290 wxWindow
*parent
= window
;
1291 while (parent
&& !parent
->IsTopLevel())
1292 parent
= parent
->GetParent();
1295 event
.SetEventType( wxEVT_CHAR_HOOK
);
1296 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1301 event
.SetEventType(wxEVT_CHAR
);
1302 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1308 //-----------------------------------------------------------------------------
1309 // "key_release_event" from any window
1310 //-----------------------------------------------------------------------------
1312 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1313 GdkEventKey
*gdk_event
,
1319 wxapp_install_idle_handler();
1324 if (g_blockEventsOnDrag
)
1327 wxKeyEvent
event( wxEVT_KEY_UP
);
1328 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1330 // unknown key pressed, ignore (the event would be useless anyhow
1334 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1337 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1341 // ============================================================================
1343 // ============================================================================
1345 // ----------------------------------------------------------------------------
1346 // mouse event processing helpers
1347 // ----------------------------------------------------------------------------
1349 // init wxMouseEvent with the info from GdkEventXXX struct
1350 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1351 wxMouseEvent
& event
,
1354 event
.SetTimestamp( gdk_event
->time
);
1355 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1356 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1357 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1358 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1359 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1360 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1361 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1362 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1364 event
.m_linesPerAction
= 3;
1365 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1366 event
.m_wheelRotation
= 120;
1367 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1368 event
.m_wheelRotation
= -120;
1371 wxPoint pt
= win
->GetClientAreaOrigin();
1372 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1373 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1375 event
.SetEventObject( win
);
1376 event
.SetId( win
->GetId() );
1377 event
.SetTimestamp( gdk_event
->time
);
1380 static void AdjustEventButtonState(wxMouseEvent
& event
)
1382 // GDK reports the old state of the button for a button press event, but
1383 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1384 // for a LEFT_DOWN event, not FALSE, so we will invert
1385 // left/right/middleDown for the corresponding click events
1387 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1388 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1389 (event
.GetEventType() == wxEVT_LEFT_UP
))
1391 event
.m_leftDown
= !event
.m_leftDown
;
1395 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1396 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1397 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1399 event
.m_middleDown
= !event
.m_middleDown
;
1403 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1404 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1405 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1407 event
.m_rightDown
= !event
.m_rightDown
;
1412 // find the window to send the mouse event too
1414 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1419 if (win
->m_wxwindow
)
1421 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1422 xx
+= pizza
->xoffset
;
1423 yy
+= pizza
->yoffset
;
1426 wxWindowList
::compatibility_iterator node
= win
->GetChildren().GetFirst();
1429 wxWindowGTK
*child
= node
->GetData();
1431 node
= node
->GetNext();
1432 if (!child
->IsShown())
1435 if (child
->IsTransparentForMouse())
1437 // wxStaticBox is transparent in the box itself
1438 int xx1
= child
->m_x
;
1439 int yy1
= child
->m_y
;
1440 int xx2
= child
->m_x
+ child
->m_width
;
1441 int yy2
= child
->m_y
+ child
->m_height
;
1444 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1446 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1448 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1450 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1461 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1462 (child
->m_x
<= xx
) &&
1463 (child
->m_y
<= yy
) &&
1464 (child
->m_x
+child
->m_width
>= xx
) &&
1465 (child
->m_y
+child
->m_height
>= yy
))
1478 //-----------------------------------------------------------------------------
1479 // "button_press_event"
1480 //-----------------------------------------------------------------------------
1482 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1483 GdkEventButton
*gdk_event
,
1489 wxapp_install_idle_handler();
1492 wxPrintf( wxT("1) OnButtonPress from ") );
1493 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1494 wxPrintf( win->GetClassInfo()->GetClassName() );
1495 wxPrintf( wxT(".\n") );
1497 if (!win
->m_hasVMT
) return FALSE
;
1498 if (g_blockEventsOnDrag
) return TRUE
;
1499 if (g_blockEventsOnScroll
) return TRUE
;
1501 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1503 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1505 gtk_widget_grab_focus( win
->m_wxwindow
);
1507 wxPrintf( wxT("GrabFocus from ") );
1508 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1509 wxPrintf( win->GetClassInfo()->GetClassName() );
1510 wxPrintf( wxT(".\n") );
1514 // GDK sends surplus button down event
1515 // before a double click event. We
1516 // need to filter these out.
1517 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1519 GdkEvent
*peek_event
= gdk_event_peek();
1522 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1523 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1525 gdk_event_free( peek_event
);
1530 gdk_event_free( peek_event
);
1535 wxEventType event_type
= wxEVT_NULL
;
1537 // GdkDisplay is a GTK+ 2.2.0 thing
1538 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1539 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1540 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1542 // Reset GDK internal timestamp variables in order to disable GDK
1543 // triple click events. GDK will then next time believe no button has
1544 // been clicked just before, and send a normal button click event.
1545 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1546 display
->button_click_time
[1] = 0;
1547 display
->button_click_time
[0] = 0;
1551 if (gdk_event
->button
== 1)
1553 // note that GDK generates triple click events which are not supported
1554 // by wxWidgets but still have to be passed to the app as otherwise
1555 // clicks would simply go missing
1556 switch (gdk_event
->type
)
1558 // we shouldn't get triple clicks at all for GTK2 because we
1559 // suppress them artificially using the code above but we still
1560 // should map them to something for GTK1 and not just ignore them
1561 // as this would lose clicks
1562 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1563 case GDK_BUTTON_PRESS
:
1564 event_type
= wxEVT_LEFT_DOWN
;
1567 case GDK_2BUTTON_PRESS
:
1568 event_type
= wxEVT_LEFT_DCLICK
;
1572 // just to silence gcc warnings
1576 else if (gdk_event
->button
== 2)
1578 switch (gdk_event
->type
)
1580 case GDK_3BUTTON_PRESS
:
1581 case GDK_BUTTON_PRESS
:
1582 event_type
= wxEVT_MIDDLE_DOWN
;
1585 case GDK_2BUTTON_PRESS
:
1586 event_type
= wxEVT_MIDDLE_DCLICK
;
1593 else if (gdk_event
->button
== 3)
1595 switch (gdk_event
->type
)
1597 case GDK_3BUTTON_PRESS
:
1598 case GDK_BUTTON_PRESS
:
1599 event_type
= wxEVT_RIGHT_DOWN
;
1602 case GDK_2BUTTON_PRESS
:
1603 event_type
= wxEVT_RIGHT_DCLICK
;
1610 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1612 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1614 event_type
= wxEVT_MOUSEWHEEL
;
1618 if ( event_type
== wxEVT_NULL
)
1620 // unknown mouse button or click type
1624 wxMouseEvent
event( event_type
);
1625 InitMouseEvent( win
, event
, gdk_event
);
1627 AdjustEventButtonState(event
);
1629 // wxListBox actually get mouse events from the item, so we need to give it
1630 // a chance to correct this
1631 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1633 // find the correct window to send the event too: it may be a different one
1634 // from the one which got it at GTK+ level because some control don't have
1635 // their own X window and thus cannot get any events.
1636 if ( !g_captureWindow
)
1637 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1639 gs_timeLastClick
= gdk_event
->time
;
1642 wxPrintf( wxT("2) OnButtonPress from ") );
1643 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1644 wxPrintf( win->GetClassInfo()->GetClassName() );
1645 wxPrintf( wxT(".\n") );
1649 if (event_type
== wxEVT_LEFT_DCLICK
)
1651 // GTK 1.2 crashes when intercepting double
1652 // click events from both wxSpinButton and
1654 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1656 // Just disable this event for now.
1662 if (win
->GetEventHandler()->ProcessEvent( event
))
1664 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1671 //-----------------------------------------------------------------------------
1672 // "button_release_event"
1673 //-----------------------------------------------------------------------------
1675 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1676 GdkEventButton
*gdk_event
,
1682 wxapp_install_idle_handler();
1684 if (!win
->m_hasVMT
) return FALSE
;
1685 if (g_blockEventsOnDrag
) return FALSE
;
1686 if (g_blockEventsOnScroll
) return FALSE
;
1688 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1690 wxEventType event_type
= wxEVT_NULL
;
1692 switch (gdk_event
->button
)
1695 event_type
= wxEVT_LEFT_UP
;
1699 event_type
= wxEVT_MIDDLE_UP
;
1703 event_type
= wxEVT_RIGHT_UP
;
1707 // unknwon button, don't process
1711 wxMouseEvent
event( event_type
);
1712 InitMouseEvent( win
, event
, gdk_event
);
1714 AdjustEventButtonState(event
);
1716 // same wxListBox hack as above
1717 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1719 if ( event_type
== wxEVT_RIGHT_UP
)
1721 // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
1724 // (a) it's a command event and so is propagated to the parent
1725 // (b) under MSW it can be generated from kbd too
1726 // (c) it uses screen coords (because of (a))
1727 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1729 win
->ClientToScreen(event
.GetPosition()));
1730 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1733 if ( !g_captureWindow
)
1734 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1736 if (win
->GetEventHandler()->ProcessEvent( event
))
1738 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1745 //-----------------------------------------------------------------------------
1746 // "motion_notify_event"
1747 //-----------------------------------------------------------------------------
1749 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1750 GdkEventMotion
*gdk_event
,
1756 wxapp_install_idle_handler();
1758 if (!win
->m_hasVMT
) return FALSE
;
1759 if (g_blockEventsOnDrag
) return FALSE
;
1760 if (g_blockEventsOnScroll
) return FALSE
;
1762 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1764 if (gdk_event
->is_hint
)
1768 GdkModifierType state
;
1769 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1775 printf( "OnMotion from " );
1776 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1777 printf( win->GetClassInfo()->GetClassName() );
1781 wxMouseEvent
event( wxEVT_MOTION
);
1782 InitMouseEvent(win
, event
, gdk_event
);
1784 if ( g_captureWindow
)
1786 // synthetize a mouse enter or leave event if needed
1787 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1788 // This seems to be necessary and actually been added to
1789 // GDK itself in version 2.0.X
1792 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1793 if ( hasMouse
!= g_captureWindowHasMouse
)
1795 // the mouse changed window
1796 g_captureWindowHasMouse
= hasMouse
;
1798 wxMouseEvent
event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1799 : wxEVT_LEAVE_WINDOW
);
1800 InitMouseEvent(win
, event
, gdk_event
);
1801 event
.SetEventObject(win
);
1802 win
->GetEventHandler()->ProcessEvent(event
);
1807 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1810 if (win
->GetEventHandler()->ProcessEvent( event
))
1812 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1820 //-----------------------------------------------------------------------------
1821 // "mouse_wheel_event"
1822 //-----------------------------------------------------------------------------
1824 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1825 GdkEventScroll
* gdk_event
,
1831 wxapp_install_idle_handler();
1833 wxEventType event_type
= wxEVT_NULL
;
1834 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1835 event_type
= wxEVT_MOUSEWHEEL
;
1836 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1837 event_type
= wxEVT_MOUSEWHEEL
;
1841 wxMouseEvent
event( event_type
);
1842 // Can't use InitMouse macro because scroll events don't have button
1843 event
.SetTimestamp( gdk_event
->time
);
1844 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1845 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1846 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1847 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1848 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1849 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1850 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1851 event
.m_linesPerAction
= 3;
1852 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1853 event
.m_wheelRotation
= 120;
1855 event
.m_wheelRotation
= -120;
1857 wxPoint pt
= win
->GetClientAreaOrigin();
1858 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1859 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1861 event
.SetEventObject( win
);
1862 event
.SetId( win
->GetId() );
1863 event
.SetTimestamp( gdk_event
->time
);
1865 if (win
->GetEventHandler()->ProcessEvent( event
))
1867 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1875 //-----------------------------------------------------------------------------
1877 //-----------------------------------------------------------------------------
1879 // send the wxChildFocusEvent and wxFocusEvent, common code of
1880 // gtk_window_focus_in_callback() and SetFocus()
1881 static bool DoSendFocusEvents(wxWindow
*win
)
1883 // Notify the parent keeping track of focus for the kbd navigation
1884 // purposes that we got it.
1885 wxChildFocusEvent
eventChildFocus(win
);
1886 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1888 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1889 eventFocus
.SetEventObject(win
);
1891 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1894 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1895 GdkEvent
*WXUNUSED(event
),
1901 wxapp_install_idle_handler();
1903 if (!win
->m_hasVMT
) return FALSE
;
1904 if (g_blockEventsOnDrag
) return FALSE
;
1906 switch ( g_sendActivateEvent
)
1909 // we've got focus from outside, synthetize wxActivateEvent
1910 g_sendActivateEvent
= 1;
1914 // another our window just lost focus, it was already ours before
1915 // - don't send any wxActivateEvent
1916 g_sendActivateEvent
= -1;
1921 g_focusWindow
= win
;
1923 wxLogTrace(TRACE_FOCUS
,
1924 _T("%s: focus in"), win
->GetName().c_str());
1928 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1932 // caret needs to be informed about focus change
1933 wxCaret
*caret
= win
->GetCaret();
1936 caret
->OnSetFocus();
1938 #endif // wxUSE_CARET
1940 g_activeFrameLostFocus
= FALSE
;
1942 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1943 if ( active
!= g_activeFrame
)
1945 if ( g_activeFrame
)
1947 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1948 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1949 event
.SetEventObject(g_activeFrame
);
1950 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1953 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1954 g_activeFrame
= active
;
1955 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1956 event
.SetEventObject(g_activeFrame
);
1957 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1959 // Don't send focus events in addition to activate
1960 // if (win == g_activeFrame)
1964 // does the window itself think that it has the focus?
1965 if ( !win
->m_hasFocus
)
1967 // not yet, notify it
1968 win
->m_hasFocus
= TRUE
;
1970 if ( DoSendFocusEvents(win
) )
1972 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1980 //-----------------------------------------------------------------------------
1981 // "focus_out_event"
1982 //-----------------------------------------------------------------------------
1984 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1989 wxapp_install_idle_handler();
1991 if (!win
->m_hasVMT
) return FALSE
;
1992 if (g_blockEventsOnDrag
) return FALSE
;
1994 wxLogTrace( TRACE_FOCUS
,
1995 _T("%s: focus out"), win
->GetName().c_str() );
1997 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1999 // VZ: commenting this out because it does happen (although not easy
2000 // to reproduce, I only see it when using wxMiniFrame and not
2001 // always) and makes using Mahogany quite annoying
2003 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
2004 wxT("unfocusing window that hasn't gained focus properly") );
2007 g_activeFrameLostFocus
= TRUE
;
2010 // if the focus goes out of our app alltogether, OnIdle() will send
2011 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
2012 // g_sendActivateEvent to -1
2013 g_sendActivateEvent
= 0;
2015 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2019 g_focusWindow
= (wxWindowGTK
*)NULL
;
2027 // caret needs to be informed about focus change
2028 wxCaret
*caret
= win
->GetCaret();
2031 caret
->OnKillFocus();
2033 #endif // wxUSE_CARET
2035 // don't send the window a kill focus event if it thinks that it doesn't
2036 // have focus already
2037 if ( win
->m_hasFocus
)
2039 win
->m_hasFocus
= FALSE
;
2041 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2042 event
.SetEventObject( win
);
2044 if (win
->GetEventHandler()->ProcessEvent( event
))
2046 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
2054 //-----------------------------------------------------------------------------
2055 // "enter_notify_event"
2056 //-----------------------------------------------------------------------------
2059 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2060 GdkEventCrossing
*gdk_event
,
2066 wxapp_install_idle_handler();
2068 if (!win
->m_hasVMT
) return FALSE
;
2069 if (g_blockEventsOnDrag
) return FALSE
;
2071 // Event was emitted after a grab
2072 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2074 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2078 GdkModifierType state
= (GdkModifierType
)0;
2080 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2082 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2083 InitMouseEvent(win
, event
, gdk_event
);
2084 wxPoint pt
= win
->GetClientAreaOrigin();
2085 event
.m_x
= x
+ pt
.x
;
2086 event
.m_y
= y
+ pt
.y
;
2088 if (win
->GetEventHandler()->ProcessEvent( event
))
2090 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2097 //-----------------------------------------------------------------------------
2098 // "leave_notify_event"
2099 //-----------------------------------------------------------------------------
2101 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2106 wxapp_install_idle_handler();
2108 if (!win
->m_hasVMT
) return FALSE
;
2109 if (g_blockEventsOnDrag
) return FALSE
;
2111 // Event was emitted after an ungrab
2112 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2114 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2116 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2117 event
.SetTimestamp( gdk_event
->time
);
2118 event
.SetEventObject( win
);
2122 GdkModifierType state
= (GdkModifierType
)0;
2124 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2126 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2127 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2128 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2129 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2130 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2131 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2132 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2134 wxPoint pt
= win
->GetClientAreaOrigin();
2135 event
.m_x
= x
+ pt
.x
;
2136 event
.m_y
= y
+ pt
.y
;
2138 if (win
->GetEventHandler()->ProcessEvent( event
))
2140 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2147 //-----------------------------------------------------------------------------
2148 // "value_changed" from m_vAdjust
2149 //-----------------------------------------------------------------------------
2151 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2158 wxapp_install_idle_handler();
2160 if (g_blockEventsOnDrag
) return;
2162 if (!win
->m_hasVMT
) return;
2164 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2165 if (fabs(diff
) < 0.2) return;
2167 win
->m_oldVerticalPos
= adjust
->value
;
2170 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2172 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2174 int value
= (int)(adjust
->value
+0.5);
2176 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2177 event
.SetEventObject( win
);
2178 win
->GetEventHandler()->ProcessEvent( event
);
2181 //-----------------------------------------------------------------------------
2182 // "value_changed" from m_hAdjust
2183 //-----------------------------------------------------------------------------
2185 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2192 wxapp_install_idle_handler();
2194 if (g_blockEventsOnDrag
) return;
2195 if (!win
->m_hasVMT
) return;
2197 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2198 if (fabs(diff
) < 0.2) return;
2201 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2203 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2205 win
->m_oldHorizontalPos
= adjust
->value
;
2207 int value
= (int)(adjust
->value
+0.5);
2209 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2210 event
.SetEventObject( win
);
2211 win
->GetEventHandler()->ProcessEvent( event
);
2214 //-----------------------------------------------------------------------------
2215 // "button_press_event" from scrollbar
2216 //-----------------------------------------------------------------------------
2218 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2219 GdkEventButton
*gdk_event
,
2225 wxapp_install_idle_handler();
2228 g_blockEventsOnScroll
= TRUE
;
2230 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2232 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2238 //-----------------------------------------------------------------------------
2239 // "button_release_event" from scrollbar
2240 //-----------------------------------------------------------------------------
2242 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2243 GdkEventButton
*WXUNUSED(gdk_event
),
2248 // don't test here as we can release the mouse while being over
2249 // a different window than the slider
2251 // if (gdk_event->window != widget->slider) return FALSE;
2253 g_blockEventsOnScroll
= FALSE
;
2255 if (win
->m_isScrolling
)
2257 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2261 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2262 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2264 value
= (int)(win
->m_hAdjust
->value
+0.5);
2267 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2269 value
= (int)(win
->m_vAdjust
->value
+0.5);
2273 wxScrollWinEvent
event( command
, value
, dir
);
2274 event
.SetEventObject( win
);
2275 win
->GetEventHandler()->ProcessEvent( event
);
2278 win
->m_isScrolling
= FALSE
;
2283 // ----------------------------------------------------------------------------
2284 // this wxWindowBase function is implemented here (in platform-specific file)
2285 // because it is static and so couldn't be made virtual
2286 // ----------------------------------------------------------------------------
2288 wxWindow
*wxWindowBase
::FindFocus()
2290 // the cast is necessary when we compile in wxUniversal mode
2291 return (wxWindow
*)g_focusWindow
;
2295 //-----------------------------------------------------------------------------
2296 // "realize" from m_widget
2297 //-----------------------------------------------------------------------------
2299 /* We cannot set colours and fonts before the widget has
2300 been realized, so we do this directly after realization. */
2303 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2308 wxapp_install_idle_handler();
2311 if (win
->m_imContext
)
2313 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2314 gtk_im_context_set_client_window( win
->m_imContext
, pizza
->bin_window
);
2318 wxWindowCreateEvent
event( win
);
2319 event
.SetEventObject( win
);
2320 win
->GetEventHandler()->ProcessEvent( event
);
2325 //-----------------------------------------------------------------------------
2327 //-----------------------------------------------------------------------------
2330 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2331 GtkAllocation
*WXUNUSED(alloc
),
2335 wxapp_install_idle_handler();
2337 if (!win
->m_hasScrolling
) return;
2339 int client_width
= 0;
2340 int client_height
= 0;
2341 win
->GetClientSize( &client_width
, &client_height
);
2342 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2345 win
->m_oldClientWidth
= client_width
;
2346 win
->m_oldClientHeight
= client_height
;
2348 if (!win
->m_nativeSizeEvent
)
2350 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2351 event
.SetEventObject( win
);
2352 win
->GetEventHandler()->ProcessEvent( event
);
2358 #define WXUNUSED_UNLESS_XIM(param) param
2360 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2363 /* Resize XIM window */
2366 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2367 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2368 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2371 wxapp_install_idle_handler();
2377 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2381 gdk_window_get_size (widget
->window
, &width
, &height
);
2382 win
->m_icattr
->preedit_area
.width
= width
;
2383 win
->m_icattr
->preedit_area
.height
= height
;
2384 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2389 //-----------------------------------------------------------------------------
2390 // "realize" from m_wxwindow
2391 //-----------------------------------------------------------------------------
2393 /* Initialize XIM support */
2396 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2397 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2400 wxapp_install_idle_handler();
2403 if (win
->m_ic
) return FALSE
;
2404 if (!widget
) return FALSE
;
2405 if (!gdk_im_ready()) return FALSE
;
2407 win
->m_icattr
= gdk_ic_attr_new();
2408 if (!win
->m_icattr
) return FALSE
;
2412 GdkColormap
*colormap
;
2413 GdkICAttr
*attr
= win
->m_icattr
;
2414 unsigned attrmask
= GDK_IC_ALL_REQ
;
2416 GdkIMStyle supported_style
= (GdkIMStyle
)
2417 (GDK_IM_PREEDIT_NONE
|
2418 GDK_IM_PREEDIT_NOTHING
|
2419 GDK_IM_PREEDIT_POSITION
|
2420 GDK_IM_STATUS_NONE
|
2421 GDK_IM_STATUS_NOTHING
);
2423 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2424 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2426 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2427 attr
->client_window
= widget
->window
;
2429 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2430 gtk_widget_get_default_colormap ())
2432 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2433 attr
->preedit_colormap
= colormap
;
2436 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2437 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2438 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2439 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2441 switch (style
& GDK_IM_PREEDIT_MASK
)
2443 case GDK_IM_PREEDIT_POSITION
:
2444 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2446 g_warning ("over-the-spot style requires fontset");
2450 gdk_window_get_size (widget
->window
, &width
, &height
);
2452 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2453 attr
->spot_location
.x
= 0;
2454 attr
->spot_location
.y
= height
;
2455 attr
->preedit_area
.x
= 0;
2456 attr
->preedit_area
.y
= 0;
2457 attr
->preedit_area
.width
= width
;
2458 attr
->preedit_area
.height
= height
;
2459 attr
->preedit_fontset
= widget
->style
->font
;
2464 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2466 if (win
->m_ic
== NULL
)
2467 g_warning ("Can't create input context.");
2470 mask
= gdk_window_get_events (widget
->window
);
2471 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2472 gdk_window_set_events (widget
->window
, mask
);
2474 if (GTK_WIDGET_HAS_FOCUS(widget
))
2475 gdk_im_begin (win
->m_ic
, widget
->window
);
2482 //-----------------------------------------------------------------------------
2483 // InsertChild for wxWindowGTK.
2484 //-----------------------------------------------------------------------------
2486 /* Callback for wxWindowGTK. This very strange beast has to be used because
2487 * C++ has no virtual methods in a constructor. We have to emulate a
2488 * virtual function here as wxNotebook requires a different way to insert
2489 * a child in it. I had opted for creating a wxNotebookPage window class
2490 * which would have made this superfluous (such in the MDI window system),
2491 * but no-one was listening to me... */
2493 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2495 /* the window might have been scrolled already, do we
2496 have to adapt the position */
2497 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2498 child
->m_x
+= pizza
->xoffset
;
2499 child
->m_y
+= pizza
->yoffset
;
2501 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2502 GTK_WIDGET(child
->m_widget
),
2509 //-----------------------------------------------------------------------------
2511 //-----------------------------------------------------------------------------
2513 wxWindow
*wxGetActiveWindow()
2515 return wxWindow
::FindFocus();
2518 //-----------------------------------------------------------------------------
2520 //-----------------------------------------------------------------------------
2522 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2524 #ifdef __WXUNIVERSAL__
2525 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2527 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2528 #endif // __WXUNIVERSAL__/__WXGTK__
2530 void wxWindowGTK
::Init()
2533 m_widget
= (GtkWidget
*) NULL
;
2534 m_wxwindow
= (GtkWidget
*) NULL
;
2535 m_focusWidget
= (GtkWidget
*) NULL
;
2545 m_needParent
= TRUE
;
2546 m_isBeingDeleted
= FALSE
;
2549 m_nativeSizeEvent
= FALSE
;
2551 m_hasScrolling
= FALSE
;
2552 m_isScrolling
= FALSE
;
2554 m_hAdjust
= (GtkAdjustment
*) NULL
;
2555 m_vAdjust
= (GtkAdjustment
*) NULL
;
2556 m_oldHorizontalPos
=
2557 m_oldVerticalPos
= 0.0;
2559 m_oldClientHeight
= 0;
2563 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2565 m_acceptsFocus
= FALSE
;
2568 m_clipPaintRegion
= FALSE
;
2570 m_cursor
= *wxSTANDARD_CURSOR
;
2574 m_x11Context
= NULL
;
2577 m_ic
= (GdkIC
*) NULL
;
2578 m_icattr
= (GdkICAttr
*) NULL
;
2583 wxWindowGTK
::wxWindowGTK()
2588 wxWindowGTK
::wxWindowGTK( wxWindow
*parent
,
2593 const wxString
&name
)
2597 Create( parent
, id
, pos
, size
, style
, name
);
2600 bool wxWindowGTK
::Create( wxWindow
*parent
,
2605 const wxString
&name
)
2607 if (!PreCreation( parent
, pos
, size
) ||
2608 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2610 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2614 m_insertCallback
= wxInsertChildInWindow
;
2616 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2617 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2619 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2621 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2622 scroll_class
->scrollbar_spacing
= 0;
2624 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2626 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2627 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2629 m_wxwindow
= gtk_pizza_new();
2631 #ifndef __WXUNIVERSAL__
2632 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2634 if (HasFlag(wxRAISED_BORDER
))
2636 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2638 else if (HasFlag(wxSUNKEN_BORDER
))
2640 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2642 else if (HasFlag(wxSIMPLE_BORDER
))
2644 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2648 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2650 #endif // __WXUNIVERSAL__
2652 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2654 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2655 m_acceptsFocus
= TRUE
;
2657 // I _really_ don't want scrollbars in the beginning
2658 m_vAdjust
->lower
= 0.0;
2659 m_vAdjust
->upper
= 1.0;
2660 m_vAdjust
->value
= 0.0;
2661 m_vAdjust
->step_increment
= 1.0;
2662 m_vAdjust
->page_increment
= 1.0;
2663 m_vAdjust
->page_size
= 5.0;
2664 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2665 m_hAdjust
->lower
= 0.0;
2666 m_hAdjust
->upper
= 1.0;
2667 m_hAdjust
->value
= 0.0;
2668 m_hAdjust
->step_increment
= 1.0;
2669 m_hAdjust
->page_increment
= 1.0;
2670 m_hAdjust
->page_size
= 5.0;
2671 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2673 // these handlers block mouse events to any window during scrolling such as
2674 // motion events and prevent GTK and wxWidgets from fighting over where the
2677 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2678 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2680 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2681 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2683 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2684 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2686 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2687 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2689 // these handlers get notified when screen updates are required either when
2690 // scrolling or when the window size (and therefore scrollbar configuration)
2693 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2694 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2695 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2696 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2698 gtk_widget_show( m_wxwindow
);
2701 m_parent
->DoAddChild( this );
2703 m_focusWidget
= m_wxwindow
;
2710 wxWindowGTK
::~wxWindowGTK()
2714 if (g_focusWindow
== this)
2715 g_focusWindow
= NULL
;
2717 if (g_activeFrame
== this)
2718 g_activeFrame
= NULL
;
2720 if ( g_delayedFocus
== this )
2721 g_delayedFocus
= NULL
;
2723 m_isBeingDeleted
= TRUE
;
2733 gdk_ic_destroy (m_ic
);
2735 gdk_ic_attr_destroy (m_icattr
);
2740 gtk_widget_destroy( m_wxwindow
);
2741 m_wxwindow
= (GtkWidget
*) NULL
;
2746 gtk_widget_destroy( m_widget
);
2747 m_widget
= (GtkWidget
*) NULL
;
2751 bool wxWindowGTK
::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2753 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2755 // Use either the given size, or the default if -1 is given.
2756 // See wxWindowBase for these functions.
2757 m_width
= WidthDefault(size
.x
) ;
2758 m_height
= HeightDefault(size
.y
);
2766 void wxWindowGTK
::PostCreation()
2768 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2774 // these get reported to wxWidgets -> wxPaintEvent
2776 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2778 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2779 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2782 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2783 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2785 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2787 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2788 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2791 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2796 // Create input method handler
2797 m_imContext
= gtk_im_multicontext_new();
2799 // Cannot handle drawing preedited text yet
2800 gtk_im_context_set_use_preedit( m_imContext
, FALSE
);
2802 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2803 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2806 // these are called when the "sunken" or "raised" borders are drawn
2807 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2808 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2811 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2812 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2818 if (m_focusWidget
== NULL
)
2819 m_focusWidget
= m_widget
;
2821 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2822 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2824 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2825 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2827 // connect to the various key and mouse handlers
2829 GtkWidget
*connect_widget
= GetConnectWidget();
2831 ConnectWidget( connect_widget
);
2833 /* We cannot set colours, fonts and cursors before the widget has
2834 been realized, so we do this directly after realization */
2835 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2836 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2840 // Catch native resize events
2841 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2842 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2844 // Initialize XIM support
2845 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2846 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2848 // And resize XIM window
2849 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2850 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2853 if ( !GTK_IS_COMBO(m_widget
))
2855 // This is needed if we want to add our windows into native
2856 // GTK control, such as the toolbar. With this callback, the
2857 // toolbar gets to know the correct size (the one set by the
2858 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2859 // when moving to GTK 2.0.
2860 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2861 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2867 // unless the window was created initially hidden (i.e. Hide() had been
2868 // called before Create()), we should show it at GTK+ level as well
2870 gtk_widget_show( m_widget
);
2873 void wxWindowGTK
::ConnectWidget( GtkWidget
*widget
)
2875 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2876 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2878 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2879 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2881 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2882 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2884 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2885 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2887 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2888 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2891 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2892 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2895 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2896 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2898 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2899 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2902 bool wxWindowGTK
::Destroy()
2904 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2908 return wxWindowBase
::Destroy();
2911 void wxWindowGTK
::DoMoveWindow(int x
, int y
, int width
, int height
)
2913 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2916 void wxWindowGTK
::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2918 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2919 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2922 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2925 if (m_resizing
) return; /* I don't like recursions */
2928 int currentX
, currentY
;
2929 GetPosition(¤tX
, ¤tY
);
2930 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2932 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2934 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2936 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2938 /* don't set the size for children of wxNotebook, just take the values. */
2946 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2947 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2949 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2950 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2954 m_x
= x
+ pizza
->xoffset
;
2955 m_y
= y
+ pizza
->yoffset
;
2958 // calculate the best size if we should auto size the window
2959 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2960 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2962 const wxSize sizeBest
= GetBestSize();
2963 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2965 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2966 height
= sizeBest
.y
;
2974 int minWidth
= GetMinWidth(),
2975 minHeight
= GetMinHeight(),
2976 maxWidth
= GetMaxWidth(),
2977 maxHeight
= GetMaxHeight();
2979 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2980 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2981 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2982 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2985 int bottom_border
= 0;
2988 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2990 /* the default button has a border around it */
2996 DoMoveWindow( m_x
-border
,
2999 m_height
+border
+bottom_border
);
3004 /* Sometimes the client area changes size without the
3005 whole windows's size changing, but if the whole
3006 windows's size doesn't change, no wxSizeEvent will
3007 normally be sent. Here we add an extra test if
3008 the client test has been changed and this will
3010 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3014 wxPrintf( "OnSize sent from " );
3015 if (GetClassInfo() && GetClassInfo()->GetClassName())
3016 wxPrintf( GetClassInfo()->GetClassName() );
3017 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3020 if (!m_nativeSizeEvent
)
3022 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3023 event
.SetEventObject( this );
3024 GetEventHandler()->ProcessEvent( event
);
3030 void wxWindowGTK
::OnInternalIdle()
3032 // Update invalidated regions.
3035 // Synthetize activate events.
3036 if ( g_sendActivateEvent
!= -1 )
3038 bool activate
= g_sendActivateEvent
!= 0;
3041 g_sendActivateEvent
= -1;
3043 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
3046 if ( g_activeFrameLostFocus
)
3048 if ( g_activeFrame
)
3050 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3051 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3052 event
.SetEventObject(g_activeFrame
);
3053 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3054 g_activeFrame
= NULL
;
3056 g_activeFrameLostFocus
= FALSE
;
3059 wxCursor cursor
= m_cursor
;
3060 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3064 /* I now set the cursor anew in every OnInternalIdle call
3065 as setting the cursor in a parent window also effects the
3066 windows above so that checking for the current cursor is
3071 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3073 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3075 if (!g_globalCursor
.Ok())
3076 cursor
= *wxSTANDARD_CURSOR
;
3078 window
= m_widget
->window
;
3079 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3080 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3086 GdkWindow
*window
= m_widget
->window
;
3087 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3088 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3093 if (wxUpdateUIEvent
::CanUpdate(this))
3094 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3097 void wxWindowGTK
::DoGetSize( int *width
, int *height
) const
3099 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3101 if (width
) (*width
) = m_width
;
3102 if (height
) (*height
) = m_height
;
3105 void wxWindowGTK
::DoSetClientSize( int width
, int height
)
3107 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3111 SetSize( width
, height
);
3118 #ifndef __WXUNIVERSAL__
3119 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3121 /* when using GTK 1.2 we set the shadow border size to 2 */
3125 if (HasFlag(wxSIMPLE_BORDER
))
3127 /* when using GTK 1.2 we set the simple border size to 1 */
3131 #endif // __WXUNIVERSAL__
3135 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3137 GtkRequisition vscroll_req
;
3138 vscroll_req
.width
= 2;
3139 vscroll_req
.height
= 2;
3140 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3141 (scroll_window
->vscrollbar
, &vscroll_req
);
3143 GtkRequisition hscroll_req
;
3144 hscroll_req
.width
= 2;
3145 hscroll_req
.height
= 2;
3146 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3147 (scroll_window
->hscrollbar
, &hscroll_req
);
3149 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3151 if (scroll_window
->vscrollbar_visible
)
3153 dw
+= vscroll_req
.width
;
3154 dw
+= scroll_class
->scrollbar_spacing
;
3157 if (scroll_window
->hscrollbar_visible
)
3159 dh
+= hscroll_req
.height
;
3160 dh
+= scroll_class
->scrollbar_spacing
;
3164 SetSize( width
+dw
, height
+dh
);
3168 void wxWindowGTK
::DoGetClientSize( int *width
, int *height
) const
3170 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3174 if (width
) (*width
) = m_width
;
3175 if (height
) (*height
) = m_height
;
3182 #ifndef __WXUNIVERSAL__
3183 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3185 /* when using GTK 1.2 we set the shadow border size to 2 */
3189 if (HasFlag(wxSIMPLE_BORDER
))
3191 /* when using GTK 1.2 we set the simple border size to 1 */
3195 #endif // __WXUNIVERSAL__
3199 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3201 GtkRequisition vscroll_req
;
3202 vscroll_req
.width
= 2;
3203 vscroll_req
.height
= 2;
3204 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3205 (scroll_window
->vscrollbar
, &vscroll_req
);
3207 GtkRequisition hscroll_req
;
3208 hscroll_req
.width
= 2;
3209 hscroll_req
.height
= 2;
3210 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3211 (scroll_window
->hscrollbar
, &hscroll_req
);
3213 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3215 if (scroll_window
->vscrollbar_visible
)
3217 dw
+= vscroll_req
.width
;
3218 dw
+= scroll_class
->scrollbar_spacing
;
3221 if (scroll_window
->hscrollbar_visible
)
3223 dh
+= hscroll_req
.height
;
3224 dh
+= scroll_class
->scrollbar_spacing
;
3228 if (width
) (*width
) = m_width
- dw
;
3229 if (height
) (*height
) = m_height
- dh
;
3233 printf( "GetClientSize, name %s ", GetName().c_str() );
3234 if (width) printf( " width = %d", (*width) );
3235 if (height) printf( " height = %d", (*height) );
3240 void wxWindowGTK
::DoGetPosition( int *x
, int *y
) const
3242 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3246 if (m_parent
&& m_parent
->m_wxwindow
)
3248 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3249 dx
= pizza
->xoffset
;
3250 dy
= pizza
->yoffset
;
3253 if (x
) (*x
) = m_x
- dx
;
3254 if (y
) (*y
) = m_y
- dy
;
3257 void wxWindowGTK
::DoClientToScreen( int *x
, int *y
) const
3259 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3261 if (!m_widget
->window
) return;
3263 GdkWindow
*source
= (GdkWindow
*) NULL
;
3265 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3267 source
= m_widget
->window
;
3271 gdk_window_get_origin( source
, &org_x
, &org_y
);
3275 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3277 org_x
+= m_widget
->allocation
.x
;
3278 org_y
+= m_widget
->allocation
.y
;
3286 void wxWindowGTK
::DoScreenToClient( int *x
, int *y
) const
3288 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3290 if (!m_widget
->window
) return;
3292 GdkWindow
*source
= (GdkWindow
*) NULL
;
3294 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3296 source
= m_widget
->window
;
3300 gdk_window_get_origin( source
, &org_x
, &org_y
);
3304 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3306 org_x
+= m_widget
->allocation
.x
;
3307 org_y
+= m_widget
->allocation
.y
;
3315 bool wxWindowGTK
::Show( bool show
)
3317 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3319 if (!wxWindowBase
::Show(show
))
3326 gtk_widget_show( m_widget
);
3328 gtk_widget_hide( m_widget
);
3330 wxShowEvent
eventShow(GetId(), show
);
3331 eventShow
.m_eventObject
= this;
3333 GetEventHandler()->ProcessEvent(eventShow
);
3338 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3340 win
->OnParentEnable(enable
);
3342 // Recurse, so that children have the opportunity to Do The Right Thing
3343 // and reset colours that have been messed up by a parent's (really ancestor's)
3345 for ( wxWindowList
::compatibility_iterator node
= win
->GetChildren().GetFirst();
3347 node
= node
->GetNext() )
3349 wxWindow
*child
= node
->GetData();
3350 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3351 wxWindowNotifyEnable(child
, enable
);
3355 bool wxWindowGTK
::Enable( bool enable
)
3357 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3359 if (!wxWindowBase
::Enable(enable
))
3365 gtk_widget_set_sensitive( m_widget
, enable
);
3367 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3369 wxWindowNotifyEnable(this, enable
);
3374 int wxWindowGTK
::GetCharHeight() const
3376 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3378 wxFont font
= GetFont();
3379 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3382 PangoContext
*context
= NULL
;
3384 context
= gtk_widget_get_pango_context( m_widget
);
3389 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3390 PangoLayout
*layout
= pango_layout_new(context
);
3391 pango_layout_set_font_description(layout
, desc
);
3392 pango_layout_set_text(layout
, "H", 1);
3393 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3395 PangoRectangle rect
;
3396 pango_layout_line_get_extents(line
, NULL
, &rect
);
3398 g_object_unref( G_OBJECT( layout
) );
3400 return (int) (rect
.height
/ PANGO_SCALE
);
3402 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3404 return gfont
->ascent
+ gfont
->descent
;
3408 int wxWindowGTK
::GetCharWidth() const
3410 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3412 wxFont font
= GetFont();
3413 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3416 PangoContext
*context
= NULL
;
3418 context
= gtk_widget_get_pango_context( m_widget
);
3423 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3424 PangoLayout
*layout
= pango_layout_new(context
);
3425 pango_layout_set_font_description(layout
, desc
);
3426 pango_layout_set_text(layout
, "g", 1);
3427 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3429 PangoRectangle rect
;
3430 pango_layout_line_get_extents(line
, NULL
, &rect
);
3432 g_object_unref( G_OBJECT( layout
) );
3434 return (int) (rect
.width
/ PANGO_SCALE
);
3436 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3438 return gdk_string_width( gfont
, "g" );
3442 void wxWindowGTK
::GetTextExtent( const wxString
& string
,
3446 int *externalLeading
,
3447 const wxFont
*theFont
) const
3449 wxFont fontToUse
= theFont ?
*theFont
: GetFont();
3451 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3453 if (string
.IsEmpty())
3461 PangoContext
*context
= NULL
;
3463 context
= gtk_widget_get_pango_context( m_widget
);
3472 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3473 PangoLayout
*layout
= pango_layout_new(context
);
3474 pango_layout_set_font_description(layout
, desc
);
3477 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3478 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3480 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3481 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3482 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3485 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3487 PangoRectangle rect
;
3488 pango_layout_line_get_extents(line
, NULL
, &rect
);
3490 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3491 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3494 // Do something about metrics here
3497 if (externalLeading
) (*externalLeading
) = 0; // ??
3499 g_object_unref( G_OBJECT( layout
) );
3501 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3502 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3503 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3504 if (descent
) (*descent
) = font
->descent
;
3505 if (externalLeading
) (*externalLeading
) = 0; // ??
3509 void wxWindowGTK
::SetFocus()
3511 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3515 // don't do anything if we already have focus
3521 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3523 gtk_widget_grab_focus (m_wxwindow
);
3528 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3530 if (!GTK_WIDGET_REALIZED(m_widget
))
3532 // we can't set the focus to the widget now so we remember that
3533 // it should be focused and will do it later, during the idle
3534 // time, as soon as we can
3535 wxLogTrace(TRACE_FOCUS
,
3536 _T("Delaying setting focus to %s(%s)"),
3537 GetClassInfo()->GetClassName(), GetLabel().c_str());
3539 g_delayedFocus
= this;
3543 wxLogTrace(TRACE_FOCUS
,
3544 _T("Setting focus to %s(%s)"),
3545 GetClassInfo()->GetClassName(), GetLabel().c_str());
3547 gtk_widget_grab_focus (m_widget
);
3550 else if (GTK_IS_CONTAINER(m_widget
))
3552 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3556 wxLogTrace(TRACE_FOCUS
,
3557 _T("Can't set focus to %s(%s)"),
3558 GetClassInfo()->GetClassName(), GetLabel().c_str());
3563 bool wxWindowGTK
::AcceptsFocus() const
3565 return m_acceptsFocus
&& wxWindowBase
::AcceptsFocus();
3568 bool wxWindowGTK
::Reparent( wxWindowBase
*newParentBase
)
3570 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3572 wxWindowGTK
*oldParent
= m_parent
,
3573 *newParent
= (wxWindowGTK
*)newParentBase
;
3575 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3577 if ( !wxWindowBase
::Reparent(newParent
) )
3580 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3582 /* prevent GTK from deleting the widget arbitrarily */
3583 gtk_widget_ref( m_widget
);
3587 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3590 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3594 /* insert GTK representation */
3595 (*(newParent
->m_insertCallback
))(newParent
, this);
3598 /* reverse: prevent GTK from deleting the widget arbitrarily */
3599 gtk_widget_unref( m_widget
);
3604 void wxWindowGTK
::DoAddChild(wxWindowGTK
*child
)
3606 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3608 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3610 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3615 /* insert GTK representation */
3616 (*m_insertCallback
)(this, child
);
3619 void wxWindowGTK
::Raise()
3621 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3623 if (!m_widget
->window
) return;
3625 gdk_window_raise( m_widget
->window
);
3628 void wxWindowGTK
::Lower()
3630 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3632 if (!m_widget
->window
) return;
3634 gdk_window_lower( m_widget
->window
);
3637 bool wxWindowGTK
::SetCursor( const wxCursor
&cursor
)
3639 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3641 if (cursor
== m_cursor
)
3645 wxapp_install_idle_handler();
3647 if (cursor
== wxNullCursor
)
3648 return wxWindowBase
::SetCursor( *wxSTANDARD_CURSOR
);
3650 return wxWindowBase
::SetCursor( cursor
);
3653 void wxWindowGTK
::WarpPointer( int x
, int y
)
3655 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3657 // We provide this function ourselves as it is
3658 // missing in GDK (top of this file).
3660 GdkWindow
*window
= (GdkWindow
*) NULL
;
3662 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3664 window
= GetConnectWidget()->window
;
3667 gdk_window_warp_pointer( window
, x
, y
);
3671 void wxWindowGTK
::Refresh( bool eraseBackground
, const wxRect
*rect
)
3673 if (!m_widget
) return;
3674 if (!m_widget
->window
) return;
3678 wxapp_install_idle_handler();
3680 wxRect
myRect(0,0,0,0);
3681 if (m_wxwindow
&& rect
)
3683 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3684 m_wxwindow
->allocation
.height
));
3685 myRect
.Intersect(*rect
);
3686 if (!myRect
.width
|| !myRect
.height
)
3687 // nothing to do, rectangle is empty
3692 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3696 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3697 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3701 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3702 m_clearRegion
.Clear();
3703 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3711 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3712 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3716 GdkRectangle gdk_rect
;
3717 gdk_rect
.x
= rect
->x
;
3718 gdk_rect
.y
= rect
->y
;
3719 gdk_rect
.width
= rect
->width
;
3720 gdk_rect
.height
= rect
->height
;
3721 gtk_widget_draw( m_widget
, &gdk_rect
);
3728 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3729 m_updateRegion
.Clear();
3730 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3734 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3742 GdkRectangle gdk_rect
;
3743 gdk_rect
.x
= rect
->x
;
3744 gdk_rect
.y
= rect
->y
;
3745 gdk_rect
.width
= rect
->width
;
3746 gdk_rect
.height
= rect
->height
;
3747 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3751 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3757 void wxWindowGTK
::Update()
3762 void wxWindowGTK
::GtkUpdate()
3765 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3766 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3768 if (!m_updateRegion
.IsEmpty())
3769 GtkSendPaintEvents();
3773 void wxWindowGTK
::GtkSendPaintEvents()
3778 m_clearRegion
.Clear();
3780 m_updateRegion
.Clear();
3784 // Clip to paint region in wxClientDC
3785 m_clipPaintRegion
= TRUE
;
3787 // widget to draw on
3788 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3790 if (GetThemeEnabled())
3792 // find ancestor from which to steal background
3793 wxWindow
*parent
= GetParent();
3794 while (parent
&& !parent
->IsTopLevel())
3795 parent
= parent
->GetParent();
3797 parent
= (wxWindow
*)this;
3799 wxRegionIterator
upd( m_updateRegion
);
3803 rect
.x
= upd
.GetX();
3804 rect
.y
= upd
.GetY();
3805 rect
.width
= upd
.GetWidth();
3806 rect
.height
= upd
.GetHeight();
3808 gtk_paint_flat_box( parent
->m_widget
->style
,
3810 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3824 wxWindowDC
dc( (wxWindow
*)this );
3825 dc
.SetClippingRegion( m_updateRegion
);
3827 wxEraseEvent
erase_event( GetId(), &dc
);
3828 erase_event
.SetEventObject( this );
3830 GetEventHandler()->ProcessEvent(erase_event
);
3833 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3835 wxWindowDC
dc( (wxWindow
*)this );
3836 if (m_clearRegion
.IsEmpty())
3837 dc
.SetClippingRegion( m_updateRegion
);
3839 dc
.SetClippingRegion( m_clearRegion
);
3841 wxEraseEvent
erase_event( GetId(), &dc
);
3842 erase_event
.SetEventObject( this );
3844 if (!GetEventHandler()->ProcessEvent(erase_event
))
3848 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3849 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3851 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
3853 wxRegionIterator
upd( m_clearRegion
);
3856 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3857 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3861 m_clearRegion
.Clear();
3865 wxNcPaintEvent
nc_paint_event( GetId() );
3866 nc_paint_event
.SetEventObject( this );
3867 GetEventHandler()->ProcessEvent( nc_paint_event
);
3869 wxPaintEvent
paint_event( GetId() );
3870 paint_event
.SetEventObject( this );
3871 GetEventHandler()->ProcessEvent( paint_event
);
3873 m_clipPaintRegion
= FALSE
;
3875 #ifndef __WXUNIVERSAL__
3877 // The following code will result in all window-less widgets
3878 // being redrawn because the wxWidgets class is allowed to
3879 // paint over the window-less widgets.
3881 GList
*children
= pizza
->children
;
3884 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3885 children
= children
->next
;
3887 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3888 GTK_WIDGET_DRAWABLE (child
->widget
))
3890 // Get intersection of widget area and update region
3891 wxRegion
region( m_updateRegion
);
3893 GdkEventExpose gdk_event
;
3894 gdk_event
.type
= GDK_EXPOSE
;
3895 gdk_event
.window
= pizza
->bin_window
;
3896 gdk_event
.count
= 0;
3898 wxRegionIterator
upd( m_updateRegion
);
3902 rect
.x
= upd
.GetX();
3903 rect
.y
= upd
.GetY();
3904 rect
.width
= upd
.GetWidth();
3905 rect
.height
= upd
.GetHeight();
3907 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3909 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3919 m_updateRegion
.Clear();
3922 void wxWindowGTK
::ClearBackground()
3924 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3927 if (m_wxwindow
&& m_wxwindow
->window
)
3929 m_clearRegion
.Clear();
3930 wxSize
size( GetClientSize() );
3931 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3933 // Better do this in idle?
3940 void wxWindowGTK
::DoSetToolTip( wxToolTip
*tip
)
3942 wxWindowBase
::DoSetToolTip(tip
);
3945 m_tooltip
->Apply( (wxWindow
*)this );
3948 void wxWindowGTK
::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3950 wxString
tmp( tip
);
3951 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3953 #endif // wxUSE_TOOLTIPS
3955 bool wxWindowGTK
::SetBackgroundColour( const wxColour
&colour
)
3957 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3959 if (!wxWindowBase
::SetBackgroundColour(colour
))
3964 // We need the pixel value e.g. for background clearing.
3965 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3968 // apply style change (forceStyle=true so that new style is applied
3969 // even if the bg colour changed from valid to wxNullColour):
3970 ApplyWidgetStyle(true);
3975 bool wxWindowGTK
::SetForegroundColour( const wxColour
&colour
)
3977 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3979 if (!wxWindowBase
::SetForegroundColour(colour
))
3986 // We need the pixel value e.g. for background clearing.
3987 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
3990 // apply style change (forceStyle=true so that new style is applied
3991 // even if the bg colour changed from valid to wxNullColour):
3992 ApplyWidgetStyle(true);
3998 PangoContext
*wxWindowGTK
::GtkGetPangoDefaultContext()
4000 return gtk_widget_get_pango_context( m_widget
);
4003 PangoContext
*wxWindowGTK
::GtkGetPangoX11Context()
4006 m_x11Context
= pango_x_get_context( gdk_display
);
4008 return m_x11Context
;
4012 GtkRcStyle
*wxWindowGTK
::CreateWidgetStyle(bool forceStyle
)
4014 // do we need to apply any changes at all?
4017 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4022 GtkRcStyle
*style
= gtk_rc_style_new();
4028 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4030 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4031 style
->fontset_name
= g_strdup(xfontname
.c_str());
4035 if ( m_foregroundColour
.Ok() )
4037 GdkColor
*fg
= m_foregroundColour
.GetColor();
4039 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4040 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4042 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4043 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4045 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4046 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4049 if ( m_backgroundColour
.Ok() )
4051 GdkColor
*bg
= m_backgroundColour
.GetColor();
4053 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4054 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4055 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4056 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4058 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4059 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4060 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4061 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4063 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4064 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4065 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4066 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4068 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4069 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4070 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4071 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4077 void wxWindowGTK
::ApplyWidgetStyle(bool forceStyle
)
4079 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4082 DoApplyWidgetStyle(style
);
4083 gtk_rc_style_unref(style
);
4087 void wxWindowGTK
::DoApplyWidgetStyle(GtkRcStyle
*style
)
4090 // should we also do m_widget in this case?
4091 gtk_widget_modify_style(m_wxwindow
, style
);
4093 gtk_widget_modify_style(m_widget
, style
);
4097 //-----------------------------------------------------------------------------
4098 // Pop-up menu stuff
4099 //-----------------------------------------------------------------------------
4101 #if wxUSE_MENUS_NATIVE
4104 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4106 *is_waiting
= FALSE
;
4109 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4111 menu
->SetInvokingWindow( win
);
4112 wxMenuItemList
::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4115 wxMenuItem
*menuitem
= node
->GetData();
4116 if (menuitem
->IsSubMenu())
4118 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4121 node
= node
->GetNext();
4125 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4128 gboolean
* WXUNUSED(whatever
),
4130 gpointer user_data
)
4132 // ensure that the menu appears entirely on screen
4134 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4136 wxSize sizeScreen
= wxGetDisplaySize();
4137 wxPoint
*pos
= (wxPoint
*)user_data
;
4139 gint xmax
= sizeScreen
.x
- req
.width
,
4140 ymax
= sizeScreen
.y
- req
.height
;
4142 *x
= pos
->x
< xmax ? pos
->x
: xmax
;
4143 *y
= pos
->y
< ymax ? pos
->y
: ymax
;
4146 bool wxWindowGTK
::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4148 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4150 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4152 SetInvokingWindow( menu
, this );
4156 bool is_waiting
= true;
4158 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4160 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4161 (gpointer
)&is_waiting
);
4165 GtkMenuPositionFunc posfunc
;
4166 if ( x
== -1 && y
== -1 )
4168 // use GTK's default positioning algorithm
4174 pos
= ClientToScreen(wxPoint(x
, y
));
4176 posfunc
= wxPopupMenuPositionCallback
;
4180 GTK_MENU(menu
->m_menu
),
4181 (GtkWidget
*) NULL
, // parent menu shell
4182 (GtkWidget
*) NULL
, // parent menu item
4183 posfunc
, // function to position it
4184 userdata
, // client data
4185 0, // button used to activate it
4187 gtk_get_current_event_time()
4189 gs_timeLastClick
// the time of activation
4195 gtk_main_iteration();
4201 #endif // wxUSE_MENUS_NATIVE
4203 #if wxUSE_DRAG_AND_DROP
4205 void wxWindowGTK
::SetDropTarget( wxDropTarget
*dropTarget
)
4207 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4209 GtkWidget
*dnd_widget
= GetConnectWidget();
4211 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4213 if (m_dropTarget
) delete m_dropTarget
;
4214 m_dropTarget
= dropTarget
;
4216 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4219 #endif // wxUSE_DRAG_AND_DROP
4221 GtkWidget
* wxWindowGTK
::GetConnectWidget()
4223 GtkWidget
*connect_widget
= m_widget
;
4224 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4226 return connect_widget
;
4229 bool wxWindowGTK
::IsOwnGtkWindow( GdkWindow
*window
)
4232 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4234 return (window
== m_widget
->window
);
4237 bool wxWindowGTK
::SetFont( const wxFont
&font
)
4239 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4241 if (!wxWindowBase
::SetFont(font
))
4244 // apply style change (forceStyle=true so that new style is applied
4245 // even if the font changed from valid to wxNullFont):
4246 ApplyWidgetStyle(true);
4251 void wxWindowGTK
::DoCaptureMouse()
4253 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4255 GdkWindow
*window
= (GdkWindow
*) NULL
;
4257 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4259 window
= GetConnectWidget()->window
;
4261 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4263 wxCursor
* cursor
= & m_cursor
;
4265 cursor
= wxSTANDARD_CURSOR
;
4267 gdk_pointer_grab( window
, FALSE
,
4269 (GDK_BUTTON_PRESS_MASK
|
4270 GDK_BUTTON_RELEASE_MASK
|
4271 GDK_POINTER_MOTION_HINT_MASK
|
4272 GDK_POINTER_MOTION_MASK
),
4274 cursor
->GetCursor(),
4275 (guint32
)GDK_CURRENT_TIME
);
4276 g_captureWindow
= this;
4277 g_captureWindowHasMouse
= TRUE
;
4280 void wxWindowGTK
::DoReleaseMouse()
4282 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4284 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4286 g_captureWindow
= (wxWindowGTK
*) NULL
;
4288 GdkWindow
*window
= (GdkWindow
*) NULL
;
4290 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4292 window
= GetConnectWidget()->window
;
4297 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4301 wxWindow
*wxWindowBase
::GetCapture()
4303 return (wxWindow
*)g_captureWindow
;
4306 bool wxWindowGTK
::IsRetained() const
4311 void wxWindowGTK
::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4312 int range
, bool refresh
)
4314 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4316 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4318 m_hasScrolling
= TRUE
;
4320 if (orient
== wxHORIZONTAL
)
4322 float fpos
= (float)pos
;
4323 float frange
= (float)range
;
4324 float fthumb
= (float)thumbVisible
;
4325 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4326 if (fpos
< 0.0) fpos
= 0.0;
4328 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4329 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4331 SetScrollPos( orient
, pos
, refresh
);
4335 m_oldHorizontalPos
= fpos
;
4337 m_hAdjust
->lower
= 0.0;
4338 m_hAdjust
->upper
= frange
;
4339 m_hAdjust
->value
= fpos
;
4340 m_hAdjust
->step_increment
= 1.0;
4341 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4342 m_hAdjust
->page_size
= fthumb
;
4346 float fpos
= (float)pos
;
4347 float frange
= (float)range
;
4348 float fthumb
= (float)thumbVisible
;
4349 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4350 if (fpos
< 0.0) fpos
= 0.0;
4352 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4353 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4355 SetScrollPos( orient
, pos
, refresh
);
4359 m_oldVerticalPos
= fpos
;
4361 m_vAdjust
->lower
= 0.0;
4362 m_vAdjust
->upper
= frange
;
4363 m_vAdjust
->value
= fpos
;
4364 m_vAdjust
->step_increment
= 1.0;
4365 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4366 m_vAdjust
->page_size
= fthumb
;
4369 if (orient
== wxHORIZONTAL
)
4370 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4372 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4375 void wxWindowGTK
::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4377 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4379 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4381 if (orient
== wxHORIZONTAL
)
4383 float fpos
= (float)pos
;
4384 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4385 if (fpos
< 0.0) fpos
= 0.0;
4386 m_oldHorizontalPos
= fpos
;
4388 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4389 m_hAdjust
->value
= fpos
;
4393 float fpos
= (float)pos
;
4394 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4395 if (fpos
< 0.0) fpos
= 0.0;
4396 m_oldVerticalPos
= fpos
;
4398 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4399 m_vAdjust
->value
= fpos
;
4402 if (m_wxwindow
->window
)
4404 if (orient
== wxHORIZONTAL
)
4406 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4407 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4409 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4411 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4412 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4416 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4417 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4419 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4421 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4422 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4427 int wxWindowGTK
::GetScrollThumb( int orient
) const
4429 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4431 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4433 if (orient
== wxHORIZONTAL
)
4434 return (int)(m_hAdjust
->page_size
+0.5);
4436 return (int)(m_vAdjust
->page_size
+0.5);
4439 int wxWindowGTK
::GetScrollPos( int orient
) const
4441 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4443 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4445 if (orient
== wxHORIZONTAL
)
4446 return (int)(m_hAdjust
->value
+0.5);
4448 return (int)(m_vAdjust
->value
+0.5);
4451 int wxWindowGTK
::GetScrollRange( int orient
) const
4453 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4455 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4457 if (orient
== wxHORIZONTAL
)
4458 return (int)(m_hAdjust
->upper
+0.5);
4460 return (int)(m_vAdjust
->upper
+0.5);
4463 void wxWindowGTK
::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4465 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4467 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4469 // No scrolling requested.
4470 if ((dx
== 0) && (dy
== 0)) return;
4473 if (!m_updateRegion
.IsEmpty())
4475 m_updateRegion
.Offset( dx
, dy
);
4479 GetClientSize( &cw
, &ch
);
4480 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4483 if (!m_clearRegion
.IsEmpty())
4485 m_clearRegion
.Offset( dx
, dy
);
4489 GetClientSize( &cw
, &ch
);
4490 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4494 m_clipPaintRegion
= TRUE
;
4496 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4498 m_clipPaintRegion
= FALSE
;
4502 // Find the wxWindow at the current mouse position, also returning the mouse
4504 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4506 pt
= wxGetMousePosition();
4507 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4511 // Get the current mouse position.
4512 wxPoint
wxGetMousePosition()
4514 /* This crashes when used within wxHelpContext,
4515 so we have to use the X-specific implementation below.
4517 GdkModifierType *mask;
4518 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4520 return wxPoint(x, y);
4524 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4526 Display
*display
= windowAtPtr ?
GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4527 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4528 Window rootReturn
, childReturn
;
4529 int rootX
, rootY
, winX
, winY
;
4530 unsigned int maskReturn
;
4532 XQueryPointer (display
,
4536 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4537 return wxPoint(rootX
, rootY
);
4541 // ----------------------------------------------------------------------------
4543 // ----------------------------------------------------------------------------
4545 class wxWinModule
: public wxModule
4552 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4555 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4557 bool wxWinModule
::OnInit()
4559 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4560 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4565 void wxWinModule
::OnExit()
4568 gdk_gc_unref( g_eraseGC
);