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 wxWindows, 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 wxWindows 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 wxWindows 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 wxStatitText 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 wxWindows 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 wxWindows 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 wxWindows, 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 wxWindows 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 //-----------------------------------------------------------------------------
271 #define DISABLE_STYLE_IF_BROKEN_THEME 0
277 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
279 # define DEBUG_MAIN_THREAD
282 #define DEBUG_MAIN_THREAD
285 // the trace mask used for the focus debugging messages
286 #define TRACE_FOCUS _T("focus")
288 //-----------------------------------------------------------------------------
289 // missing gdk functions
290 //-----------------------------------------------------------------------------
293 gdk_window_warp_pointer (GdkWindow
*window
,
298 GdkWindowPrivate
*priv
;
302 window
= GDK_ROOT_PARENT();
305 if (!GDK_WINDOW_DESTROYED(window
))
307 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
308 None
, /* not source window -> move from anywhere */
309 GDK_WINDOW_XID(window
), /* dest window */
310 0, 0, 0, 0, /* not source window -> move from anywhere */
314 priv
= (GdkWindowPrivate
*) window
;
316 if (!priv
->destroyed
)
318 XWarpPointer (priv
->xdisplay
,
319 None
, /* not source window -> move from anywhere */
320 priv
->xwindow
, /* dest window */
321 0, 0, 0, 0, /* not source window -> move from anywhere */
327 //-----------------------------------------------------------------------------
329 //-----------------------------------------------------------------------------
331 extern void wxapp_install_idle_handler();
332 extern bool g_isIdle
;
334 //-----------------------------------------------------------------------------
335 // local code (see below)
336 //-----------------------------------------------------------------------------
338 // returns the child of win which currently has focus or NULL if not found
340 // Note: can't be static, needed by textctrl.cpp.
341 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
343 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
345 return (wxWindow
*)NULL
;
347 if ( winFocus
== win
)
348 return (wxWindow
*)win
;
350 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
352 node
= node
->GetNext() )
354 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
359 return (wxWindow
*)NULL
;
362 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
364 // wxUniversal widgets draw the borders and scrollbars themselves
365 #ifndef __WXUNIVERSAL__
372 if (win
->m_hasScrolling
)
374 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
376 GtkRequisition vscroll_req
;
377 vscroll_req
.width
= 2;
378 vscroll_req
.height
= 2;
379 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
380 (scroll_window
->vscrollbar
, &vscroll_req
);
382 GtkRequisition hscroll_req
;
383 hscroll_req
.width
= 2;
384 hscroll_req
.height
= 2;
385 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
386 (scroll_window
->hscrollbar
, &hscroll_req
);
388 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
390 if (scroll_window
->vscrollbar_visible
)
392 dw
+= vscroll_req
.width
;
393 dw
+= scroll_class
->scrollbar_spacing
;
396 if (scroll_window
->hscrollbar_visible
)
398 dh
+= hscroll_req
.height
;
399 dh
+= scroll_class
->scrollbar_spacing
;
405 if (GTK_WIDGET_NO_WINDOW (widget
))
407 dx
+= widget
->allocation
.x
;
408 dy
+= widget
->allocation
.y
;
411 if (win
->HasFlag(wxRAISED_BORDER
))
413 gtk_draw_shadow( widget
->style
,
418 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
422 if (win
->HasFlag(wxSUNKEN_BORDER
))
424 gtk_draw_shadow( widget
->style
,
429 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
433 if (win
->HasFlag(wxSIMPLE_BORDER
))
436 gc
= gdk_gc_new( widget
->window
);
437 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
438 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
440 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
444 #endif // __WXUNIVERSAL__
447 //-----------------------------------------------------------------------------
448 // "expose_event" of m_widget
449 //-----------------------------------------------------------------------------
451 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
453 if (gdk_event
->count
> 0) return FALSE
;
455 draw_frame( widget
, win
);
459 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
465 //-----------------------------------------------------------------------------
466 // "draw" of m_widget
467 //-----------------------------------------------------------------------------
471 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
473 draw_frame( widget
, win
);
478 //-----------------------------------------------------------------------------
479 // "size_request" of m_widget
480 //-----------------------------------------------------------------------------
482 // make it extern because wxStatitText needs to disconnect this one
484 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
485 GtkRequisition
*requisition
,
489 win
->GetSize( &w
, &h
);
495 requisition
->height
= h
;
496 requisition
->width
= w
;
499 //-----------------------------------------------------------------------------
500 // "expose_event" of m_wxwindow
501 //-----------------------------------------------------------------------------
503 static int gtk_window_expose_callback( GtkWidget
*widget
,
504 GdkEventExpose
*gdk_event
,
510 wxapp_install_idle_handler();
513 // This callback gets called in drawing-idle time under
514 // GTK 2.0, so we don't need to defer anything to idle
517 GtkPizza
*pizza
= GTK_PIZZA( widget
);
518 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
523 wxPrintf( wxT("OnExpose from ") );
524 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
525 wxPrintf( win
->GetClassInfo()->GetClassName() );
526 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
527 (int)gdk_event
->area
.y
,
528 (int)gdk_event
->area
.width
,
529 (int)gdk_event
->area
.height
);
534 win
->m_wxwindow
->style
,
538 (GdkRectangle
*) NULL
,
540 (char *)"button", // const_cast
545 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
547 win
->GtkSendPaintEvents();
550 // Let parent window draw window less widgets
551 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
553 // This gets called immediately after an expose event
554 // under GTK 1.2 so we collect the calls and wait for
555 // the idle handler to pick things up.
557 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
559 gdk_event
->area
.width
,
560 gdk_event
->area
.height
);
561 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
563 gdk_event
->area
.width
,
564 gdk_event
->area
.height
);
566 // Actual redrawing takes place in idle time.
573 //-----------------------------------------------------------------------------
574 // "event" of m_wxwindow
575 //-----------------------------------------------------------------------------
577 // GTK thinks it is clever and filters out a certain amount of "unneeded"
578 // expose events. We need them, of course, so we override the main event
579 // procedure in GtkWidget by giving our own handler for all system events.
580 // There, we look for expose events ourselves whereas all other events are
583 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
584 GdkEventExpose
*event
,
587 if (event
->type
== GDK_EXPOSE
)
589 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
596 //-----------------------------------------------------------------------------
597 // "draw" of m_wxwindow
598 //-----------------------------------------------------------------------------
602 // This callback is a complete replacement of the gtk_pizza_draw() function,
603 // which is disabled.
605 static void gtk_window_draw_callback( GtkWidget
*widget
,
612 wxapp_install_idle_handler();
614 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
615 // there are no child windows.
616 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
617 (win
->GetChildren().GetCount() == 0))
625 wxPrintf( wxT("OnDraw from ") );
626 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
627 wxPrintf( win
->GetClassInfo()->GetClassName() );
628 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
635 #ifndef __WXUNIVERSAL__
636 GtkPizza
*pizza
= GTK_PIZZA (widget
);
638 if (win
->GetThemeEnabled())
640 wxWindow
*parent
= win
->GetParent();
641 while (parent
&& !parent
->IsTopLevel())
642 parent
= parent
->GetParent();
646 gtk_paint_flat_box (parent
->m_widget
->style
,
657 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
658 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
660 // Update immediately, not in idle time.
663 #ifndef __WXUNIVERSAL__
664 // Redraw child widgets
665 GList
*children
= pizza
->children
;
668 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
669 children
= children
->next
;
671 GdkRectangle child_area
;
672 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
674 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
682 //-----------------------------------------------------------------------------
683 // "key_press_event" from any window
684 //-----------------------------------------------------------------------------
686 // set WXTRACE to this to see the key event codes on the console
687 #define TRACE_KEYS _T("keyevent")
689 // translates an X key symbol to WXK_XXX value
691 // if isChar is true it means that the value returned will be used for EVT_CHAR
692 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
693 // for example, while if it is false it means that the value is going to be
694 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
696 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
702 // Shift, Control and Alt don't generate the CHAR events at all
705 key_code
= isChar
? 0 : WXK_SHIFT
;
709 key_code
= isChar
? 0 : WXK_CONTROL
;
717 key_code
= isChar
? 0 : WXK_ALT
;
720 // neither do the toggle modifies
721 case GDK_Scroll_Lock
:
722 key_code
= isChar
? 0 : WXK_SCROLL
;
726 key_code
= isChar
? 0 : WXK_CAPITAL
;
730 key_code
= isChar
? 0 : WXK_NUMLOCK
;
734 // various other special keys
747 case GDK_ISO_Left_Tab
:
754 key_code
= WXK_RETURN
;
758 key_code
= WXK_CLEAR
;
762 key_code
= WXK_PAUSE
;
766 key_code
= WXK_SELECT
;
770 key_code
= WXK_PRINT
;
774 key_code
= WXK_EXECUTE
;
778 key_code
= WXK_ESCAPE
;
781 // cursor and other extended keyboard keys
783 key_code
= WXK_DELETE
;
799 key_code
= WXK_RIGHT
;
806 case GDK_Prior
: // == GDK_Page_Up
807 key_code
= WXK_PRIOR
;
810 case GDK_Next
: // == GDK_Page_Down
823 key_code
= WXK_INSERT
;
838 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
842 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
846 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
850 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
854 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
858 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
862 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
866 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
870 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
874 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
878 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
882 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
886 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
889 case GDK_KP_Prior
: // == GDK_KP_Page_Up
890 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
893 case GDK_KP_Next
: // == GDK_KP_Page_Down
894 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
898 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
902 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
906 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
910 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
914 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
917 case GDK_KP_Multiply
:
918 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
922 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
925 case GDK_KP_Separator
:
926 // FIXME: what is this?
927 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
930 case GDK_KP_Subtract
:
931 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
935 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
939 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
956 key_code
= WXK_F1
+ keysym
- GDK_F1
;
966 static inline bool wxIsAsciiKeysym(KeySym ks
)
972 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
974 GdkEventKey
*gdk_event
)
976 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
977 // but only event->keyval which is quite useless to us, so remember
978 // the last character from GDK_KEY_PRESS and reuse it as last resort
980 // NB: should be MT-safe as we're always called from the main thread only
985 } s_lastKeyPress
= { 0, 0 };
987 KeySym keysym
= gdk_event
->keyval
;
989 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
990 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
994 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
998 // do we have the translation or is it a plain ASCII character?
999 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1001 // we should use keysym if it is ASCII as X does some translations
1002 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1003 // which we don't want here (but which we do use for OnChar())
1004 if ( !wxIsAsciiKeysym(keysym
) )
1006 keysym
= (KeySym
)gdk_event
->string
[0];
1009 // we want to always get the same key code when the same key is
1010 // pressed regardless of the state of the modifies, i.e. on a
1011 // standard US keyboard pressing '5' or '%' ('5' key with
1012 // Shift) should result in the same key code in OnKeyDown():
1013 // '5' (although OnChar() will get either '5' or '%').
1015 // to do it we first translate keysym to keycode (== scan code)
1016 // and then back but always using the lower register
1017 Display
*dpy
= (Display
*)wxGetDisplay();
1018 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1020 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1022 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1024 // use the normalized, i.e. lower register, keysym if we've
1026 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1028 // as explained above, we want to have lower register key codes
1029 // normally but for the letter keys we want to have the upper ones
1031 // NB: don't use XConvertCase() here, we want to do it for letters
1033 key_code
= toupper(key_code
);
1035 else // non ASCII key, what to do?
1037 // by default, ignore it
1040 // but if we have cached information from the last KEY_PRESS
1041 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1044 if ( keysym
== s_lastKeyPress
.keysym
)
1046 key_code
= s_lastKeyPress
.keycode
;
1051 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1053 // remember it to be reused for KEY_UP event later
1054 s_lastKeyPress
.keysym
= keysym
;
1055 s_lastKeyPress
.keycode
= key_code
;
1059 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1061 // sending unknown key events doesn't really make sense
1065 // now fill all the other fields
1068 GdkModifierType state
;
1069 if (gdk_event
->window
)
1070 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1072 event
.SetTimestamp( gdk_event
->time
);
1073 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1074 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1075 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1076 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1077 event
.m_keyCode
= key_code
;
1078 event
.m_scanCode
= gdk_event
->keyval
;
1079 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1080 event
.m_rawFlags
= 0;
1083 event
.SetEventObject( win
);
1089 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1090 GdkEventKey
*gdk_event
,
1096 wxapp_install_idle_handler();
1100 if (g_blockEventsOnDrag
)
1104 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1105 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1107 // unknown key pressed, ignore (the event would be useless anyhow)
1111 // Emit KEY_DOWN event
1112 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1117 wxWindowGTK
*ancestor
= win
;
1120 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1123 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1124 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1127 if (ancestor
->IsTopLevel())
1129 ancestor
= ancestor
->GetParent();
1132 #endif // wxUSE_ACCEL
1134 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1135 // will only be sent if it is not in an accelerator table.
1139 KeySym keysym
= gdk_event
->keyval
;
1141 // In GTK 2.0, we need to hand over the key event to an input method
1142 // and the IM will emit a "commit" event containing the actual utf8
1143 // character. In that case the EVT_CHAR events will be sent from
1144 // there. But only do it this way for non-KeySym keys.
1145 key_code
= wxTranslateKeySymToWXKey(gdk_event
->keyval
, FALSE
/* isChar */);
1146 if ( !key_code
&& win
->m_imContext
)
1148 gtk_im_context_filter_keypress ( (GtkIMContext
*) win
->m_imContext
, gdk_event
);
1154 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1155 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1158 if ( gdk_event
->length
== 1 )
1160 key_code
= (unsigned char)gdk_event
->string
[0];
1162 else if ( wxIsAsciiKeysym(keysym
) )
1165 key_code
= (unsigned char)keysym
;
1171 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1173 event
.m_keyCode
= key_code
;
1175 // Implement OnCharHook by checking ancesteror top level windows
1176 wxWindow
*parent
= win
;
1177 while (parent
&& !parent
->IsTopLevel())
1178 parent
= parent
->GetParent();
1181 event
.SetEventType( wxEVT_CHAR_HOOK
);
1182 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1187 event
.SetEventType(wxEVT_CHAR
);
1188 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1194 // win is a control: tab can be propagated up
1196 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1197 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1198 // have this style, yet choose not to process this particular TAB in which
1199 // case TAB must still work as a navigational character
1201 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1203 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1205 wxNavigationKeyEvent new_event
;
1206 new_event
.SetEventObject( win
->GetParent() );
1207 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1208 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1209 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1210 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1211 new_event
.SetCurrentFocus( win
);
1212 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1215 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1217 (gdk_event
->keyval
== GDK_Escape
) )
1219 // however only do it if we have a Cancel button in the dialog,
1220 // otherwise the user code may get confused by the events from a
1221 // non-existing button and, worse, a wxButton might get button event
1222 // from another button which is not really expected
1223 wxWindow
*winForCancel
= win
,
1225 while ( winForCancel
)
1227 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1230 // found a cancel button
1234 if ( winForCancel
->IsTopLevel() )
1236 // no need to look further
1240 // maybe our parent has a cancel button?
1241 winForCancel
= winForCancel
->GetParent();
1246 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1247 event
.SetEventObject(btnCancel
);
1248 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1254 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1262 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1268 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1271 event
.m_uniChar
= g_utf8_get_char( str
);
1273 // Backward compatible for ISO-8859
1274 if (event
.m_uniChar
< 256)
1275 event
.m_keyCode
= event
.m_uniChar
;
1277 gunichar uniChar
= g_utf8_get_char( str
);
1278 // We cannot handle Unicode in non-Unicode mode
1279 if (uniChar
> 255) return;
1281 event
.m_keyCode
= uniChar
;
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 gdk_event
1351 // NB: this has to be a macro as gdk_event type is different for different
1352 // events we're used with
1353 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1354 /* wxMouseEvent& */ event, \
1355 /* GdkEventXXX * */ gdk_event) \
1357 event.SetTimestamp( gdk_event->time ); \
1358 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1359 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1360 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1361 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1362 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1363 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1364 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1365 if (event.GetEventType()==wxEVT_MOUSEWHEEL) \
1367 if (((GdkEventButton*)gdk_event)->button == 4) \
1368 event.m_wheelRotation = 120; \
1369 else if (((GdkEventButton*)gdk_event)->button == 5) \
1370 event.m_wheelRotation = -120; \
1373 wxPoint pt = win->GetClientAreaOrigin(); \
1374 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1375 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1377 event.SetEventObject( win ); \
1378 event.SetId( win->GetId() ); \
1379 event.SetTimestamp( gdk_event->time ); \
1382 static void AdjustEventButtonState(wxMouseEvent& event)
1384 // GDK reports the old state of the button for a button press event, but
1385 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1386 // for a LEFT_DOWN event, not FALSE, so we will invert
1387 // left/right/middleDown for the corresponding click events
1389 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1390 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1391 (event
.GetEventType() == wxEVT_LEFT_UP
))
1393 event
.m_leftDown
= !event
.m_leftDown
;
1397 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1398 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1399 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1401 event
.m_middleDown
= !event
.m_middleDown
;
1405 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1406 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1407 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1409 event
.m_rightDown
= !event
.m_rightDown
;
1414 // find the window to send the mouse event too
1416 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1421 if (win
->m_wxwindow
)
1423 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1424 xx
+= pizza
->xoffset
;
1425 yy
+= pizza
->yoffset
;
1428 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1431 wxWindowGTK
*child
= node
->GetData();
1433 node
= node
->GetNext();
1434 if (!child
->IsShown())
1437 if (child
->IsTransparentForMouse())
1439 // wxStaticBox is transparent in the box itself
1440 int xx1
= child
->m_x
;
1441 int yy1
= child
->m_y
;
1442 int xx2
= child
->m_x
+ child
->m_width
;
1443 int yy2
= child
->m_y
+ child
->m_height
;
1446 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1448 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1450 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1452 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1463 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1464 (child
->m_x
<= xx
) &&
1465 (child
->m_y
<= yy
) &&
1466 (child
->m_x
+child
->m_width
>= xx
) &&
1467 (child
->m_y
+child
->m_height
>= yy
))
1480 //-----------------------------------------------------------------------------
1481 // "button_press_event"
1482 //-----------------------------------------------------------------------------
1484 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1485 GdkEventButton
*gdk_event
,
1491 wxapp_install_idle_handler();
1494 wxPrintf( wxT("1) OnButtonPress from ") );
1495 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1496 wxPrintf( win->GetClassInfo()->GetClassName() );
1497 wxPrintf( wxT(".\n") );
1499 if (!win
->m_hasVMT
) return FALSE
;
1500 if (g_blockEventsOnDrag
) return TRUE
;
1501 if (g_blockEventsOnScroll
) return TRUE
;
1503 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1505 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1507 gtk_widget_grab_focus( win
->m_wxwindow
);
1509 wxPrintf( wxT("GrabFocus from ") );
1510 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1511 wxPrintf( win->GetClassInfo()->GetClassName() );
1512 wxPrintf( wxT(".\n") );
1516 // GDK sends surplus button down event
1517 // before a double click event. We
1518 // need to filter these out.
1519 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1521 GdkEvent
*peek_event
= gdk_event_peek();
1524 if (peek_event
->type
== GDK_2BUTTON_PRESS
)
1526 gdk_event_free( peek_event
);
1531 gdk_event_free( peek_event
);
1536 wxEventType event_type
= wxEVT_NULL
;
1538 if (gdk_event
->button
== 1)
1540 switch (gdk_event
->type
)
1542 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1543 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1547 else if (gdk_event
->button
== 2)
1549 switch (gdk_event
->type
)
1551 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1552 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1556 else if (gdk_event
->button
== 3)
1558 switch (gdk_event
->type
)
1560 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1561 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1565 else if (gdk_event
->button
== 4)
1567 switch (gdk_event
->type
)
1569 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1573 else if (gdk_event
->button
== 5)
1575 switch (gdk_event
->type
)
1577 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1582 if ( event_type
== wxEVT_NULL
)
1584 // unknown mouse button or click type
1588 wxMouseEvent
event( event_type
);
1589 InitMouseEvent( win
, event
, gdk_event
);
1591 AdjustEventButtonState(event
);
1593 // wxListBox actually get mouse events from the item, so we need to give it
1594 // a chance to correct this
1595 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1597 // find the correct window to send the event too: it may be a different one
1598 // from the one which got it at GTK+ level because some control don't have
1599 // their own X window and thus cannot get any events.
1600 if ( !g_captureWindow
)
1601 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1603 gs_timeLastClick
= gdk_event
->time
;
1606 wxPrintf( wxT("2) OnButtonPress from ") );
1607 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1608 wxPrintf( win->GetClassInfo()->GetClassName() );
1609 wxPrintf( wxT(".\n") );
1613 if (event_type
== wxEVT_LEFT_DCLICK
)
1615 // GTK 1.2 crashes when intercepting double
1616 // click events from both wxSpinButton and
1618 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1620 // Just disable this event for now.
1626 if (win
->GetEventHandler()->ProcessEvent( event
))
1628 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1635 //-----------------------------------------------------------------------------
1636 // "button_release_event"
1637 //-----------------------------------------------------------------------------
1639 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1640 GdkEventButton
*gdk_event
,
1646 wxapp_install_idle_handler();
1648 if (!win
->m_hasVMT
) return FALSE
;
1649 if (g_blockEventsOnDrag
) return FALSE
;
1650 if (g_blockEventsOnScroll
) return FALSE
;
1652 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1654 wxEventType event_type
= wxEVT_NULL
;
1656 switch (gdk_event
->button
)
1659 event_type
= wxEVT_LEFT_UP
;
1663 event_type
= wxEVT_MIDDLE_UP
;
1667 event_type
= wxEVT_RIGHT_UP
;
1671 // unknwon button, don't process
1675 wxMouseEvent
event( event_type
);
1676 InitMouseEvent( win
, event
, gdk_event
);
1678 AdjustEventButtonState(event
);
1680 // same wxListBox hack as above
1681 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1683 if ( event_type
== wxEVT_RIGHT_UP
)
1685 // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
1688 // (a) it's a command event and so is propagated to the parent
1689 // (b) under MSW it can be generated from kbd too
1690 // (c) it uses screen coords (because of (a))
1691 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1693 win
->ClientToScreen(event
.GetPosition()));
1694 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1697 if ( !g_captureWindow
)
1698 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1700 if (win
->GetEventHandler()->ProcessEvent( event
))
1702 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1709 //-----------------------------------------------------------------------------
1710 // "motion_notify_event"
1711 //-----------------------------------------------------------------------------
1713 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1714 GdkEventMotion
*gdk_event
,
1720 wxapp_install_idle_handler();
1722 if (!win
->m_hasVMT
) return FALSE
;
1723 if (g_blockEventsOnDrag
) return FALSE
;
1724 if (g_blockEventsOnScroll
) return FALSE
;
1726 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1728 if (gdk_event
->is_hint
)
1732 GdkModifierType state
;
1733 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1739 printf( "OnMotion from " );
1740 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1741 printf( win->GetClassInfo()->GetClassName() );
1745 wxMouseEvent
event( wxEVT_MOTION
);
1746 InitMouseEvent(win
, event
, gdk_event
);
1748 if ( g_captureWindow
)
1750 // synthetize a mouse enter or leave event if needed
1751 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1752 // This seems to be necessary and actually been added to
1753 // GDK itself in version 2.0.X
1756 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1757 if ( hasMouse
!= g_captureWindowHasMouse
)
1759 // the mouse changed window
1760 g_captureWindowHasMouse
= hasMouse
;
1762 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1763 : wxEVT_LEAVE_WINDOW
);
1764 InitMouseEvent(win
, event
, gdk_event
);
1765 event
.SetEventObject(win
);
1766 win
->GetEventHandler()->ProcessEvent(event
);
1771 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1774 if (win
->GetEventHandler()->ProcessEvent( event
))
1776 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1783 //-----------------------------------------------------------------------------
1785 //-----------------------------------------------------------------------------
1787 // send the wxChildFocusEvent and wxFocusEvent, common code of
1788 // gtk_window_focus_in_callback() and SetFocus()
1789 static bool DoSendFocusEvents(wxWindow
*win
)
1791 // Notify the parent keeping track of focus for the kbd navigation
1792 // purposes that we got it.
1793 wxChildFocusEvent
eventChildFocus(win
);
1794 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1796 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1797 eventFocus
.SetEventObject(win
);
1799 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1802 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1803 GdkEvent
*WXUNUSED(event
),
1809 wxapp_install_idle_handler();
1811 if (!win
->m_hasVMT
) return FALSE
;
1812 if (g_blockEventsOnDrag
) return FALSE
;
1814 switch ( g_sendActivateEvent
)
1817 // we've got focus from outside, synthetize wxActivateEvent
1818 g_sendActivateEvent
= 1;
1822 // another our window just lost focus, it was already ours before
1823 // - don't send any wxActivateEvent
1824 g_sendActivateEvent
= -1;
1829 g_focusWindow
= win
;
1831 wxLogTrace(TRACE_FOCUS
,
1832 _T("%s: focus in"), win
->GetName().c_str());
1836 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1840 // caret needs to be informed about focus change
1841 wxCaret
*caret
= win
->GetCaret();
1844 caret
->OnSetFocus();
1846 #endif // wxUSE_CARET
1848 g_activeFrameLostFocus
= FALSE
;
1850 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1851 if ( active
!= g_activeFrame
)
1853 if ( g_activeFrame
)
1855 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1856 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1857 event
.SetEventObject(g_activeFrame
);
1858 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1861 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1862 g_activeFrame
= active
;
1863 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1864 event
.SetEventObject(g_activeFrame
);
1865 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1867 // Don't send focus events in addition to activate
1868 // if (win == g_activeFrame)
1872 // does the window itself think that it has the focus?
1873 if ( !win
->m_hasFocus
)
1875 // not yet, notify it
1876 win
->m_hasFocus
= TRUE
;
1878 if ( DoSendFocusEvents(win
) )
1880 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1888 //-----------------------------------------------------------------------------
1889 // "focus_out_event"
1890 //-----------------------------------------------------------------------------
1892 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1897 wxapp_install_idle_handler();
1899 if (!win
->m_hasVMT
) return FALSE
;
1900 if (g_blockEventsOnDrag
) return FALSE
;
1902 wxLogTrace( TRACE_FOCUS
,
1903 _T("%s: focus out"), win
->GetName().c_str() );
1905 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1907 // VZ: commenting this out because it does happen (although not easy
1908 // to reproduce, I only see it when using wxMiniFrame and not
1909 // always) and makes using Mahogany quite annoying
1911 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1912 wxT("unfocusing window that hasn't gained focus properly") );
1915 g_activeFrameLostFocus
= TRUE
;
1918 // if the focus goes out of our app alltogether, OnIdle() will send
1919 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1920 // g_sendActivateEvent to -1
1921 g_sendActivateEvent
= 0;
1923 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1927 g_focusWindow
= (wxWindowGTK
*)NULL
;
1935 // caret needs to be informed about focus change
1936 wxCaret
*caret
= win
->GetCaret();
1939 caret
->OnKillFocus();
1941 #endif // wxUSE_CARET
1943 // don't send the window a kill focus event if it thinks that it doesn't
1944 // have focus already
1945 if ( win
->m_hasFocus
)
1947 win
->m_hasFocus
= FALSE
;
1949 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1950 event
.SetEventObject( win
);
1952 if (win
->GetEventHandler()->ProcessEvent( event
))
1954 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1962 //-----------------------------------------------------------------------------
1963 // "enter_notify_event"
1964 //-----------------------------------------------------------------------------
1967 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1968 GdkEventCrossing
*gdk_event
,
1974 wxapp_install_idle_handler();
1976 if (!win
->m_hasVMT
) return FALSE
;
1977 if (g_blockEventsOnDrag
) return FALSE
;
1979 // Event was emitted after a grab
1980 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1982 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1986 GdkModifierType state
= (GdkModifierType
)0;
1988 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1990 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1991 InitMouseEvent(win
, event
, gdk_event
);
1992 wxPoint pt
= win
->GetClientAreaOrigin();
1993 event
.m_x
= x
+ pt
.x
;
1994 event
.m_y
= y
+ pt
.y
;
1996 if (win
->GetEventHandler()->ProcessEvent( event
))
1998 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2005 //-----------------------------------------------------------------------------
2006 // "leave_notify_event"
2007 //-----------------------------------------------------------------------------
2009 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2014 wxapp_install_idle_handler();
2016 if (!win
->m_hasVMT
) return FALSE
;
2017 if (g_blockEventsOnDrag
) return FALSE
;
2019 // Event was emitted after an ungrab
2020 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2022 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2024 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2025 event
.SetTimestamp( gdk_event
->time
);
2026 event
.SetEventObject( win
);
2030 GdkModifierType state
= (GdkModifierType
)0;
2032 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2034 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2035 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2036 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2037 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2038 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2039 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2040 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2042 wxPoint pt
= win
->GetClientAreaOrigin();
2043 event
.m_x
= x
+ pt
.x
;
2044 event
.m_y
= y
+ pt
.y
;
2046 if (win
->GetEventHandler()->ProcessEvent( event
))
2048 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2055 //-----------------------------------------------------------------------------
2056 // "value_changed" from m_vAdjust
2057 //-----------------------------------------------------------------------------
2059 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2066 wxapp_install_idle_handler();
2068 if (g_blockEventsOnDrag
) return;
2070 if (!win
->m_hasVMT
) return;
2072 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2073 if (fabs(diff
) < 0.2) return;
2075 win
->m_oldVerticalPos
= adjust
->value
;
2078 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2080 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2082 int value
= (int)(adjust
->value
+0.5);
2084 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2085 event
.SetEventObject( win
);
2086 win
->GetEventHandler()->ProcessEvent( event
);
2089 //-----------------------------------------------------------------------------
2090 // "value_changed" from m_hAdjust
2091 //-----------------------------------------------------------------------------
2093 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2100 wxapp_install_idle_handler();
2102 if (g_blockEventsOnDrag
) return;
2103 if (!win
->m_hasVMT
) return;
2105 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2106 if (fabs(diff
) < 0.2) return;
2109 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2111 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2113 win
->m_oldHorizontalPos
= adjust
->value
;
2115 int value
= (int)(adjust
->value
+0.5);
2117 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2118 event
.SetEventObject( win
);
2119 win
->GetEventHandler()->ProcessEvent( event
);
2122 //-----------------------------------------------------------------------------
2123 // "button_press_event" from scrollbar
2124 //-----------------------------------------------------------------------------
2126 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2127 GdkEventButton
*gdk_event
,
2133 wxapp_install_idle_handler();
2136 g_blockEventsOnScroll
= TRUE
;
2138 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2140 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2146 //-----------------------------------------------------------------------------
2147 // "button_release_event" from scrollbar
2148 //-----------------------------------------------------------------------------
2150 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2151 GdkEventButton
*WXUNUSED(gdk_event
),
2156 // don't test here as we can release the mouse while being over
2157 // a different window than the slider
2159 // if (gdk_event->window != widget->slider) return FALSE;
2161 g_blockEventsOnScroll
= FALSE
;
2163 if (win
->m_isScrolling
)
2165 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2169 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2170 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2172 value
= (int)(win
->m_hAdjust
->value
+0.5);
2175 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2177 value
= (int)(win
->m_vAdjust
->value
+0.5);
2181 wxScrollWinEvent
event( command
, value
, dir
);
2182 event
.SetEventObject( win
);
2183 win
->GetEventHandler()->ProcessEvent( event
);
2186 win
->m_isScrolling
= FALSE
;
2191 // ----------------------------------------------------------------------------
2192 // this wxWindowBase function is implemented here (in platform-specific file)
2193 // because it is static and so couldn't be made virtual
2194 // ----------------------------------------------------------------------------
2196 wxWindow
*wxWindowBase::FindFocus()
2198 // the cast is necessary when we compile in wxUniversal mode
2199 return (wxWindow
*)g_focusWindow
;
2203 //-----------------------------------------------------------------------------
2204 // "realize" from m_widget
2205 //-----------------------------------------------------------------------------
2207 /* We cannot set colours and fonts before the widget has
2208 been realized, so we do this directly after realization. */
2211 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2216 wxapp_install_idle_handler();
2218 if (win
->m_delayedBackgroundColour
&& !win
->GetThemeEnabled())
2219 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2221 if (win
->m_delayedForegroundColour
&& !win
->GetThemeEnabled())
2222 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2225 if (win
->m_imContext
)
2227 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2228 gtk_im_context_set_client_window( (GtkIMContext
*) win
->m_imContext
, pizza
->bin_window
);
2232 wxWindowCreateEvent
event( win
);
2233 event
.SetEventObject( win
);
2234 win
->GetEventHandler()->ProcessEvent( event
);
2239 //-----------------------------------------------------------------------------
2241 //-----------------------------------------------------------------------------
2244 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2245 GtkAllocation
*WXUNUSED(alloc
),
2249 wxapp_install_idle_handler();
2251 if (!win
->m_hasScrolling
) return;
2253 int client_width
= 0;
2254 int client_height
= 0;
2255 win
->GetClientSize( &client_width
, &client_height
);
2256 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2259 win
->m_oldClientWidth
= client_width
;
2260 win
->m_oldClientHeight
= client_height
;
2262 if (!win
->m_nativeSizeEvent
)
2264 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2265 event
.SetEventObject( win
);
2266 win
->GetEventHandler()->ProcessEvent( event
);
2272 #define WXUNUSED_UNLESS_XIM(param) param
2274 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2277 /* Resize XIM window */
2280 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2281 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2282 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2285 wxapp_install_idle_handler();
2291 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2295 gdk_window_get_size (widget
->window
, &width
, &height
);
2296 win
->m_icattr
->preedit_area
.width
= width
;
2297 win
->m_icattr
->preedit_area
.height
= height
;
2298 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2303 //-----------------------------------------------------------------------------
2304 // "realize" from m_wxwindow
2305 //-----------------------------------------------------------------------------
2307 /* Initialize XIM support */
2310 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2311 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2314 wxapp_install_idle_handler();
2317 if (win
->m_ic
) return FALSE
;
2318 if (!widget
) return FALSE
;
2319 if (!gdk_im_ready()) return FALSE
;
2321 win
->m_icattr
= gdk_ic_attr_new();
2322 if (!win
->m_icattr
) return FALSE
;
2326 GdkColormap
*colormap
;
2327 GdkICAttr
*attr
= win
->m_icattr
;
2328 unsigned attrmask
= GDK_IC_ALL_REQ
;
2330 GdkIMStyle supported_style
= (GdkIMStyle
)
2331 (GDK_IM_PREEDIT_NONE
|
2332 GDK_IM_PREEDIT_NOTHING
|
2333 GDK_IM_PREEDIT_POSITION
|
2334 GDK_IM_STATUS_NONE
|
2335 GDK_IM_STATUS_NOTHING
);
2337 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2338 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2340 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2341 attr
->client_window
= widget
->window
;
2343 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2344 gtk_widget_get_default_colormap ())
2346 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2347 attr
->preedit_colormap
= colormap
;
2350 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2351 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2352 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2353 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2355 switch (style
& GDK_IM_PREEDIT_MASK
)
2357 case GDK_IM_PREEDIT_POSITION
:
2358 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2360 g_warning ("over-the-spot style requires fontset");
2364 gdk_window_get_size (widget
->window
, &width
, &height
);
2366 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2367 attr
->spot_location
.x
= 0;
2368 attr
->spot_location
.y
= height
;
2369 attr
->preedit_area
.x
= 0;
2370 attr
->preedit_area
.y
= 0;
2371 attr
->preedit_area
.width
= width
;
2372 attr
->preedit_area
.height
= height
;
2373 attr
->preedit_fontset
= widget
->style
->font
;
2378 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2380 if (win
->m_ic
== NULL
)
2381 g_warning ("Can't create input context.");
2384 mask
= gdk_window_get_events (widget
->window
);
2385 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2386 gdk_window_set_events (widget
->window
, mask
);
2388 if (GTK_WIDGET_HAS_FOCUS(widget
))
2389 gdk_im_begin (win
->m_ic
, widget
->window
);
2396 //-----------------------------------------------------------------------------
2397 // InsertChild for wxWindowGTK.
2398 //-----------------------------------------------------------------------------
2400 /* Callback for wxWindowGTK. This very strange beast has to be used because
2401 * C++ has no virtual methods in a constructor. We have to emulate a
2402 * virtual function here as wxNotebook requires a different way to insert
2403 * a child in it. I had opted for creating a wxNotebookPage window class
2404 * which would have made this superfluous (such in the MDI window system),
2405 * but no-one was listening to me... */
2407 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2409 /* the window might have been scrolled already, do we
2410 have to adapt the position */
2411 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2412 child
->m_x
+= pizza
->xoffset
;
2413 child
->m_y
+= pizza
->yoffset
;
2415 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2416 GTK_WIDGET(child
->m_widget
),
2423 //-----------------------------------------------------------------------------
2425 //-----------------------------------------------------------------------------
2427 wxWindow
*wxGetActiveWindow()
2429 return wxWindow::FindFocus();
2432 //-----------------------------------------------------------------------------
2434 //-----------------------------------------------------------------------------
2436 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2438 #ifdef __WXUNIVERSAL__
2439 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2441 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2442 #endif // __WXUNIVERSAL__/__WXGTK__
2444 void wxWindowGTK::Init()
2450 m_widget
= (GtkWidget
*) NULL
;
2451 m_wxwindow
= (GtkWidget
*) NULL
;
2452 m_focusWidget
= (GtkWidget
*) NULL
;
2462 m_needParent
= TRUE
;
2463 m_isBeingDeleted
= FALSE
;
2466 m_nativeSizeEvent
= FALSE
;
2468 m_hasScrolling
= FALSE
;
2469 m_isScrolling
= FALSE
;
2471 m_hAdjust
= (GtkAdjustment
*) NULL
;
2472 m_vAdjust
= (GtkAdjustment
*) NULL
;
2473 m_oldHorizontalPos
=
2474 m_oldVerticalPos
= 0.0;
2476 m_oldClientHeight
= 0;
2479 m_widgetStyle
= (GtkStyle
*) NULL
;
2481 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2483 m_acceptsFocus
= FALSE
;
2486 m_clipPaintRegion
= FALSE
;
2488 m_cursor
= *wxSTANDARD_CURSOR
;
2490 m_delayedForegroundColour
= FALSE
;
2491 m_delayedBackgroundColour
= FALSE
;
2495 m_x11Context
= NULL
;
2498 m_ic
= (GdkIC
*) NULL
;
2499 m_icattr
= (GdkICAttr
*) NULL
;
2504 wxWindowGTK::wxWindowGTK()
2509 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2514 const wxString
&name
)
2518 Create( parent
, id
, pos
, size
, style
, name
);
2521 bool wxWindowGTK::Create( wxWindow
*parent
,
2526 const wxString
&name
)
2528 if (!PreCreation( parent
, pos
, size
) ||
2529 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2531 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2535 m_insertCallback
= wxInsertChildInWindow
;
2537 // always needed for background clearing
2538 m_delayedBackgroundColour
= TRUE
;
2540 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2541 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2543 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2545 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2546 scroll_class
->scrollbar_spacing
= 0;
2548 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2550 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2551 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2553 m_wxwindow
= gtk_pizza_new();
2555 #ifndef __WXUNIVERSAL__
2556 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2558 if (HasFlag(wxRAISED_BORDER
))
2560 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2562 else if (HasFlag(wxSUNKEN_BORDER
))
2564 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2566 else if (HasFlag(wxSIMPLE_BORDER
))
2568 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2572 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2574 #endif // __WXUNIVERSAL__
2576 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2578 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2579 m_acceptsFocus
= TRUE
;
2581 // I _really_ don't want scrollbars in the beginning
2582 m_vAdjust
->lower
= 0.0;
2583 m_vAdjust
->upper
= 1.0;
2584 m_vAdjust
->value
= 0.0;
2585 m_vAdjust
->step_increment
= 1.0;
2586 m_vAdjust
->page_increment
= 1.0;
2587 m_vAdjust
->page_size
= 5.0;
2588 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2589 m_hAdjust
->lower
= 0.0;
2590 m_hAdjust
->upper
= 1.0;
2591 m_hAdjust
->value
= 0.0;
2592 m_hAdjust
->step_increment
= 1.0;
2593 m_hAdjust
->page_increment
= 1.0;
2594 m_hAdjust
->page_size
= 5.0;
2595 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2597 // these handlers block mouse events to any window during scrolling such as
2598 // motion events and prevent GTK and wxWindows from fighting over where the
2601 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2602 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2604 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2605 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2607 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2608 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2610 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2611 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2613 // these handlers get notified when screen updates are required either when
2614 // scrolling or when the window size (and therefore scrollbar configuration)
2617 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2618 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2619 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2620 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2623 // Create input method handler
2624 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2626 // Cannot handle drawing preedited text yet
2627 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2629 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2630 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2633 gtk_widget_show( m_wxwindow
);
2636 m_parent
->DoAddChild( this );
2638 m_focusWidget
= m_wxwindow
;
2647 wxWindowGTK::~wxWindowGTK()
2651 if (g_focusWindow
== this)
2652 g_focusWindow
= NULL
;
2654 if (g_activeFrame
== this)
2655 g_activeFrame
= NULL
;
2657 if ( g_delayedFocus
== this )
2658 g_delayedFocus
= NULL
;
2660 m_isBeingDeleted
= TRUE
;
2669 m_parent
->RemoveChild( this );
2673 gdk_ic_destroy (m_ic
);
2675 gdk_ic_attr_destroy (m_icattr
);
2680 #if DISABLE_STYLE_IF_BROKEN_THEME
2681 // don't delete if it's a pixmap theme style
2682 if (!m_widgetStyle
->engine_data
)
2683 gtk_style_unref( m_widgetStyle
);
2685 m_widgetStyle
= (GtkStyle
*) NULL
;
2690 gtk_widget_destroy( m_wxwindow
);
2691 m_wxwindow
= (GtkWidget
*) NULL
;
2696 gtk_widget_destroy( m_widget
);
2697 m_widget
= (GtkWidget
*) NULL
;
2701 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2703 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2705 // This turns -1 into 30 so that a minimal window is
2706 // visible even although -1,-1 has been given as the
2707 // size of the window. the same trick is used in other
2708 // ports and should make debugging easier.
2709 m_width
= WidthDefault(size
.x
) ;
2710 m_height
= HeightDefault(size
.y
);
2715 // some reasonable defaults
2720 m_x
= (gdk_screen_width () - m_width
) / 2;
2721 if (m_x
< 10) m_x
= 10;
2725 m_y
= (gdk_screen_height () - m_height
) / 2;
2726 if (m_y
< 10) m_y
= 10;
2733 void wxWindowGTK::PostCreation()
2735 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2741 // these get reported to wxWindows -> wxPaintEvent
2743 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2745 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2746 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2749 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2750 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2752 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2754 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2755 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2758 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE ) );
2762 // Create input method handler
2763 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2765 // Cannot handle drawing preedited text yet
2766 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2768 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2769 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2773 // these are called when the "sunken" or "raised" borders are drawn
2774 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2775 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2778 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2779 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2785 if (m_focusWidget
== NULL
)
2786 m_focusWidget
= m_widget
;
2788 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2789 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2791 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2792 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2794 // connect to the various key and mouse handlers
2796 GtkWidget
*connect_widget
= GetConnectWidget();
2798 ConnectWidget( connect_widget
);
2800 /* We cannot set colours, fonts and cursors before the widget has
2801 been realized, so we do this directly after realization */
2802 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2803 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2807 // Catch native resize events
2808 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2809 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2811 // Initialize XIM support
2812 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2813 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2815 // And resize XIM window
2816 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2817 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2820 if ( !GTK_IS_COMBO(m_widget
))
2822 // This is needed if we want to add our windows into native
2823 // GTK control, such as the toolbar. With this callback, the
2824 // toolbar gets to know the correct size (the one set by the
2825 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2826 // when moving to GTK 2.0.
2827 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2828 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2835 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2837 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2838 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2840 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2841 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2843 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2844 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2846 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2847 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2849 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2850 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2852 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2853 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2855 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2856 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2859 bool wxWindowGTK::Destroy()
2861 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2865 return wxWindowBase::Destroy();
2868 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2870 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2873 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2875 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2876 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2879 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2882 if (m_resizing
) return; /* I don't like recursions */
2885 int currentX
, currentY
;
2886 GetPosition(¤tX
, ¤tY
);
2891 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2893 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2895 /* don't set the size for children of wxNotebook, just take the values. */
2903 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2904 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2906 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2907 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2911 m_x
= x
+ pizza
->xoffset
;
2912 m_y
= y
+ pizza
->yoffset
;
2914 if (width
!= -1) m_width
= width
;
2915 if (height
!= -1) m_height
= height
;
2917 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2919 if (width
== -1) m_width
= 80;
2922 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2924 if (height
== -1) m_height
= 26;
2927 int minWidth
= GetMinWidth(),
2928 minHeight
= GetMinHeight(),
2929 maxWidth
= GetMaxWidth(),
2930 maxHeight
= GetMaxHeight();
2932 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2933 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2934 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2935 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2938 int bottom_border
= 0;
2941 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2943 /* the default button has a border around it */
2949 DoMoveWindow( m_x
-border
,
2952 m_height
+border
+bottom_border
);
2957 /* Sometimes the client area changes size without the
2958 whole windows's size changing, but if the whole
2959 windows's size doesn't change, no wxSizeEvent will
2960 normally be sent. Here we add an extra test if
2961 the client test has been changed and this will
2963 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2967 wxPrintf( "OnSize sent from " );
2968 if (GetClassInfo() && GetClassInfo()->GetClassName())
2969 wxPrintf( GetClassInfo()->GetClassName() );
2970 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2973 if (!m_nativeSizeEvent
)
2975 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2976 event
.SetEventObject( this );
2977 GetEventHandler()->ProcessEvent( event
);
2983 void wxWindowGTK::OnInternalIdle()
2985 // Update invalidated regions.
2988 // Synthetize activate events.
2989 if ( g_sendActivateEvent
!= -1 )
2991 bool activate
= g_sendActivateEvent
!= 0;
2994 g_sendActivateEvent
= -1;
2996 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2999 if ( g_activeFrameLostFocus
)
3001 if ( g_activeFrame
)
3003 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3004 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3005 event
.SetEventObject(g_activeFrame
);
3006 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3007 g_activeFrame
= NULL
;
3009 g_activeFrameLostFocus
= FALSE
;
3012 wxCursor cursor
= m_cursor
;
3013 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3017 /* I now set the cursor anew in every OnInternalIdle call
3018 as setting the cursor in a parent window also effects the
3019 windows above so that checking for the current cursor is
3024 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3026 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3028 if (!g_globalCursor
.Ok())
3029 cursor
= *wxSTANDARD_CURSOR
;
3031 window
= m_widget
->window
;
3032 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3033 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3039 GdkWindow
*window
= m_widget
->window
;
3040 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3041 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3046 if (wxUpdateUIEvent::CanUpdate(this))
3047 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3050 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3052 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3054 if (width
) (*width
) = m_width
;
3055 if (height
) (*height
) = m_height
;
3058 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3060 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3064 SetSize( width
, height
);
3071 #ifndef __WXUNIVERSAL__
3072 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3074 /* when using GTK 1.2 we set the shadow border size to 2 */
3078 if (HasFlag(wxSIMPLE_BORDER
))
3080 /* when using GTK 1.2 we set the simple border size to 1 */
3084 #endif // __WXUNIVERSAL__
3088 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3090 GtkRequisition vscroll_req
;
3091 vscroll_req
.width
= 2;
3092 vscroll_req
.height
= 2;
3093 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3094 (scroll_window
->vscrollbar
, &vscroll_req
);
3096 GtkRequisition hscroll_req
;
3097 hscroll_req
.width
= 2;
3098 hscroll_req
.height
= 2;
3099 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3100 (scroll_window
->hscrollbar
, &hscroll_req
);
3102 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3104 if (scroll_window
->vscrollbar_visible
)
3106 dw
+= vscroll_req
.width
;
3107 dw
+= scroll_class
->scrollbar_spacing
;
3110 if (scroll_window
->hscrollbar_visible
)
3112 dh
+= hscroll_req
.height
;
3113 dh
+= scroll_class
->scrollbar_spacing
;
3117 SetSize( width
+dw
, height
+dh
);
3121 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3123 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3127 if (width
) (*width
) = m_width
;
3128 if (height
) (*height
) = m_height
;
3135 #ifndef __WXUNIVERSAL__
3136 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3138 /* when using GTK 1.2 we set the shadow border size to 2 */
3142 if (HasFlag(wxSIMPLE_BORDER
))
3144 /* when using GTK 1.2 we set the simple border size to 1 */
3148 #endif // __WXUNIVERSAL__
3152 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3154 GtkRequisition vscroll_req
;
3155 vscroll_req
.width
= 2;
3156 vscroll_req
.height
= 2;
3157 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3158 (scroll_window
->vscrollbar
, &vscroll_req
);
3160 GtkRequisition hscroll_req
;
3161 hscroll_req
.width
= 2;
3162 hscroll_req
.height
= 2;
3163 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3164 (scroll_window
->hscrollbar
, &hscroll_req
);
3166 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3168 if (scroll_window
->vscrollbar_visible
)
3170 dw
+= vscroll_req
.width
;
3171 dw
+= scroll_class
->scrollbar_spacing
;
3174 if (scroll_window
->hscrollbar_visible
)
3176 dh
+= hscroll_req
.height
;
3177 dh
+= scroll_class
->scrollbar_spacing
;
3181 if (width
) (*width
) = m_width
- dw
;
3182 if (height
) (*height
) = m_height
- dh
;
3186 printf( "GetClientSize, name %s ", GetName().c_str() );
3187 if (width) printf( " width = %d", (*width) );
3188 if (height) printf( " height = %d", (*height) );
3193 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3195 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3199 if (m_parent
&& m_parent
->m_wxwindow
)
3201 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3202 dx
= pizza
->xoffset
;
3203 dy
= pizza
->yoffset
;
3206 if (x
) (*x
) = m_x
- dx
;
3207 if (y
) (*y
) = m_y
- dy
;
3210 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3212 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3214 if (!m_widget
->window
) return;
3216 GdkWindow
*source
= (GdkWindow
*) NULL
;
3218 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3220 source
= m_widget
->window
;
3224 gdk_window_get_origin( source
, &org_x
, &org_y
);
3228 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3230 org_x
+= m_widget
->allocation
.x
;
3231 org_y
+= m_widget
->allocation
.y
;
3239 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3241 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3243 if (!m_widget
->window
) return;
3245 GdkWindow
*source
= (GdkWindow
*) NULL
;
3247 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3249 source
= m_widget
->window
;
3253 gdk_window_get_origin( source
, &org_x
, &org_y
);
3257 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3259 org_x
+= m_widget
->allocation
.x
;
3260 org_y
+= m_widget
->allocation
.y
;
3268 bool wxWindowGTK::Show( bool show
)
3270 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3272 if (!wxWindowBase::Show(show
))
3279 gtk_widget_show( m_widget
);
3281 gtk_widget_hide( m_widget
);
3283 wxShowEvent
eventShow(GetId(), show
);
3284 eventShow
.m_eventObject
= this;
3286 GetEventHandler()->ProcessEvent(eventShow
);
3291 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3293 win
->OnParentEnable(enable
);
3295 // Recurse, so that children have the opportunity to Do The Right Thing
3296 // and reset colours that have been messed up by a parent's (really ancestor's)
3298 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3300 node
= node
->GetNext() )
3302 wxWindow
*child
= node
->GetData();
3303 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3304 wxWindowNotifyEnable(child
, enable
);
3308 bool wxWindowGTK::Enable( bool enable
)
3310 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3312 if (!wxWindowBase::Enable(enable
))
3318 gtk_widget_set_sensitive( m_widget
, enable
);
3320 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3322 wxWindowNotifyEnable(this, enable
);
3327 int wxWindowGTK::GetCharHeight() const
3329 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3331 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3334 PangoContext
*context
= NULL
;
3336 context
= gtk_widget_get_pango_context( m_widget
);
3341 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3342 PangoLayout
*layout
= pango_layout_new(context
);
3343 pango_layout_set_font_description(layout
, desc
);
3344 pango_layout_set_text(layout
, "H", 1);
3345 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3347 PangoRectangle rect
;
3348 pango_layout_line_get_extents(line
, NULL
, &rect
);
3350 g_object_unref( G_OBJECT( layout
) );
3352 return (int) (rect
.height
/ PANGO_SCALE
);
3354 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3356 return font
->ascent
+ font
->descent
;
3360 int wxWindowGTK::GetCharWidth() const
3362 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3364 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3367 PangoContext
*context
= NULL
;
3369 context
= gtk_widget_get_pango_context( m_widget
);
3374 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3375 PangoLayout
*layout
= pango_layout_new(context
);
3376 pango_layout_set_font_description(layout
, desc
);
3377 pango_layout_set_text(layout
, "H", 1);
3378 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3380 PangoRectangle rect
;
3381 pango_layout_line_get_extents(line
, NULL
, &rect
);
3383 g_object_unref( G_OBJECT( layout
) );
3385 return (int) (rect
.width
/ PANGO_SCALE
);
3387 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3389 return gdk_string_width( font
, "H" );
3393 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3397 int *externalLeading
,
3398 const wxFont
*theFont
) const
3400 wxFont fontToUse
= m_font
;
3401 if (theFont
) fontToUse
= *theFont
;
3403 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3405 if (string
.IsEmpty())
3413 PangoContext
*context
= NULL
;
3415 context
= gtk_widget_get_pango_context( m_widget
);
3424 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3425 PangoLayout
*layout
= pango_layout_new(context
);
3426 pango_layout_set_font_description(layout
, desc
);
3429 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3430 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3432 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3433 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3434 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3437 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3439 PangoRectangle rect
;
3440 pango_layout_line_get_extents(line
, NULL
, &rect
);
3442 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3443 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3446 // Do something about metrics here
3449 if (externalLeading
) (*externalLeading
) = 0; // ??
3451 g_object_unref( G_OBJECT( layout
) );
3453 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3454 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3455 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3456 if (descent
) (*descent
) = font
->descent
;
3457 if (externalLeading
) (*externalLeading
) = 0; // ??
3461 void wxWindowGTK::SetFocus()
3463 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3467 // don't do anything if we already have focus
3473 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3475 gtk_widget_grab_focus (m_wxwindow
);
3480 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3482 if (!GTK_WIDGET_REALIZED(m_widget
))
3484 // we can't set the focus to the widget now so we remember that
3485 // it should be focused and will do it later, during the idle
3486 // time, as soon as we can
3487 wxLogTrace(TRACE_FOCUS
,
3488 _T("Delaying setting focus to %s(%s)"),
3489 GetClassInfo()->GetClassName(), GetLabel().c_str());
3491 g_delayedFocus
= this;
3495 wxLogTrace(TRACE_FOCUS
,
3496 _T("Setting focus to %s(%s)"),
3497 GetClassInfo()->GetClassName(), GetLabel().c_str());
3499 gtk_widget_grab_focus (m_widget
);
3502 else if (GTK_IS_CONTAINER(m_widget
))
3504 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3508 wxLogTrace(TRACE_FOCUS
,
3509 _T("Can't set focus to %s(%s)"),
3510 GetClassInfo()->GetClassName(), GetLabel().c_str());
3515 bool wxWindowGTK::AcceptsFocus() const
3517 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3520 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3522 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3524 wxWindowGTK
*oldParent
= m_parent
,
3525 *newParent
= (wxWindowGTK
*)newParentBase
;
3527 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3529 if ( !wxWindowBase::Reparent(newParent
) )
3532 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3534 /* prevent GTK from deleting the widget arbitrarily */
3535 gtk_widget_ref( m_widget
);
3539 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3542 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3546 /* insert GTK representation */
3547 (*(newParent
->m_insertCallback
))(newParent
, this);
3550 /* reverse: prevent GTK from deleting the widget arbitrarily */
3551 gtk_widget_unref( m_widget
);
3556 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3558 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3560 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3562 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3567 /* insert GTK representation */
3568 (*m_insertCallback
)(this, child
);
3571 void wxWindowGTK::Raise()
3573 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3575 if (!m_widget
->window
) return;
3577 gdk_window_raise( m_widget
->window
);
3580 void wxWindowGTK::Lower()
3582 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3584 if (!m_widget
->window
) return;
3586 gdk_window_lower( m_widget
->window
);
3589 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3591 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3593 if (cursor
== m_cursor
)
3597 wxapp_install_idle_handler();
3599 if (cursor
== wxNullCursor
)
3600 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3602 return wxWindowBase::SetCursor( cursor
);
3605 void wxWindowGTK::WarpPointer( int x
, int y
)
3607 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3609 // We provide this function ourselves as it is
3610 // missing in GDK (top of this file).
3612 GdkWindow
*window
= (GdkWindow
*) NULL
;
3614 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3616 window
= GetConnectWidget()->window
;
3619 gdk_window_warp_pointer( window
, x
, y
);
3623 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3625 if (!m_widget
) return;
3626 if (!m_widget
->window
) return;
3630 wxapp_install_idle_handler();
3632 wxRect
myRect(0,0,0,0);
3633 if (m_wxwindow
&& rect
)
3635 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3636 m_wxwindow
->allocation
.height
));
3637 myRect
.Intersect(*rect
);
3638 if (!myRect
.width
|| !myRect
.height
)
3639 // nothing to do, rectangle is empty
3644 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3648 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3649 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3653 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3654 m_clearRegion
.Clear();
3655 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3663 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3664 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3668 GdkRectangle gdk_rect
;
3669 gdk_rect
.x
= rect
->x
;
3670 gdk_rect
.y
= rect
->y
;
3671 gdk_rect
.width
= rect
->width
;
3672 gdk_rect
.height
= rect
->height
;
3673 gtk_widget_draw( m_widget
, &gdk_rect
);
3680 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3681 m_updateRegion
.Clear();
3682 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3686 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3694 GdkRectangle gdk_rect
;
3695 gdk_rect
.x
= rect
->x
;
3696 gdk_rect
.y
= rect
->y
;
3697 gdk_rect
.width
= rect
->width
;
3698 gdk_rect
.height
= rect
->height
;
3699 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3703 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3709 void wxWindowGTK::Update()
3714 void wxWindowGTK::GtkUpdate()
3717 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3718 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3720 if (!m_updateRegion
.IsEmpty())
3721 GtkSendPaintEvents();
3725 void wxWindowGTK::GtkSendPaintEvents()
3730 m_clearRegion
.Clear();
3732 m_updateRegion
.Clear();
3736 // Clip to paint region in wxClientDC
3737 m_clipPaintRegion
= TRUE
;
3740 // widget to draw on
3741 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3743 // later for GTK 2.0, too.
3744 if (GetThemeEnabled())
3746 // find ancestor from which to steal background
3747 wxWindow
*parent
= GetParent();
3748 while (parent
&& !parent
->IsTopLevel())
3749 parent
= parent
->GetParent();
3751 parent
= (wxWindow
*)this;
3753 wxRegionIterator
upd( m_updateRegion
);
3757 rect
.x
= upd
.GetX();
3758 rect
.y
= upd
.GetY();
3759 rect
.width
= upd
.GetWidth();
3760 rect
.height
= upd
.GetHeight();
3762 gtk_paint_flat_box( parent
->m_widget
->style
,
3779 wxWindowDC
dc( (wxWindow
*)this );
3780 dc
.SetClippingRegion( m_updateRegion
);
3782 wxEraseEvent
erase_event( GetId(), &dc
);
3783 erase_event
.SetEventObject( this );
3785 GetEventHandler()->ProcessEvent(erase_event
);
3788 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3790 wxWindowDC
dc( (wxWindow
*)this );
3791 if (m_clearRegion
.IsEmpty())
3792 dc
.SetClippingRegion( m_updateRegion
);
3794 dc
.SetClippingRegion( m_clearRegion
);
3796 wxEraseEvent
erase_event( GetId(), &dc
);
3797 erase_event
.SetEventObject( this );
3799 if (!GetEventHandler()->ProcessEvent(erase_event
))
3803 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3804 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3806 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3808 wxRegionIterator
upd( m_clearRegion
);
3811 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3812 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3816 m_clearRegion
.Clear();
3820 wxNcPaintEvent
nc_paint_event( GetId() );
3821 nc_paint_event
.SetEventObject( this );
3822 GetEventHandler()->ProcessEvent( nc_paint_event
);
3824 wxPaintEvent
paint_event( GetId() );
3825 paint_event
.SetEventObject( this );
3826 GetEventHandler()->ProcessEvent( paint_event
);
3828 m_clipPaintRegion
= FALSE
;
3830 #ifndef __WXUNIVERSAL__
3832 // The following code will result in all window-less widgets
3833 // being redrawn because the wxWindows class is allowed to
3834 // paint over the window-less widgets.
3836 GList
*children
= pizza
->children
;
3839 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3840 children
= children
->next
;
3842 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3843 GTK_WIDGET_DRAWABLE (child
->widget
))
3845 // Get intersection of widget area and update region
3846 wxRegion
region( m_updateRegion
);
3848 GdkEventExpose gdk_event
;
3849 gdk_event
.type
= GDK_EXPOSE
;
3850 gdk_event
.window
= pizza
->bin_window
;
3851 gdk_event
.count
= 0;
3853 wxRegionIterator
upd( m_updateRegion
);
3857 rect
.x
= upd
.GetX();
3858 rect
.y
= upd
.GetY();
3859 rect
.width
= upd
.GetWidth();
3860 rect
.height
= upd
.GetHeight();
3862 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3864 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3874 m_updateRegion
.Clear();
3877 void wxWindowGTK::ClearBackground()
3879 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3882 if (m_wxwindow
&& m_wxwindow
->window
)
3884 m_clearRegion
.Clear();
3885 wxSize
size( GetClientSize() );
3886 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3888 // Better do this in idle?
3895 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3897 wxWindowBase::DoSetToolTip(tip
);
3900 m_tooltip
->Apply( (wxWindow
*)this );
3903 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3905 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3907 #endif // wxUSE_TOOLTIPS
3909 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3911 GdkWindow
*window
= (GdkWindow
*) NULL
;
3913 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3915 window
= GetConnectWidget()->window
;
3919 // We need the pixel value e.g. for background clearing.
3920 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3924 // wxMSW doesn't clear the window here, either.
3925 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3931 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3933 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3935 if (!wxWindowBase::SetBackgroundColour(colour
))
3938 GdkWindow
*window
= (GdkWindow
*) NULL
;
3940 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3942 window
= GetConnectWidget()->window
;
3946 // indicate that a new style has been set
3947 // but it couldn't get applied as the
3948 // widget hasn't been realized yet.
3949 m_delayedBackgroundColour
= TRUE
;
3954 GtkSetBackgroundColour( colour
);
3960 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3962 GdkWindow
*window
= (GdkWindow
*) NULL
;
3964 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3966 window
= GetConnectWidget()->window
;
3973 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3975 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3977 if (!wxWindowBase::SetForegroundColour(colour
))
3979 // don't leave if the GTK widget has just
3981 if (!m_delayedForegroundColour
) return FALSE
;
3984 GdkWindow
*window
= (GdkWindow
*) NULL
;
3986 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3988 window
= GetConnectWidget()->window
;
3992 // indicate that a new style has been set
3993 // but it couldn't get applied as the
3994 // widget hasn't been realized yet.
3995 m_delayedForegroundColour
= TRUE
;
3999 GtkSetForegroundColour( colour
);
4006 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4008 return gtk_widget_get_pango_context( m_widget
);
4011 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4014 m_x11Context
= pango_x_get_context( gdk_display
);
4016 return m_x11Context
;
4020 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4024 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4026 // FIXME: no more klass in 2.0
4028 remake
->klass
= m_widgetStyle
->klass
;
4031 gtk_style_unref( m_widgetStyle
);
4032 m_widgetStyle
= remake
;
4036 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4039 def
= gtk_widget_get_default_style();
4041 m_widgetStyle
= gtk_style_copy( def
);
4043 // FIXME: no more klass in 2.0
4045 m_widgetStyle
->klass
= def
->klass
;
4049 return m_widgetStyle
;
4052 void wxWindowGTK::SetWidgetStyle()
4054 #if DISABLE_STYLE_IF_BROKEN_THEME
4055 if (m_widget
->style
->engine_data
)
4057 static bool s_warningPrinted
= FALSE
;
4058 if (!s_warningPrinted
)
4060 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
4061 s_warningPrinted
= TRUE
;
4063 m_widgetStyle
= m_widget
->style
;
4068 GtkStyle
*style
= GetWidgetStyle();
4070 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
4073 pango_font_description_free( style
->font_desc
);
4074 style
->font_desc
= pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4076 gdk_font_unref( style
->font
);
4077 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4081 if (m_foregroundColour
.Ok())
4083 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4084 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4086 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4087 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4088 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4092 // Try to restore the gtk default style. This is still a little
4093 // oversimplified for what is probably really needed here for controls
4094 // other than buttons, but is better than not being able to (re)set a
4095 // control's foreground colour to *wxBLACK -- RL
4096 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4099 def
= gtk_widget_get_default_style();
4101 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4102 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4103 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4107 if (m_backgroundColour
.Ok())
4109 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4110 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4112 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4113 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4114 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4115 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4116 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4117 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4118 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4119 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4123 // Try to restore the gtk default style. This is still a little
4124 // oversimplified for what is probably really needed here for controls
4125 // other than buttons, but is better than not being able to (re)set a
4126 // control's background colour to default grey and means resetting a
4127 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4129 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4132 def
= gtk_widget_get_default_style();
4134 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4135 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4136 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4137 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4138 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4139 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4140 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4141 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4146 void wxWindowGTK::ApplyWidgetStyle()
4150 //-----------------------------------------------------------------------------
4151 // Pop-up menu stuff
4152 //-----------------------------------------------------------------------------
4154 #if wxUSE_MENUS_NATIVE
4157 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4159 *is_waiting
= FALSE
;
4162 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4164 menu
->SetInvokingWindow( win
);
4165 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4168 wxMenuItem
*menuitem
= node
->GetData();
4169 if (menuitem
->IsSubMenu())
4171 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4174 node
= node
->GetNext();
4178 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
4179 // wxPopupMenuPositionCallback()
4181 // should be safe even in the MT case as the user can hardly popup 2 menus
4182 // simultaneously, can he?
4183 static gint gs_pop_x
= 0;
4184 static gint gs_pop_y
= 0;
4186 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4189 gboolean
* WXUNUSED(whatever
),
4191 gpointer
WXUNUSED(user_data
) )
4193 // ensure that the menu appears entirely on screen
4195 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4197 wxSize sizeScreen
= wxGetDisplaySize();
4199 gint xmax
= sizeScreen
.x
- req
.width
,
4200 ymax
= sizeScreen
.y
- req
.height
;
4202 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
4203 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
4206 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4208 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4210 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
4212 SetInvokingWindow( menu
, this );
4218 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
4220 bool is_waiting
= TRUE
;
4222 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4224 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4225 (gpointer
)&is_waiting
);
4228 GTK_MENU(menu
->m_menu
),
4229 (GtkWidget
*) NULL
, // parent menu shell
4230 (GtkWidget
*) NULL
, // parent menu item
4231 wxPopupMenuPositionCallback
, // function to position it
4232 NULL
, // client data
4233 0, // button used to activate it
4235 gtk_get_current_event_time()
4237 gs_timeLastClick
// the time of activation
4243 gtk_main_iteration();
4249 #endif // wxUSE_MENUS_NATIVE
4251 #if wxUSE_DRAG_AND_DROP
4253 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4255 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4257 GtkWidget
*dnd_widget
= GetConnectWidget();
4259 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4261 if (m_dropTarget
) delete m_dropTarget
;
4262 m_dropTarget
= dropTarget
;
4264 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4267 #endif // wxUSE_DRAG_AND_DROP
4269 GtkWidget
* wxWindowGTK::GetConnectWidget()
4271 GtkWidget
*connect_widget
= m_widget
;
4272 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4274 return connect_widget
;
4277 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4280 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4282 return (window
== m_widget
->window
);
4285 bool wxWindowGTK::SetFont( const wxFont
&font
)
4287 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4289 if (!wxWindowBase::SetFont(font
))
4294 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4295 if ( sysbg
== m_backgroundColour
)
4297 m_backgroundColour
= wxNullColour
;
4299 m_backgroundColour
= sysbg
;
4309 void wxWindowGTK::DoCaptureMouse()
4311 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4313 GdkWindow
*window
= (GdkWindow
*) NULL
;
4315 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4317 window
= GetConnectWidget()->window
;
4319 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4321 wxCursor
* cursor
= & m_cursor
;
4323 cursor
= wxSTANDARD_CURSOR
;
4325 gdk_pointer_grab( window
, FALSE
,
4327 (GDK_BUTTON_PRESS_MASK
|
4328 GDK_BUTTON_RELEASE_MASK
|
4329 GDK_POINTER_MOTION_HINT_MASK
|
4330 GDK_POINTER_MOTION_MASK
),
4332 cursor
->GetCursor(),
4333 (guint32
)GDK_CURRENT_TIME
);
4334 g_captureWindow
= this;
4335 g_captureWindowHasMouse
= TRUE
;
4338 void wxWindowGTK::DoReleaseMouse()
4340 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4342 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4344 g_captureWindow
= (wxWindowGTK
*) NULL
;
4346 GdkWindow
*window
= (GdkWindow
*) NULL
;
4348 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4350 window
= GetConnectWidget()->window
;
4355 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4359 wxWindow
*wxWindowBase::GetCapture()
4361 return (wxWindow
*)g_captureWindow
;
4364 bool wxWindowGTK::IsRetained() const
4369 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4370 int range
, bool refresh
)
4372 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4374 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4376 m_hasScrolling
= TRUE
;
4378 if (orient
== wxHORIZONTAL
)
4380 float fpos
= (float)pos
;
4381 float frange
= (float)range
;
4382 float fthumb
= (float)thumbVisible
;
4383 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4384 if (fpos
< 0.0) fpos
= 0.0;
4386 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4387 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4389 SetScrollPos( orient
, pos
, refresh
);
4393 m_oldHorizontalPos
= fpos
;
4395 m_hAdjust
->lower
= 0.0;
4396 m_hAdjust
->upper
= frange
;
4397 m_hAdjust
->value
= fpos
;
4398 m_hAdjust
->step_increment
= 1.0;
4399 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4400 m_hAdjust
->page_size
= fthumb
;
4404 float fpos
= (float)pos
;
4405 float frange
= (float)range
;
4406 float fthumb
= (float)thumbVisible
;
4407 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4408 if (fpos
< 0.0) fpos
= 0.0;
4410 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4411 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4413 SetScrollPos( orient
, pos
, refresh
);
4417 m_oldVerticalPos
= fpos
;
4419 m_vAdjust
->lower
= 0.0;
4420 m_vAdjust
->upper
= frange
;
4421 m_vAdjust
->value
= fpos
;
4422 m_vAdjust
->step_increment
= 1.0;
4423 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4424 m_vAdjust
->page_size
= fthumb
;
4427 if (orient
== wxHORIZONTAL
)
4428 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4430 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4433 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4435 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4437 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4439 if (orient
== wxHORIZONTAL
)
4441 float fpos
= (float)pos
;
4442 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4443 if (fpos
< 0.0) fpos
= 0.0;
4444 m_oldHorizontalPos
= fpos
;
4446 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4447 m_hAdjust
->value
= fpos
;
4451 float fpos
= (float)pos
;
4452 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4453 if (fpos
< 0.0) fpos
= 0.0;
4454 m_oldVerticalPos
= fpos
;
4456 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4457 m_vAdjust
->value
= fpos
;
4460 if (m_wxwindow
->window
)
4462 if (orient
== wxHORIZONTAL
)
4464 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4465 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4467 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4469 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4470 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4474 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4475 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4477 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4479 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4480 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4485 int wxWindowGTK::GetScrollThumb( int orient
) const
4487 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4489 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4491 if (orient
== wxHORIZONTAL
)
4492 return (int)(m_hAdjust
->page_size
+0.5);
4494 return (int)(m_vAdjust
->page_size
+0.5);
4497 int wxWindowGTK::GetScrollPos( int orient
) const
4499 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4501 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4503 if (orient
== wxHORIZONTAL
)
4504 return (int)(m_hAdjust
->value
+0.5);
4506 return (int)(m_vAdjust
->value
+0.5);
4509 int wxWindowGTK::GetScrollRange( int orient
) const
4511 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4513 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4515 if (orient
== wxHORIZONTAL
)
4516 return (int)(m_hAdjust
->upper
+0.5);
4518 return (int)(m_vAdjust
->upper
+0.5);
4521 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4523 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4525 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4527 // No scrolling requested.
4528 if ((dx
== 0) && (dy
== 0)) return;
4531 if (!m_updateRegion
.IsEmpty())
4533 m_updateRegion
.Offset( dx
, dy
);
4537 GetClientSize( &cw
, &ch
);
4538 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4541 if (!m_clearRegion
.IsEmpty())
4543 m_clearRegion
.Offset( dx
, dy
);
4547 GetClientSize( &cw
, &ch
);
4548 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4552 m_clipPaintRegion
= TRUE
;
4554 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4556 m_clipPaintRegion
= FALSE
;
4560 // Find the wxWindow at the current mouse position, also returning the mouse
4562 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4564 pt
= wxGetMousePosition();
4565 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4569 // Get the current mouse position.
4570 wxPoint
wxGetMousePosition()
4572 /* This crashes when used within wxHelpContext,
4573 so we have to use the X-specific implementation below.
4575 GdkModifierType *mask;
4576 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4578 return wxPoint(x, y);
4582 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4584 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4585 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4586 Window rootReturn
, childReturn
;
4587 int rootX
, rootY
, winX
, winY
;
4588 unsigned int maskReturn
;
4590 XQueryPointer (display
,
4594 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4595 return wxPoint(rootX
, rootY
);
4599 // ----------------------------------------------------------------------------
4601 // ----------------------------------------------------------------------------
4603 class wxWinModule
: public wxModule
4610 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4613 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4615 bool wxWinModule::OnInit()
4617 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4618 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4623 void wxWinModule::OnExit()
4626 gdk_gc_unref( g_eraseGC
);