1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
19 #define XWarpPointer XWARPPOINTER
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
26 #include "wx/layout.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
32 #if wxUSE_DRAG_AND_DROP
37 #include "wx/tooltip.h"
45 #include "wx/textctrl.h"
49 #include "wx/statusbr.h"
51 #include "wx/settings.h"
53 #include "wx/fontutil.h"
56 #include "wx/thread.h"
62 #include "wx/gtk/private.h"
63 #include <gdk/gdkprivate.h>
64 #include <gdk/gdkkeysyms.h>
68 #include <gtk/gtkprivate.h>
70 #include "wx/gtk/win_gtk.h"
73 #include <pango/pangox.h>
77 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
79 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
89 extern GtkContainerClass
*pizza_parent_class
;
92 //-----------------------------------------------------------------------------
93 // documentation on internals
94 //-----------------------------------------------------------------------------
97 I have been asked several times about writing some documentation about
98 the GTK port of wxWidgets, especially its internal structures. Obviously,
99 you cannot understand wxGTK without knowing a little about the GTK, but
100 some more information about what the wxWindow, which is the base class
101 for all other window classes, does seems required as well.
105 What does wxWindow do? It contains the common interface for the following
106 jobs of its descendants:
108 1) Define the rudimentary behaviour common to all window classes, such as
109 resizing, intercepting user input (so as to make it possible to use these
110 events for special purposes in a derived class), window names etc.
112 2) Provide the possibility to contain and manage children, if the derived
113 class is allowed to contain children, which holds true for those window
114 classes which do not display a native GTK widget. To name them, these
115 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
116 work classes are a special case and are handled a bit differently from
117 the rest. The same holds true for the wxNotebook class.
119 3) Provide the possibility to draw into a client area of a window. This,
120 too, only holds true for classes that do not display a native GTK widget
123 4) Provide the entire mechanism for scrolling widgets. This actual inter-
124 face for this is usually in wxScrolledWindow, but the GTK implementation
127 5) A multitude of helper or extra methods for special purposes, such as
128 Drag'n'Drop, managing validators etc.
130 6) Display a border (sunken, raised, simple or none).
132 Normally one might expect, that one wxWidgets window would always correspond
133 to one GTK widget. Under GTK, there is no such allround widget that has all
134 the functionality. Moreover, the GTK defines a client area as a different
135 widget from the actual widget you are handling. Last but not least some
136 special classes (e.g. wxFrame) handle different categories of widgets and
137 still have the possibility to draw something in the client area.
138 It was therefore required to write a special purpose GTK widget, that would
139 represent a client area in the sense of wxWidgets capable to do the jobs
140 2), 3) and 4). I have written this class and it resides in win_gtk.c of
143 All windows must have a widget, with which they interact with other under-
144 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
145 thw wxWindow class has a member variable called m_widget which holds a
146 pointer to this widget. When the window class represents a GTK native widget,
147 this is (in most cases) the only GTK widget the class manages. E.g. the
148 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 wxWidgets class. If not, all input to the widget
169 that gets pointed to by m_widget gets intercepted and sent to the class.
173 The design of scrolling in wxWidgets is markedly different from that offered
174 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
175 clicking on a scrollbar belonging to scrolled window will inevitably move
176 the window. In wxWidgets, the scrollbar will only emit an event, send this
177 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
178 which actually moves the window and its subchildren. Note that GtkPizza
179 memorizes how much it has been scrolled but that wxWidgets forgets this
180 so that the two coordinates systems have to be kept in synch. This is done
181 in various places using the pizza->xoffset and pizza->yoffset values.
185 Singularily the most broken code in GTK is the code that is supposes to
186 inform subwindows (child windows) about new positions. Very often, duplicate
187 events are sent without changes in size or position, equally often no
188 events are sent at all (All this is due to a bug in the GtkContainer code
189 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
190 GTK's own system and it simply waits for size events for toplevel windows
191 and then iterates down the respective size events to all window. This has
192 the disadvantage, that windows might get size events before the GTK widget
193 actually has the reported size. This doesn't normally pose any problem, but
194 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
195 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
196 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
197 window that is used for OpenGl output really has that size (as reported by
202 If someone at some point of time feels the immense desire to have a look at,
203 change or attempt to optimse the Refresh() logic, this person will need an
204 intimate understanding of what a "draw" and what an "expose" events are and
205 what there are used for, in particular when used in connection with GTK's
206 own windowless widgets. Beware.
210 Cursors, too, have been a constant source of pleasure. The main difficulty
211 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
212 for the parent. To prevent this from doing too much harm, I use idle time
213 to set the cursor over and over again, starting from the toplevel windows
214 and ending with the youngest generation (speaking of parent and child windows).
215 Also don't forget that cursors (like much else) are connected to GdkWindows,
216 not GtkWidgets and that the "window" field of a GtkWidget might very well
217 point to the GdkWindow of the parent widget (-> "window less widget") and
218 that the two obviously have very different meanings.
222 //-----------------------------------------------------------------------------
224 //-----------------------------------------------------------------------------
226 extern wxList wxPendingDelete
;
227 extern bool g_blockEventsOnDrag
;
228 extern bool g_blockEventsOnScroll
;
229 extern wxCursor g_globalCursor
;
231 static GdkGC
*g_eraseGC
= NULL
;
233 // mouse capture state: the window which has it and if the mouse is currently
235 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
236 static bool g_captureWindowHasMouse
= FALSE
;
238 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
240 // the last window which had the focus - this is normally never NULL (except
241 // if we never had focus at all) as even when g_focusWindow is NULL it still
242 // keeps its previous value
243 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
245 // the frame that is currently active (i.e. its child has focus). It is
246 // used to generate wxActivateEvents
247 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
248 static bool g_activeFrameLostFocus
= FALSE
;
250 // If a window get the focus set but has not been realized
251 // yet, defer setting the focus to idle time.
252 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
254 // if we detect that the app has got/lost the focus, we set this variable to
255 // either TRUE or FALSE and an activate event will be sent during the next
256 // OnIdle() call and it is reset to -1: this value means that we shouldn't
257 // send any activate events at all
258 static int g_sendActivateEvent
= -1;
260 // hack: we need something to pass to gtk_menu_popup, so we store the time of
261 // the last click here
262 static guint32 gs_timeLastClick
= 0;
264 extern bool g_mainThreadLocked
;
266 //-----------------------------------------------------------------------------
268 //-----------------------------------------------------------------------------
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 // if there are any children we must refresh everything
617 if ( !win
->HasFlag(wxFULL_REPAINT_ON_RESIZE
) &&
618 win
->GetChildren().IsEmpty() )
626 wxPrintf( wxT("OnDraw from ") );
627 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
628 wxPrintf( win
->GetClassInfo()->GetClassName() );
629 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
636 #ifndef __WXUNIVERSAL__
637 GtkPizza
*pizza
= GTK_PIZZA (widget
);
639 if (win
->GetThemeEnabled())
641 wxWindow
*parent
= win
->GetParent();
642 while (parent
&& !parent
->IsTopLevel())
643 parent
= parent
->GetParent();
647 gtk_paint_flat_box (parent
->m_widget
->style
,
658 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
659 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
661 // Update immediately, not in idle time.
664 #ifndef __WXUNIVERSAL__
665 // Redraw child widgets
666 GList
*children
= pizza
->children
;
669 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
670 children
= children
->next
;
672 GdkRectangle child_area
;
673 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
675 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
683 //-----------------------------------------------------------------------------
684 // "key_press_event" from any window
685 //-----------------------------------------------------------------------------
687 // set WXTRACE to this to see the key event codes on the console
688 #define TRACE_KEYS _T("keyevent")
690 // translates an X key symbol to WXK_XXX value
692 // if isChar is true it means that the value returned will be used for EVT_CHAR
693 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
694 // for example, while if it is false it means that the value is going to be
695 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
697 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
703 // Shift, Control and Alt don't generate the CHAR events at all
706 key_code
= isChar
? 0 : WXK_SHIFT
;
710 key_code
= isChar
? 0 : WXK_CONTROL
;
718 key_code
= isChar
? 0 : WXK_ALT
;
721 // neither do the toggle modifies
722 case GDK_Scroll_Lock
:
723 key_code
= isChar
? 0 : WXK_SCROLL
;
727 key_code
= isChar
? 0 : WXK_CAPITAL
;
731 key_code
= isChar
? 0 : WXK_NUMLOCK
;
735 // various other special keys
748 case GDK_ISO_Left_Tab
:
755 key_code
= WXK_RETURN
;
759 key_code
= WXK_CLEAR
;
763 key_code
= WXK_PAUSE
;
767 key_code
= WXK_SELECT
;
771 key_code
= WXK_PRINT
;
775 key_code
= WXK_EXECUTE
;
779 key_code
= WXK_ESCAPE
;
782 // cursor and other extended keyboard keys
784 key_code
= WXK_DELETE
;
800 key_code
= WXK_RIGHT
;
807 case GDK_Prior
: // == GDK_Page_Up
808 key_code
= WXK_PRIOR
;
811 case GDK_Next
: // == GDK_Page_Down
824 key_code
= WXK_INSERT
;
839 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
843 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
847 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
851 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
855 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
859 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
863 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
867 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
871 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
875 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
879 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
883 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
887 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
890 case GDK_KP_Prior
: // == GDK_KP_Page_Up
891 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
894 case GDK_KP_Next
: // == GDK_KP_Page_Down
895 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
899 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
903 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
907 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
911 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
915 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
918 case GDK_KP_Multiply
:
919 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
923 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
926 case GDK_KP_Separator
:
927 // FIXME: what is this?
928 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
931 case GDK_KP_Subtract
:
932 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
936 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
940 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
957 key_code
= WXK_F1
+ keysym
- GDK_F1
;
967 static inline bool wxIsAsciiKeysym(KeySym ks
)
973 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
975 GdkEventKey
*gdk_event
)
977 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
978 // but only event->keyval which is quite useless to us, so remember
979 // the last character from GDK_KEY_PRESS and reuse it as last resort
981 // NB: should be MT-safe as we're always called from the main thread only
986 } s_lastKeyPress
= { 0, 0 };
988 KeySym keysym
= gdk_event
->keyval
;
990 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
991 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
995 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
999 // do we have the translation or is it a plain ASCII character?
1000 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1002 // we should use keysym if it is ASCII as X does some translations
1003 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1004 // which we don't want here (but which we do use for OnChar())
1005 if ( !wxIsAsciiKeysym(keysym
) )
1007 keysym
= (KeySym
)gdk_event
->string
[0];
1010 // we want to always get the same key code when the same key is
1011 // pressed regardless of the state of the modifies, i.e. on a
1012 // standard US keyboard pressing '5' or '%' ('5' key with
1013 // Shift) should result in the same key code in OnKeyDown():
1014 // '5' (although OnChar() will get either '5' or '%').
1016 // to do it we first translate keysym to keycode (== scan code)
1017 // and then back but always using the lower register
1018 Display
*dpy
= (Display
*)wxGetDisplay();
1019 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1021 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1023 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1025 // use the normalized, i.e. lower register, keysym if we've
1027 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1029 // as explained above, we want to have lower register key codes
1030 // normally but for the letter keys we want to have the upper ones
1032 // NB: don't use XConvertCase() here, we want to do it for letters
1034 key_code
= toupper(key_code
);
1036 else // non ASCII key, what to do?
1038 // by default, ignore it
1041 // but if we have cached information from the last KEY_PRESS
1042 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1045 if ( keysym
== s_lastKeyPress
.keysym
)
1047 key_code
= s_lastKeyPress
.keycode
;
1052 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1054 // remember it to be reused for KEY_UP event later
1055 s_lastKeyPress
.keysym
= keysym
;
1056 s_lastKeyPress
.keycode
= key_code
;
1060 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1062 // sending unknown key events doesn't really make sense
1066 // now fill all the other fields
1069 GdkModifierType state
;
1070 if (gdk_event
->window
)
1071 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1073 event
.SetTimestamp( gdk_event
->time
);
1074 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1075 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1076 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1077 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1078 event
.m_keyCode
= key_code
;
1079 event
.m_scanCode
= gdk_event
->keyval
;
1080 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1081 event
.m_rawFlags
= 0;
1084 event
.SetEventObject( win
);
1090 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1091 GdkEventKey
*gdk_event
,
1097 wxapp_install_idle_handler();
1101 if (g_blockEventsOnDrag
)
1105 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1106 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1108 // unknown key pressed, ignore (the event would be useless anyhow)
1112 // Emit KEY_DOWN event
1113 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1118 wxWindowGTK
*ancestor
= win
;
1121 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1124 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1125 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1128 if (ancestor
->IsTopLevel())
1130 ancestor
= ancestor
->GetParent();
1133 #endif // wxUSE_ACCEL
1135 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1136 // will only be sent if it is not in an accelerator table.
1140 KeySym keysym
= gdk_event
->keyval
;
1142 // In GTK 2.0, we need to hand over the key event to an input method
1143 // and the IM will emit a "commit" event containing the actual utf8
1144 // character. In that case the EVT_CHAR events will be sent from
1145 // there. But only do it this way for non-KeySym keys.
1146 key_code
= wxTranslateKeySymToWXKey(gdk_event
->keyval
, FALSE
/* isChar */);
1147 if ( !key_code
&& win
->m_imContext
)
1149 gtk_im_context_filter_keypress ( (GtkIMContext
*) win
->m_imContext
, gdk_event
);
1155 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1156 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1159 if ( gdk_event
->length
== 1 )
1161 key_code
= (unsigned char)gdk_event
->string
[0];
1163 else if ( wxIsAsciiKeysym(keysym
) )
1166 key_code
= (unsigned char)keysym
;
1172 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1174 event
.m_keyCode
= key_code
;
1176 // Implement OnCharHook by checking ancesteror top level windows
1177 wxWindow
*parent
= win
;
1178 while (parent
&& !parent
->IsTopLevel())
1179 parent
= parent
->GetParent();
1182 event
.SetEventType( wxEVT_CHAR_HOOK
);
1183 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1188 event
.SetEventType(wxEVT_CHAR
);
1189 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1195 // win is a control: tab can be propagated up
1197 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1198 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1199 // have this style, yet choose not to process this particular TAB in which
1200 // case TAB must still work as a navigational character
1202 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1204 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1206 wxNavigationKeyEvent new_event
;
1207 new_event
.SetEventObject( win
->GetParent() );
1208 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1209 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1210 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1211 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1212 new_event
.SetCurrentFocus( win
);
1213 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1216 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1218 (gdk_event
->keyval
== GDK_Escape
) )
1220 // however only do it if we have a Cancel button in the dialog,
1221 // otherwise the user code may get confused by the events from a
1222 // non-existing button and, worse, a wxButton might get button event
1223 // from another button which is not really expected
1224 wxWindow
*winForCancel
= win
,
1226 while ( winForCancel
)
1228 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1231 // found a cancel button
1235 if ( winForCancel
->IsTopLevel() )
1237 // no need to look further
1241 // maybe our parent has a cancel button?
1242 winForCancel
= winForCancel
->GetParent();
1247 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1248 event
.SetEventObject(btnCancel
);
1249 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1255 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1263 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1269 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1272 event
.m_uniChar
= g_utf8_get_char( str
);
1274 // Backward compatible for ISO-8859
1275 if (event
.m_uniChar
< 256)
1276 event
.m_keyCode
= event
.m_uniChar
;
1278 gunichar uniChar
= g_utf8_get_char( str
);
1279 // We cannot handle Unicode in non-Unicode mode
1280 if (uniChar
> 255) return;
1282 event
.m_keyCode
= uniChar
;
1286 // TODO: We still need to set all the extra attributes of the
1287 // event, modifiers and such...
1290 // Implement OnCharHook by checking ancestor top level windows
1291 wxWindow
*parent
= window
;
1292 while (parent
&& !parent
->IsTopLevel())
1293 parent
= parent
->GetParent();
1296 event
.SetEventType( wxEVT_CHAR_HOOK
);
1297 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1302 event
.SetEventType(wxEVT_CHAR
);
1303 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1309 //-----------------------------------------------------------------------------
1310 // "key_release_event" from any window
1311 //-----------------------------------------------------------------------------
1313 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1314 GdkEventKey
*gdk_event
,
1320 wxapp_install_idle_handler();
1325 if (g_blockEventsOnDrag
)
1328 wxKeyEvent
event( wxEVT_KEY_UP
);
1329 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1331 // unknown key pressed, ignore (the event would be useless anyhow
1335 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1338 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1342 // ============================================================================
1344 // ============================================================================
1346 // ----------------------------------------------------------------------------
1347 // mouse event processing helpers
1348 // ----------------------------------------------------------------------------
1350 // init wxMouseEvent with the info from GdkEventXXX struct
1351 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1352 wxMouseEvent
& event
,
1355 event
.SetTimestamp( gdk_event
->time
);
1356 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1357 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1358 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1359 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1360 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1361 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1362 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1363 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1365 event
.m_linesPerAction
= 3;
1366 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1367 event
.m_wheelRotation
= 120;
1368 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1369 event
.m_wheelRotation
= -120;
1372 wxPoint pt
= win
->GetClientAreaOrigin();
1373 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1374 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1376 event
.SetEventObject( win
);
1377 event
.SetId( win
->GetId() );
1378 event
.SetTimestamp( gdk_event
->time
);
1381 static void AdjustEventButtonState(wxMouseEvent
& event
)
1383 // GDK reports the old state of the button for a button press event, but
1384 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1385 // for a LEFT_DOWN event, not FALSE, so we will invert
1386 // left/right/middleDown for the corresponding click events
1388 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1389 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1390 (event
.GetEventType() == wxEVT_LEFT_UP
))
1392 event
.m_leftDown
= !event
.m_leftDown
;
1396 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1397 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1398 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1400 event
.m_middleDown
= !event
.m_middleDown
;
1404 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1405 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1406 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1408 event
.m_rightDown
= !event
.m_rightDown
;
1413 // find the window to send the mouse event too
1415 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1420 if (win
->m_wxwindow
)
1422 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1423 xx
+= pizza
->xoffset
;
1424 yy
+= pizza
->yoffset
;
1427 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1430 wxWindowGTK
*child
= node
->GetData();
1432 node
= node
->GetNext();
1433 if (!child
->IsShown())
1436 if (child
->IsTransparentForMouse())
1438 // wxStaticBox is transparent in the box itself
1439 int xx1
= child
->m_x
;
1440 int yy1
= child
->m_y
;
1441 int xx2
= child
->m_x
+ child
->m_width
;
1442 int yy2
= child
->m_y
+ child
->m_height
;
1445 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1447 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1449 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1451 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1462 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1463 (child
->m_x
<= xx
) &&
1464 (child
->m_y
<= yy
) &&
1465 (child
->m_x
+child
->m_width
>= xx
) &&
1466 (child
->m_y
+child
->m_height
>= yy
))
1479 //-----------------------------------------------------------------------------
1480 // "button_press_event"
1481 //-----------------------------------------------------------------------------
1483 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1484 GdkEventButton
*gdk_event
,
1490 wxapp_install_idle_handler();
1493 wxPrintf( wxT("1) OnButtonPress from ") );
1494 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1495 wxPrintf( win->GetClassInfo()->GetClassName() );
1496 wxPrintf( wxT(".\n") );
1498 if (!win
->m_hasVMT
) return FALSE
;
1499 if (g_blockEventsOnDrag
) return TRUE
;
1500 if (g_blockEventsOnScroll
) return TRUE
;
1502 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1504 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1506 gtk_widget_grab_focus( win
->m_wxwindow
);
1508 wxPrintf( wxT("GrabFocus from ") );
1509 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1510 wxPrintf( win->GetClassInfo()->GetClassName() );
1511 wxPrintf( wxT(".\n") );
1515 // GDK sends surplus button down event
1516 // before a double click event. We
1517 // need to filter these out.
1518 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1520 GdkEvent
*peek_event
= gdk_event_peek();
1523 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1524 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1526 gdk_event_free( peek_event
);
1531 gdk_event_free( peek_event
);
1536 wxEventType event_type
= wxEVT_NULL
;
1538 // GdkDisplay is a GTK+ 2.1.0 thing
1539 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 1, 0)
1540 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1541 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1543 // Reset GDK internal timestamp variables in order to disable GDK
1544 // triple click events. GDK will then next time believe no button has
1545 // been clicked just before, and send a normal button click event.
1546 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1547 display
->button_click_time
[1] = 0;
1548 display
->button_click_time
[0] = 0;
1552 if (gdk_event
->button
== 1)
1554 // note that GDK generates triple click events which are not supported
1555 // by wxWidgets but still have to be passed to the app as otherwise
1556 // clicks would simply go missing
1557 switch (gdk_event
->type
)
1559 // we shouldn't get triple clicks at all for GTK2 because we
1560 // suppress them artificially using the code above but we still
1561 // should map them to something for GTK1 and not just ignore them
1562 // as this would lose clicks
1563 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1564 case GDK_BUTTON_PRESS
:
1565 event_type
= wxEVT_LEFT_DOWN
;
1568 case GDK_2BUTTON_PRESS
:
1569 event_type
= wxEVT_LEFT_DCLICK
;
1573 // just to silence gcc warnings
1577 else if (gdk_event
->button
== 2)
1579 switch (gdk_event
->type
)
1581 case GDK_3BUTTON_PRESS
:
1582 case GDK_BUTTON_PRESS
:
1583 event_type
= wxEVT_MIDDLE_DOWN
;
1586 case GDK_2BUTTON_PRESS
:
1587 event_type
= wxEVT_MIDDLE_DCLICK
;
1594 else if (gdk_event
->button
== 3)
1596 switch (gdk_event
->type
)
1598 case GDK_3BUTTON_PRESS
:
1599 case GDK_BUTTON_PRESS
:
1600 event_type
= wxEVT_RIGHT_DOWN
;
1603 case GDK_2BUTTON_PRESS
:
1604 event_type
= wxEVT_RIGHT_DCLICK
;
1611 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1613 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1615 event_type
= wxEVT_MOUSEWHEEL
;
1619 if ( event_type
== wxEVT_NULL
)
1621 // unknown mouse button or click type
1625 wxMouseEvent
event( event_type
);
1626 InitMouseEvent( win
, event
, gdk_event
);
1628 AdjustEventButtonState(event
);
1630 // wxListBox actually get mouse events from the item, so we need to give it
1631 // a chance to correct this
1632 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1634 // find the correct window to send the event too: it may be a different one
1635 // from the one which got it at GTK+ level because some control don't have
1636 // their own X window and thus cannot get any events.
1637 if ( !g_captureWindow
)
1638 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1640 gs_timeLastClick
= gdk_event
->time
;
1643 wxPrintf( wxT("2) OnButtonPress from ") );
1644 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1645 wxPrintf( win->GetClassInfo()->GetClassName() );
1646 wxPrintf( wxT(".\n") );
1650 if (event_type
== wxEVT_LEFT_DCLICK
)
1652 // GTK 1.2 crashes when intercepting double
1653 // click events from both wxSpinButton and
1655 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1657 // Just disable this event for now.
1663 if (win
->GetEventHandler()->ProcessEvent( event
))
1665 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1672 //-----------------------------------------------------------------------------
1673 // "button_release_event"
1674 //-----------------------------------------------------------------------------
1676 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1677 GdkEventButton
*gdk_event
,
1683 wxapp_install_idle_handler();
1685 if (!win
->m_hasVMT
) return FALSE
;
1686 if (g_blockEventsOnDrag
) return FALSE
;
1687 if (g_blockEventsOnScroll
) return FALSE
;
1689 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1691 wxEventType event_type
= wxEVT_NULL
;
1693 switch (gdk_event
->button
)
1696 event_type
= wxEVT_LEFT_UP
;
1700 event_type
= wxEVT_MIDDLE_UP
;
1704 event_type
= wxEVT_RIGHT_UP
;
1708 // unknwon button, don't process
1712 wxMouseEvent
event( event_type
);
1713 InitMouseEvent( win
, event
, gdk_event
);
1715 AdjustEventButtonState(event
);
1717 // same wxListBox hack as above
1718 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1720 if ( event_type
== wxEVT_RIGHT_UP
)
1722 // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
1725 // (a) it's a command event and so is propagated to the parent
1726 // (b) under MSW it can be generated from kbd too
1727 // (c) it uses screen coords (because of (a))
1728 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1730 win
->ClientToScreen(event
.GetPosition()));
1731 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1734 if ( !g_captureWindow
)
1735 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1737 if (win
->GetEventHandler()->ProcessEvent( event
))
1739 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1746 //-----------------------------------------------------------------------------
1747 // "motion_notify_event"
1748 //-----------------------------------------------------------------------------
1750 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1751 GdkEventMotion
*gdk_event
,
1757 wxapp_install_idle_handler();
1759 if (!win
->m_hasVMT
) return FALSE
;
1760 if (g_blockEventsOnDrag
) return FALSE
;
1761 if (g_blockEventsOnScroll
) return FALSE
;
1763 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1765 if (gdk_event
->is_hint
)
1769 GdkModifierType state
;
1770 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1776 printf( "OnMotion from " );
1777 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1778 printf( win->GetClassInfo()->GetClassName() );
1782 wxMouseEvent
event( wxEVT_MOTION
);
1783 InitMouseEvent(win
, event
, gdk_event
);
1785 if ( g_captureWindow
)
1787 // synthetize a mouse enter or leave event if needed
1788 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1789 // This seems to be necessary and actually been added to
1790 // GDK itself in version 2.0.X
1793 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1794 if ( hasMouse
!= g_captureWindowHasMouse
)
1796 // the mouse changed window
1797 g_captureWindowHasMouse
= hasMouse
;
1799 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1800 : wxEVT_LEAVE_WINDOW
);
1801 InitMouseEvent(win
, event
, gdk_event
);
1802 event
.SetEventObject(win
);
1803 win
->GetEventHandler()->ProcessEvent(event
);
1808 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1811 if (win
->GetEventHandler()->ProcessEvent( event
))
1813 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1821 //-----------------------------------------------------------------------------
1822 // "mouse_wheel_event"
1823 //-----------------------------------------------------------------------------
1825 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1826 GdkEventScroll
* gdk_event
,
1832 wxapp_install_idle_handler();
1834 wxEventType event_type
= wxEVT_NULL
;
1835 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1836 event_type
= wxEVT_MOUSEWHEEL
;
1837 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1838 event_type
= wxEVT_MOUSEWHEEL
;
1842 wxMouseEvent
event( event_type
);
1843 // Can't use InitMouse macro because scroll events don't have button
1844 event
.SetTimestamp( gdk_event
->time
);
1845 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1846 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1847 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1848 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1849 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1850 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1851 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1852 event
.m_linesPerAction
= 3;
1853 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1854 event
.m_wheelRotation
= 120;
1856 event
.m_wheelRotation
= -120;
1858 wxPoint pt
= win
->GetClientAreaOrigin();
1859 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1860 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1862 event
.SetEventObject( win
);
1863 event
.SetId( win
->GetId() );
1864 event
.SetTimestamp( gdk_event
->time
);
1866 if (win
->GetEventHandler()->ProcessEvent( event
))
1868 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1876 //-----------------------------------------------------------------------------
1878 //-----------------------------------------------------------------------------
1880 // send the wxChildFocusEvent and wxFocusEvent, common code of
1881 // gtk_window_focus_in_callback() and SetFocus()
1882 static bool DoSendFocusEvents(wxWindow
*win
)
1884 // Notify the parent keeping track of focus for the kbd navigation
1885 // purposes that we got it.
1886 wxChildFocusEvent
eventChildFocus(win
);
1887 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1889 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1890 eventFocus
.SetEventObject(win
);
1892 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1895 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1896 GdkEvent
*WXUNUSED(event
),
1902 wxapp_install_idle_handler();
1904 if (!win
->m_hasVMT
) return FALSE
;
1905 if (g_blockEventsOnDrag
) return FALSE
;
1907 switch ( g_sendActivateEvent
)
1910 // we've got focus from outside, synthetize wxActivateEvent
1911 g_sendActivateEvent
= 1;
1915 // another our window just lost focus, it was already ours before
1916 // - don't send any wxActivateEvent
1917 g_sendActivateEvent
= -1;
1922 g_focusWindow
= win
;
1924 wxLogTrace(TRACE_FOCUS
,
1925 _T("%s: focus in"), win
->GetName().c_str());
1929 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1933 // caret needs to be informed about focus change
1934 wxCaret
*caret
= win
->GetCaret();
1937 caret
->OnSetFocus();
1939 #endif // wxUSE_CARET
1941 g_activeFrameLostFocus
= FALSE
;
1943 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1944 if ( active
!= g_activeFrame
)
1946 if ( g_activeFrame
)
1948 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1949 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1950 event
.SetEventObject(g_activeFrame
);
1951 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1954 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1955 g_activeFrame
= active
;
1956 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1957 event
.SetEventObject(g_activeFrame
);
1958 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1960 // Don't send focus events in addition to activate
1961 // if (win == g_activeFrame)
1965 // does the window itself think that it has the focus?
1966 if ( !win
->m_hasFocus
)
1968 // not yet, notify it
1969 win
->m_hasFocus
= TRUE
;
1971 if ( DoSendFocusEvents(win
) )
1973 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1981 //-----------------------------------------------------------------------------
1982 // "focus_out_event"
1983 //-----------------------------------------------------------------------------
1985 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1990 wxapp_install_idle_handler();
1992 if (!win
->m_hasVMT
) return FALSE
;
1993 if (g_blockEventsOnDrag
) return FALSE
;
1995 wxLogTrace( TRACE_FOCUS
,
1996 _T("%s: focus out"), win
->GetName().c_str() );
1998 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
2000 // VZ: commenting this out because it does happen (although not easy
2001 // to reproduce, I only see it when using wxMiniFrame and not
2002 // always) and makes using Mahogany quite annoying
2004 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
2005 wxT("unfocusing window that hasn't gained focus properly") );
2008 g_activeFrameLostFocus
= TRUE
;
2011 // if the focus goes out of our app alltogether, OnIdle() will send
2012 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
2013 // g_sendActivateEvent to -1
2014 g_sendActivateEvent
= 0;
2016 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2020 g_focusWindow
= (wxWindowGTK
*)NULL
;
2028 // caret needs to be informed about focus change
2029 wxCaret
*caret
= win
->GetCaret();
2032 caret
->OnKillFocus();
2034 #endif // wxUSE_CARET
2036 // don't send the window a kill focus event if it thinks that it doesn't
2037 // have focus already
2038 if ( win
->m_hasFocus
)
2040 win
->m_hasFocus
= FALSE
;
2042 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2043 event
.SetEventObject( win
);
2045 if (win
->GetEventHandler()->ProcessEvent( event
))
2047 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
2055 //-----------------------------------------------------------------------------
2056 // "enter_notify_event"
2057 //-----------------------------------------------------------------------------
2060 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2061 GdkEventCrossing
*gdk_event
,
2067 wxapp_install_idle_handler();
2069 if (!win
->m_hasVMT
) return FALSE
;
2070 if (g_blockEventsOnDrag
) return FALSE
;
2072 // Event was emitted after a grab
2073 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2075 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2079 GdkModifierType state
= (GdkModifierType
)0;
2081 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2083 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2084 InitMouseEvent(win
, event
, gdk_event
);
2085 wxPoint pt
= win
->GetClientAreaOrigin();
2086 event
.m_x
= x
+ pt
.x
;
2087 event
.m_y
= y
+ pt
.y
;
2089 if (win
->GetEventHandler()->ProcessEvent( event
))
2091 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2098 //-----------------------------------------------------------------------------
2099 // "leave_notify_event"
2100 //-----------------------------------------------------------------------------
2102 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2107 wxapp_install_idle_handler();
2109 if (!win
->m_hasVMT
) return FALSE
;
2110 if (g_blockEventsOnDrag
) return FALSE
;
2112 // Event was emitted after an ungrab
2113 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2115 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2117 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2118 event
.SetTimestamp( gdk_event
->time
);
2119 event
.SetEventObject( win
);
2123 GdkModifierType state
= (GdkModifierType
)0;
2125 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2127 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2128 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2129 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2130 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2131 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2132 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2133 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2135 wxPoint pt
= win
->GetClientAreaOrigin();
2136 event
.m_x
= x
+ pt
.x
;
2137 event
.m_y
= y
+ pt
.y
;
2139 if (win
->GetEventHandler()->ProcessEvent( event
))
2141 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2148 //-----------------------------------------------------------------------------
2149 // "value_changed" from m_vAdjust
2150 //-----------------------------------------------------------------------------
2152 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2159 wxapp_install_idle_handler();
2161 if (g_blockEventsOnDrag
) return;
2163 if (!win
->m_hasVMT
) return;
2165 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2166 if (fabs(diff
) < 0.2) return;
2168 win
->m_oldVerticalPos
= adjust
->value
;
2171 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2173 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2175 int value
= (int)(adjust
->value
+0.5);
2177 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2178 event
.SetEventObject( win
);
2179 win
->GetEventHandler()->ProcessEvent( event
);
2182 //-----------------------------------------------------------------------------
2183 // "value_changed" from m_hAdjust
2184 //-----------------------------------------------------------------------------
2186 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2193 wxapp_install_idle_handler();
2195 if (g_blockEventsOnDrag
) return;
2196 if (!win
->m_hasVMT
) return;
2198 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2199 if (fabs(diff
) < 0.2) return;
2202 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2204 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2206 win
->m_oldHorizontalPos
= adjust
->value
;
2208 int value
= (int)(adjust
->value
+0.5);
2210 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2211 event
.SetEventObject( win
);
2212 win
->GetEventHandler()->ProcessEvent( event
);
2215 //-----------------------------------------------------------------------------
2216 // "button_press_event" from scrollbar
2217 //-----------------------------------------------------------------------------
2219 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2220 GdkEventButton
*gdk_event
,
2226 wxapp_install_idle_handler();
2229 g_blockEventsOnScroll
= TRUE
;
2231 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2233 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2239 //-----------------------------------------------------------------------------
2240 // "button_release_event" from scrollbar
2241 //-----------------------------------------------------------------------------
2243 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2244 GdkEventButton
*WXUNUSED(gdk_event
),
2249 // don't test here as we can release the mouse while being over
2250 // a different window than the slider
2252 // if (gdk_event->window != widget->slider) return FALSE;
2254 g_blockEventsOnScroll
= FALSE
;
2256 if (win
->m_isScrolling
)
2258 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2262 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2263 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2265 value
= (int)(win
->m_hAdjust
->value
+0.5);
2268 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2270 value
= (int)(win
->m_vAdjust
->value
+0.5);
2274 wxScrollWinEvent
event( command
, value
, dir
);
2275 event
.SetEventObject( win
);
2276 win
->GetEventHandler()->ProcessEvent( event
);
2279 win
->m_isScrolling
= FALSE
;
2284 // ----------------------------------------------------------------------------
2285 // this wxWindowBase function is implemented here (in platform-specific file)
2286 // because it is static and so couldn't be made virtual
2287 // ----------------------------------------------------------------------------
2289 wxWindow
*wxWindowBase::FindFocus()
2291 // the cast is necessary when we compile in wxUniversal mode
2292 return (wxWindow
*)g_focusWindow
;
2296 //-----------------------------------------------------------------------------
2297 // "realize" from m_widget
2298 //-----------------------------------------------------------------------------
2300 /* We cannot set colours and fonts before the widget has
2301 been realized, so we do this directly after realization. */
2304 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2309 wxapp_install_idle_handler();
2311 if (win
->m_delayedBackgroundColour
&& !win
->GetThemeEnabled())
2312 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2314 if (win
->m_delayedForegroundColour
&& !win
->GetThemeEnabled())
2315 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2318 if (win
->m_imContext
)
2320 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2321 gtk_im_context_set_client_window( (GtkIMContext
*) win
->m_imContext
, pizza
->bin_window
);
2325 wxWindowCreateEvent
event( win
);
2326 event
.SetEventObject( win
);
2327 win
->GetEventHandler()->ProcessEvent( event
);
2332 //-----------------------------------------------------------------------------
2334 //-----------------------------------------------------------------------------
2337 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2338 GtkAllocation
*WXUNUSED(alloc
),
2342 wxapp_install_idle_handler();
2344 if (!win
->m_hasScrolling
) return;
2346 int client_width
= 0;
2347 int client_height
= 0;
2348 win
->GetClientSize( &client_width
, &client_height
);
2349 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2352 win
->m_oldClientWidth
= client_width
;
2353 win
->m_oldClientHeight
= client_height
;
2355 if (!win
->m_nativeSizeEvent
)
2357 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2358 event
.SetEventObject( win
);
2359 win
->GetEventHandler()->ProcessEvent( event
);
2365 #define WXUNUSED_UNLESS_XIM(param) param
2367 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2370 /* Resize XIM window */
2373 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2374 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2375 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2378 wxapp_install_idle_handler();
2384 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2388 gdk_window_get_size (widget
->window
, &width
, &height
);
2389 win
->m_icattr
->preedit_area
.width
= width
;
2390 win
->m_icattr
->preedit_area
.height
= height
;
2391 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2396 //-----------------------------------------------------------------------------
2397 // "realize" from m_wxwindow
2398 //-----------------------------------------------------------------------------
2400 /* Initialize XIM support */
2403 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2404 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2407 wxapp_install_idle_handler();
2410 if (win
->m_ic
) return FALSE
;
2411 if (!widget
) return FALSE
;
2412 if (!gdk_im_ready()) return FALSE
;
2414 win
->m_icattr
= gdk_ic_attr_new();
2415 if (!win
->m_icattr
) return FALSE
;
2419 GdkColormap
*colormap
;
2420 GdkICAttr
*attr
= win
->m_icattr
;
2421 unsigned attrmask
= GDK_IC_ALL_REQ
;
2423 GdkIMStyle supported_style
= (GdkIMStyle
)
2424 (GDK_IM_PREEDIT_NONE
|
2425 GDK_IM_PREEDIT_NOTHING
|
2426 GDK_IM_PREEDIT_POSITION
|
2427 GDK_IM_STATUS_NONE
|
2428 GDK_IM_STATUS_NOTHING
);
2430 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2431 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2433 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2434 attr
->client_window
= widget
->window
;
2436 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2437 gtk_widget_get_default_colormap ())
2439 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2440 attr
->preedit_colormap
= colormap
;
2443 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2444 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2445 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2446 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2448 switch (style
& GDK_IM_PREEDIT_MASK
)
2450 case GDK_IM_PREEDIT_POSITION
:
2451 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2453 g_warning ("over-the-spot style requires fontset");
2457 gdk_window_get_size (widget
->window
, &width
, &height
);
2459 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2460 attr
->spot_location
.x
= 0;
2461 attr
->spot_location
.y
= height
;
2462 attr
->preedit_area
.x
= 0;
2463 attr
->preedit_area
.y
= 0;
2464 attr
->preedit_area
.width
= width
;
2465 attr
->preedit_area
.height
= height
;
2466 attr
->preedit_fontset
= widget
->style
->font
;
2471 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2473 if (win
->m_ic
== NULL
)
2474 g_warning ("Can't create input context.");
2477 mask
= gdk_window_get_events (widget
->window
);
2478 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2479 gdk_window_set_events (widget
->window
, mask
);
2481 if (GTK_WIDGET_HAS_FOCUS(widget
))
2482 gdk_im_begin (win
->m_ic
, widget
->window
);
2489 //-----------------------------------------------------------------------------
2490 // InsertChild for wxWindowGTK.
2491 //-----------------------------------------------------------------------------
2493 /* Callback for wxWindowGTK. This very strange beast has to be used because
2494 * C++ has no virtual methods in a constructor. We have to emulate a
2495 * virtual function here as wxNotebook requires a different way to insert
2496 * a child in it. I had opted for creating a wxNotebookPage window class
2497 * which would have made this superfluous (such in the MDI window system),
2498 * but no-one was listening to me... */
2500 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2502 /* the window might have been scrolled already, do we
2503 have to adapt the position */
2504 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2505 child
->m_x
+= pizza
->xoffset
;
2506 child
->m_y
+= pizza
->yoffset
;
2508 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2509 GTK_WIDGET(child
->m_widget
),
2516 //-----------------------------------------------------------------------------
2518 //-----------------------------------------------------------------------------
2520 wxWindow
*wxGetActiveWindow()
2522 return wxWindow::FindFocus();
2525 //-----------------------------------------------------------------------------
2527 //-----------------------------------------------------------------------------
2529 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2531 #ifdef __WXUNIVERSAL__
2532 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2534 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2535 #endif // __WXUNIVERSAL__/__WXGTK__
2537 void wxWindowGTK::Init()
2540 m_widget
= (GtkWidget
*) NULL
;
2541 m_wxwindow
= (GtkWidget
*) NULL
;
2542 m_focusWidget
= (GtkWidget
*) NULL
;
2552 m_needParent
= TRUE
;
2553 m_isBeingDeleted
= FALSE
;
2556 m_nativeSizeEvent
= FALSE
;
2558 m_hasScrolling
= FALSE
;
2559 m_isScrolling
= FALSE
;
2561 m_hAdjust
= (GtkAdjustment
*) NULL
;
2562 m_vAdjust
= (GtkAdjustment
*) NULL
;
2563 m_oldHorizontalPos
=
2564 m_oldVerticalPos
= 0.0;
2566 m_oldClientHeight
= 0;
2569 m_widgetStyle
= (GtkStyle
*) NULL
;
2571 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2573 m_acceptsFocus
= FALSE
;
2576 m_clipPaintRegion
= FALSE
;
2578 m_cursor
= *wxSTANDARD_CURSOR
;
2580 m_delayedForegroundColour
= FALSE
;
2581 m_delayedBackgroundColour
= FALSE
;
2585 m_x11Context
= NULL
;
2588 m_ic
= (GdkIC
*) NULL
;
2589 m_icattr
= (GdkICAttr
*) NULL
;
2594 wxWindowGTK::wxWindowGTK()
2599 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2604 const wxString
&name
)
2608 Create( parent
, id
, pos
, size
, style
, name
);
2611 bool wxWindowGTK::Create( wxWindow
*parent
,
2616 const wxString
&name
)
2618 if (!PreCreation( parent
, pos
, size
) ||
2619 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2621 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2625 m_insertCallback
= wxInsertChildInWindow
;
2627 // always needed for background clearing
2628 m_delayedBackgroundColour
= TRUE
;
2630 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2631 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2633 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2635 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2636 scroll_class
->scrollbar_spacing
= 0;
2638 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2640 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2641 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2643 m_wxwindow
= gtk_pizza_new();
2645 #ifndef __WXUNIVERSAL__
2646 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2648 if (HasFlag(wxRAISED_BORDER
))
2650 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2652 else if (HasFlag(wxSUNKEN_BORDER
))
2654 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2656 else if (HasFlag(wxSIMPLE_BORDER
))
2658 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2662 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2664 #endif // __WXUNIVERSAL__
2666 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2668 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2669 m_acceptsFocus
= TRUE
;
2671 // I _really_ don't want scrollbars in the beginning
2672 m_vAdjust
->lower
= 0.0;
2673 m_vAdjust
->upper
= 1.0;
2674 m_vAdjust
->value
= 0.0;
2675 m_vAdjust
->step_increment
= 1.0;
2676 m_vAdjust
->page_increment
= 1.0;
2677 m_vAdjust
->page_size
= 5.0;
2678 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2679 m_hAdjust
->lower
= 0.0;
2680 m_hAdjust
->upper
= 1.0;
2681 m_hAdjust
->value
= 0.0;
2682 m_hAdjust
->step_increment
= 1.0;
2683 m_hAdjust
->page_increment
= 1.0;
2684 m_hAdjust
->page_size
= 5.0;
2685 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2687 // these handlers block mouse events to any window during scrolling such as
2688 // motion events and prevent GTK and wxWidgets from fighting over where the
2691 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2692 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2694 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2695 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2697 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2698 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2700 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2701 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2703 // these handlers get notified when screen updates are required either when
2704 // scrolling or when the window size (and therefore scrollbar configuration)
2707 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2708 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2709 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2710 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2713 // Create input method handler
2714 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2716 // Cannot handle drawing preedited text yet
2717 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2719 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2720 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2723 gtk_widget_show( m_wxwindow
);
2726 m_parent
->DoAddChild( this );
2728 m_focusWidget
= m_wxwindow
;
2735 wxWindowGTK::~wxWindowGTK()
2739 if (g_focusWindow
== this)
2740 g_focusWindow
= NULL
;
2742 if (g_activeFrame
== this)
2743 g_activeFrame
= NULL
;
2745 if ( g_delayedFocus
== this )
2746 g_delayedFocus
= NULL
;
2748 m_isBeingDeleted
= TRUE
;
2758 gdk_ic_destroy (m_ic
);
2760 gdk_ic_attr_destroy (m_icattr
);
2765 #if DISABLE_STYLE_IF_BROKEN_THEME
2766 // don't delete if it's a pixmap theme style
2767 if (!m_widgetStyle
->engine_data
)
2768 gtk_style_unref( m_widgetStyle
);
2770 m_widgetStyle
= (GtkStyle
*) NULL
;
2775 gtk_widget_destroy( m_wxwindow
);
2776 m_wxwindow
= (GtkWidget
*) NULL
;
2781 gtk_widget_destroy( m_widget
);
2782 m_widget
= (GtkWidget
*) NULL
;
2786 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2788 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2790 // Use either the given size, or the default if -1 is given.
2791 // See wxWindowBase for these functions.
2792 m_width
= WidthDefault(size
.x
) ;
2793 m_height
= HeightDefault(size
.y
);
2801 void wxWindowGTK::PostCreation()
2803 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2809 // these get reported to wxWidgets -> wxPaintEvent
2811 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2813 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2814 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2817 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2818 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2820 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2822 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2823 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2826 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2830 // Create input method handler
2831 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2833 // Cannot handle drawing preedited text yet
2834 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2836 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2837 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2841 // these are called when the "sunken" or "raised" borders are drawn
2842 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2843 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2846 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2847 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2853 if (m_focusWidget
== NULL
)
2854 m_focusWidget
= m_widget
;
2856 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2857 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2859 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2860 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2862 // connect to the various key and mouse handlers
2864 GtkWidget
*connect_widget
= GetConnectWidget();
2866 ConnectWidget( connect_widget
);
2868 /* We cannot set colours, fonts and cursors before the widget has
2869 been realized, so we do this directly after realization */
2870 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2871 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2875 // Catch native resize events
2876 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2877 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2879 // Initialize XIM support
2880 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2881 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2883 // And resize XIM window
2884 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2885 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2888 if ( !GTK_IS_COMBO(m_widget
))
2890 // This is needed if we want to add our windows into native
2891 // GTK control, such as the toolbar. With this callback, the
2892 // toolbar gets to know the correct size (the one set by the
2893 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2894 // when moving to GTK 2.0.
2895 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2896 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2902 // unless the window was created initially hidden (i.e. Hide() had been
2903 // called before Create()), we should show it at GTK+ level as well
2905 gtk_widget_show( m_widget
);
2908 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2910 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2911 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2913 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2914 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2916 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2917 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2919 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2920 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2922 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2923 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2926 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2927 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2930 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2931 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2933 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2934 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2937 bool wxWindowGTK::Destroy()
2939 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2943 return wxWindowBase::Destroy();
2946 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2948 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2951 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2953 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2954 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2957 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2960 if (m_resizing
) return; /* I don't like recursions */
2963 int currentX
, currentY
;
2964 GetPosition(¤tX
, ¤tY
);
2965 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2967 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2969 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2971 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2973 /* don't set the size for children of wxNotebook, just take the values. */
2981 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2982 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2984 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2985 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2989 m_x
= x
+ pizza
->xoffset
;
2990 m_y
= y
+ pizza
->yoffset
;
2993 // calculate the best size if we should auto size the window
2994 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2995 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2997 const wxSize sizeBest
= GetBestSize();
2998 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
3000 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
3001 height
= sizeBest
.y
;
3009 int minWidth
= GetMinWidth(),
3010 minHeight
= GetMinHeight(),
3011 maxWidth
= GetMaxWidth(),
3012 maxHeight
= GetMaxHeight();
3014 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3015 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3016 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3017 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3020 int bottom_border
= 0;
3023 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3025 /* the default button has a border around it */
3031 DoMoveWindow( m_x
-border
,
3034 m_height
+border
+bottom_border
);
3039 /* Sometimes the client area changes size without the
3040 whole windows's size changing, but if the whole
3041 windows's size doesn't change, no wxSizeEvent will
3042 normally be sent. Here we add an extra test if
3043 the client test has been changed and this will
3045 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3049 wxPrintf( "OnSize sent from " );
3050 if (GetClassInfo() && GetClassInfo()->GetClassName())
3051 wxPrintf( GetClassInfo()->GetClassName() );
3052 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3055 if (!m_nativeSizeEvent
)
3057 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3058 event
.SetEventObject( this );
3059 GetEventHandler()->ProcessEvent( event
);
3065 void wxWindowGTK::OnInternalIdle()
3067 // Update invalidated regions.
3070 // Synthetize activate events.
3071 if ( g_sendActivateEvent
!= -1 )
3073 bool activate
= g_sendActivateEvent
!= 0;
3076 g_sendActivateEvent
= -1;
3078 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
3081 if ( g_activeFrameLostFocus
)
3083 if ( g_activeFrame
)
3085 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3086 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3087 event
.SetEventObject(g_activeFrame
);
3088 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3089 g_activeFrame
= NULL
;
3091 g_activeFrameLostFocus
= FALSE
;
3094 wxCursor cursor
= m_cursor
;
3095 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3099 /* I now set the cursor anew in every OnInternalIdle call
3100 as setting the cursor in a parent window also effects the
3101 windows above so that checking for the current cursor is
3106 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3108 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3110 if (!g_globalCursor
.Ok())
3111 cursor
= *wxSTANDARD_CURSOR
;
3113 window
= m_widget
->window
;
3114 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3115 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3121 GdkWindow
*window
= m_widget
->window
;
3122 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3123 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3128 if (wxUpdateUIEvent::CanUpdate(this))
3129 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3132 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3134 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3136 if (width
) (*width
) = m_width
;
3137 if (height
) (*height
) = m_height
;
3140 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3142 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3146 SetSize( width
, height
);
3153 #ifndef __WXUNIVERSAL__
3154 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3156 /* when using GTK 1.2 we set the shadow border size to 2 */
3160 if (HasFlag(wxSIMPLE_BORDER
))
3162 /* when using GTK 1.2 we set the simple border size to 1 */
3166 #endif // __WXUNIVERSAL__
3170 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3172 GtkRequisition vscroll_req
;
3173 vscroll_req
.width
= 2;
3174 vscroll_req
.height
= 2;
3175 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3176 (scroll_window
->vscrollbar
, &vscroll_req
);
3178 GtkRequisition hscroll_req
;
3179 hscroll_req
.width
= 2;
3180 hscroll_req
.height
= 2;
3181 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3182 (scroll_window
->hscrollbar
, &hscroll_req
);
3184 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3186 if (scroll_window
->vscrollbar_visible
)
3188 dw
+= vscroll_req
.width
;
3189 dw
+= scroll_class
->scrollbar_spacing
;
3192 if (scroll_window
->hscrollbar_visible
)
3194 dh
+= hscroll_req
.height
;
3195 dh
+= scroll_class
->scrollbar_spacing
;
3199 SetSize( width
+dw
, height
+dh
);
3203 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3205 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3209 if (width
) (*width
) = m_width
;
3210 if (height
) (*height
) = m_height
;
3217 #ifndef __WXUNIVERSAL__
3218 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3220 /* when using GTK 1.2 we set the shadow border size to 2 */
3224 if (HasFlag(wxSIMPLE_BORDER
))
3226 /* when using GTK 1.2 we set the simple border size to 1 */
3230 #endif // __WXUNIVERSAL__
3234 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3236 GtkRequisition vscroll_req
;
3237 vscroll_req
.width
= 2;
3238 vscroll_req
.height
= 2;
3239 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3240 (scroll_window
->vscrollbar
, &vscroll_req
);
3242 GtkRequisition hscroll_req
;
3243 hscroll_req
.width
= 2;
3244 hscroll_req
.height
= 2;
3245 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3246 (scroll_window
->hscrollbar
, &hscroll_req
);
3248 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3250 if (scroll_window
->vscrollbar_visible
)
3252 dw
+= vscroll_req
.width
;
3253 dw
+= scroll_class
->scrollbar_spacing
;
3256 if (scroll_window
->hscrollbar_visible
)
3258 dh
+= hscroll_req
.height
;
3259 dh
+= scroll_class
->scrollbar_spacing
;
3263 if (width
) (*width
) = m_width
- dw
;
3264 if (height
) (*height
) = m_height
- dh
;
3268 printf( "GetClientSize, name %s ", GetName().c_str() );
3269 if (width) printf( " width = %d", (*width) );
3270 if (height) printf( " height = %d", (*height) );
3275 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3277 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3281 if (m_parent
&& m_parent
->m_wxwindow
)
3283 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3284 dx
= pizza
->xoffset
;
3285 dy
= pizza
->yoffset
;
3288 if (x
) (*x
) = m_x
- dx
;
3289 if (y
) (*y
) = m_y
- dy
;
3292 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3294 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3296 if (!m_widget
->window
) return;
3298 GdkWindow
*source
= (GdkWindow
*) NULL
;
3300 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3302 source
= m_widget
->window
;
3306 gdk_window_get_origin( source
, &org_x
, &org_y
);
3310 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3312 org_x
+= m_widget
->allocation
.x
;
3313 org_y
+= m_widget
->allocation
.y
;
3321 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3323 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3325 if (!m_widget
->window
) return;
3327 GdkWindow
*source
= (GdkWindow
*) NULL
;
3329 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3331 source
= m_widget
->window
;
3335 gdk_window_get_origin( source
, &org_x
, &org_y
);
3339 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3341 org_x
+= m_widget
->allocation
.x
;
3342 org_y
+= m_widget
->allocation
.y
;
3350 bool wxWindowGTK::Show( bool show
)
3352 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3354 if (!wxWindowBase::Show(show
))
3361 gtk_widget_show( m_widget
);
3363 gtk_widget_hide( m_widget
);
3365 wxShowEvent
eventShow(GetId(), show
);
3366 eventShow
.m_eventObject
= this;
3368 GetEventHandler()->ProcessEvent(eventShow
);
3373 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3375 win
->OnParentEnable(enable
);
3377 // Recurse, so that children have the opportunity to Do The Right Thing
3378 // and reset colours that have been messed up by a parent's (really ancestor's)
3380 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3382 node
= node
->GetNext() )
3384 wxWindow
*child
= node
->GetData();
3385 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3386 wxWindowNotifyEnable(child
, enable
);
3390 bool wxWindowGTK::Enable( bool enable
)
3392 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3394 if (!wxWindowBase::Enable(enable
))
3400 gtk_widget_set_sensitive( m_widget
, enable
);
3402 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3404 wxWindowNotifyEnable(this, enable
);
3409 int wxWindowGTK::GetCharHeight() const
3411 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3413 wxFont font
= GetFont();
3414 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3417 PangoContext
*context
= NULL
;
3419 context
= gtk_widget_get_pango_context( m_widget
);
3424 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3425 PangoLayout
*layout
= pango_layout_new(context
);
3426 pango_layout_set_font_description(layout
, desc
);
3427 pango_layout_set_text(layout
, "H", 1);
3428 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3430 PangoRectangle rect
;
3431 pango_layout_line_get_extents(line
, NULL
, &rect
);
3433 g_object_unref( G_OBJECT( layout
) );
3435 return (int) (rect
.height
/ PANGO_SCALE
);
3437 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3439 return gfont
->ascent
+ gfont
->descent
;
3443 int wxWindowGTK::GetCharWidth() const
3445 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3447 wxFont font
= GetFont();
3448 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3451 PangoContext
*context
= NULL
;
3453 context
= gtk_widget_get_pango_context( m_widget
);
3458 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3459 PangoLayout
*layout
= pango_layout_new(context
);
3460 pango_layout_set_font_description(layout
, desc
);
3461 pango_layout_set_text(layout
, "g", 1);
3462 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3464 PangoRectangle rect
;
3465 pango_layout_line_get_extents(line
, NULL
, &rect
);
3467 g_object_unref( G_OBJECT( layout
) );
3469 return (int) (rect
.width
/ PANGO_SCALE
);
3471 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3473 return gdk_string_width( gfont
, "g" );
3477 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3481 int *externalLeading
,
3482 const wxFont
*theFont
) const
3484 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3486 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3488 if (string
.IsEmpty())
3496 PangoContext
*context
= NULL
;
3498 context
= gtk_widget_get_pango_context( m_widget
);
3507 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3508 PangoLayout
*layout
= pango_layout_new(context
);
3509 pango_layout_set_font_description(layout
, desc
);
3512 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3513 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3515 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3516 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3517 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3520 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3522 PangoRectangle rect
;
3523 pango_layout_line_get_extents(line
, NULL
, &rect
);
3525 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3526 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3529 // Do something about metrics here
3532 if (externalLeading
) (*externalLeading
) = 0; // ??
3534 g_object_unref( G_OBJECT( layout
) );
3536 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3537 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3538 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3539 if (descent
) (*descent
) = font
->descent
;
3540 if (externalLeading
) (*externalLeading
) = 0; // ??
3544 void wxWindowGTK::SetFocus()
3546 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3550 // don't do anything if we already have focus
3556 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3558 gtk_widget_grab_focus (m_wxwindow
);
3563 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3565 if (!GTK_WIDGET_REALIZED(m_widget
))
3567 // we can't set the focus to the widget now so we remember that
3568 // it should be focused and will do it later, during the idle
3569 // time, as soon as we can
3570 wxLogTrace(TRACE_FOCUS
,
3571 _T("Delaying setting focus to %s(%s)"),
3572 GetClassInfo()->GetClassName(), GetLabel().c_str());
3574 g_delayedFocus
= this;
3578 wxLogTrace(TRACE_FOCUS
,
3579 _T("Setting focus to %s(%s)"),
3580 GetClassInfo()->GetClassName(), GetLabel().c_str());
3582 gtk_widget_grab_focus (m_widget
);
3585 else if (GTK_IS_CONTAINER(m_widget
))
3587 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3591 wxLogTrace(TRACE_FOCUS
,
3592 _T("Can't set focus to %s(%s)"),
3593 GetClassInfo()->GetClassName(), GetLabel().c_str());
3598 bool wxWindowGTK::AcceptsFocus() const
3600 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3603 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3605 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3607 wxWindowGTK
*oldParent
= m_parent
,
3608 *newParent
= (wxWindowGTK
*)newParentBase
;
3610 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3612 if ( !wxWindowBase::Reparent(newParent
) )
3615 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3617 /* prevent GTK from deleting the widget arbitrarily */
3618 gtk_widget_ref( m_widget
);
3622 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3625 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3629 /* insert GTK representation */
3630 (*(newParent
->m_insertCallback
))(newParent
, this);
3633 /* reverse: prevent GTK from deleting the widget arbitrarily */
3634 gtk_widget_unref( m_widget
);
3639 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3641 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3643 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3645 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3650 /* insert GTK representation */
3651 (*m_insertCallback
)(this, child
);
3654 void wxWindowGTK::Raise()
3656 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3658 if (!m_widget
->window
) return;
3660 gdk_window_raise( m_widget
->window
);
3663 void wxWindowGTK::Lower()
3665 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3667 if (!m_widget
->window
) return;
3669 gdk_window_lower( m_widget
->window
);
3672 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3674 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3676 if (cursor
== m_cursor
)
3680 wxapp_install_idle_handler();
3682 if (cursor
== wxNullCursor
)
3683 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3685 return wxWindowBase::SetCursor( cursor
);
3688 void wxWindowGTK::WarpPointer( int x
, int y
)
3690 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3692 // We provide this function ourselves as it is
3693 // missing in GDK (top of this file).
3695 GdkWindow
*window
= (GdkWindow
*) NULL
;
3697 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3699 window
= GetConnectWidget()->window
;
3702 gdk_window_warp_pointer( window
, x
, y
);
3706 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3708 if (!m_widget
) return;
3709 if (!m_widget
->window
) return;
3713 wxapp_install_idle_handler();
3715 wxRect
myRect(0,0,0,0);
3716 if (m_wxwindow
&& rect
)
3718 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3719 m_wxwindow
->allocation
.height
));
3720 myRect
.Intersect(*rect
);
3721 if (!myRect
.width
|| !myRect
.height
)
3722 // nothing to do, rectangle is empty
3727 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3731 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3732 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3736 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3737 m_clearRegion
.Clear();
3738 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3746 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3747 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3751 GdkRectangle gdk_rect
;
3752 gdk_rect
.x
= rect
->x
;
3753 gdk_rect
.y
= rect
->y
;
3754 gdk_rect
.width
= rect
->width
;
3755 gdk_rect
.height
= rect
->height
;
3756 gtk_widget_draw( m_widget
, &gdk_rect
);
3763 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3764 m_updateRegion
.Clear();
3765 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3769 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3777 GdkRectangle gdk_rect
;
3778 gdk_rect
.x
= rect
->x
;
3779 gdk_rect
.y
= rect
->y
;
3780 gdk_rect
.width
= rect
->width
;
3781 gdk_rect
.height
= rect
->height
;
3782 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3786 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3792 void wxWindowGTK::Update()
3797 void wxWindowGTK::GtkUpdate()
3800 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3801 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3803 if (!m_updateRegion
.IsEmpty())
3804 GtkSendPaintEvents();
3808 void wxWindowGTK::GtkSendPaintEvents()
3813 m_clearRegion
.Clear();
3815 m_updateRegion
.Clear();
3819 // Clip to paint region in wxClientDC
3820 m_clipPaintRegion
= TRUE
;
3823 // widget to draw on
3824 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3826 // later for GTK 2.0, too.
3827 if (GetThemeEnabled())
3829 // find ancestor from which to steal background
3830 wxWindow
*parent
= GetParent();
3831 while (parent
&& !parent
->IsTopLevel())
3832 parent
= parent
->GetParent();
3834 parent
= (wxWindow
*)this;
3836 wxRegionIterator
upd( m_updateRegion
);
3840 rect
.x
= upd
.GetX();
3841 rect
.y
= upd
.GetY();
3842 rect
.width
= upd
.GetWidth();
3843 rect
.height
= upd
.GetHeight();
3845 gtk_paint_flat_box( parent
->m_widget
->style
,
3862 wxWindowDC
dc( (wxWindow
*)this );
3863 dc
.SetClippingRegion( m_updateRegion
);
3865 wxEraseEvent
erase_event( GetId(), &dc
);
3866 erase_event
.SetEventObject( this );
3868 GetEventHandler()->ProcessEvent(erase_event
);
3871 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3873 wxWindowDC
dc( (wxWindow
*)this );
3874 if (m_clearRegion
.IsEmpty())
3875 dc
.SetClippingRegion( m_updateRegion
);
3877 dc
.SetClippingRegion( m_clearRegion
);
3879 wxEraseEvent
erase_event( GetId(), &dc
);
3880 erase_event
.SetEventObject( this );
3882 if (!GetEventHandler()->ProcessEvent(erase_event
))
3886 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3887 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3889 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
3891 wxRegionIterator
upd( m_clearRegion
);
3894 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3895 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3899 m_clearRegion
.Clear();
3903 wxNcPaintEvent
nc_paint_event( GetId() );
3904 nc_paint_event
.SetEventObject( this );
3905 GetEventHandler()->ProcessEvent( nc_paint_event
);
3907 wxPaintEvent
paint_event( GetId() );
3908 paint_event
.SetEventObject( this );
3909 GetEventHandler()->ProcessEvent( paint_event
);
3911 m_clipPaintRegion
= FALSE
;
3913 #ifndef __WXUNIVERSAL__
3915 // The following code will result in all window-less widgets
3916 // being redrawn because the wxWidgets class is allowed to
3917 // paint over the window-less widgets.
3919 GList
*children
= pizza
->children
;
3922 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3923 children
= children
->next
;
3925 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3926 GTK_WIDGET_DRAWABLE (child
->widget
))
3928 // Get intersection of widget area and update region
3929 wxRegion
region( m_updateRegion
);
3931 GdkEventExpose gdk_event
;
3932 gdk_event
.type
= GDK_EXPOSE
;
3933 gdk_event
.window
= pizza
->bin_window
;
3934 gdk_event
.count
= 0;
3936 wxRegionIterator
upd( m_updateRegion
);
3940 rect
.x
= upd
.GetX();
3941 rect
.y
= upd
.GetY();
3942 rect
.width
= upd
.GetWidth();
3943 rect
.height
= upd
.GetHeight();
3945 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3947 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3957 m_updateRegion
.Clear();
3960 void wxWindowGTK::ClearBackground()
3962 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3965 if (m_wxwindow
&& m_wxwindow
->window
)
3967 m_clearRegion
.Clear();
3968 wxSize
size( GetClientSize() );
3969 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3971 // Better do this in idle?
3978 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3980 wxWindowBase::DoSetToolTip(tip
);
3983 m_tooltip
->Apply( (wxWindow
*)this );
3986 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3988 wxString
tmp( tip
);
3989 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
3991 #endif // wxUSE_TOOLTIPS
3993 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3995 GdkWindow
*window
= (GdkWindow
*) NULL
;
3997 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3999 window
= GetConnectWidget()->window
;
4003 // We need the pixel value e.g. for background clearing.
4004 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
4008 // wxMSW doesn't clear the window here, either.
4009 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
4015 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4017 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4019 if (!wxWindowBase::SetBackgroundColour(colour
))
4022 GdkWindow
*window
= (GdkWindow
*) NULL
;
4024 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4026 window
= GetConnectWidget()->window
;
4030 // indicate that a new style has been set
4031 // but it couldn't get applied as the
4032 // widget hasn't been realized yet.
4033 m_delayedBackgroundColour
= TRUE
;
4038 GtkSetBackgroundColour( colour
);
4044 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
4046 GdkWindow
*window
= (GdkWindow
*) NULL
;
4048 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4050 window
= GetConnectWidget()->window
;
4057 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4059 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4061 if (!wxWindowBase::SetForegroundColour(colour
))
4063 // don't leave if the GTK widget has just
4065 if (!m_delayedForegroundColour
) return FALSE
;
4068 GdkWindow
*window
= (GdkWindow
*) NULL
;
4070 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4072 window
= GetConnectWidget()->window
;
4076 // indicate that a new style has been set
4077 // but it couldn't get applied as the
4078 // widget hasn't been realized yet.
4079 m_delayedForegroundColour
= TRUE
;
4083 GtkSetForegroundColour( colour
);
4090 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4092 return gtk_widget_get_pango_context( m_widget
);
4095 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4098 m_x11Context
= pango_x_get_context( gdk_display
);
4100 return m_x11Context
;
4104 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4108 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4110 // FIXME: no more klass in 2.0
4112 remake
->klass
= m_widgetStyle
->klass
;
4115 gtk_style_unref( m_widgetStyle
);
4116 m_widgetStyle
= remake
;
4120 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4123 def
= gtk_widget_get_default_style();
4125 m_widgetStyle
= gtk_style_copy( def
);
4127 // FIXME: no more klass in 2.0
4129 m_widgetStyle
->klass
= def
->klass
;
4133 return m_widgetStyle
;
4136 void wxWindowGTK::SetWidgetStyle()
4138 #if DISABLE_STYLE_IF_BROKEN_THEME
4139 if (m_widget
->style
->engine_data
)
4141 static bool s_warningPrinted
= FALSE
;
4142 if (!s_warningPrinted
)
4144 printf( "wxWidgets warning: Widget styles disabled due to buggy GTK theme.\n" );
4145 s_warningPrinted
= TRUE
;
4147 m_widgetStyle
= m_widget
->style
;
4152 GtkStyle
*style
= GetWidgetStyle();
4157 pango_font_description_free( style
->font_desc
);
4158 style
->font_desc
= pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4160 gdk_font_unref( style
->font
);
4161 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4167 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4168 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4170 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4171 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4172 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4176 // Try to restore the gtk default style. This is still a little
4177 // oversimplified for what is probably really needed here for controls
4178 // other than buttons, but is better than not being able to (re)set a
4179 // control's foreground colour to *wxBLACK -- RL
4180 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4183 def
= gtk_widget_get_default_style();
4185 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4186 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4187 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4191 if ( m_hasBgCol
&& m_backgroundColour
.Ok() )
4193 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4194 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4196 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4197 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4198 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4199 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4200 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4201 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4202 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4203 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4207 // Try to restore the gtk default style. This is still a little
4208 // oversimplified for what is probably really needed here for controls
4209 // other than buttons, but is better than not being able to (re)set a
4210 // control's background colour to default grey and means resetting a
4211 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4213 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4216 def
= gtk_widget_get_default_style();
4218 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4219 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4220 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4221 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4222 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4223 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4224 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4225 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4230 void wxWindowGTK::ApplyWidgetStyle()
4234 //-----------------------------------------------------------------------------
4235 // Pop-up menu stuff
4236 //-----------------------------------------------------------------------------
4238 #if wxUSE_MENUS_NATIVE
4241 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4243 *is_waiting
= FALSE
;
4246 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4248 menu
->SetInvokingWindow( win
);
4249 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4252 wxMenuItem
*menuitem
= node
->GetData();
4253 if (menuitem
->IsSubMenu())
4255 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4258 node
= node
->GetNext();
4262 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4265 gboolean
* WXUNUSED(whatever
),
4267 gpointer user_data
)
4269 // ensure that the menu appears entirely on screen
4271 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4273 wxSize sizeScreen
= wxGetDisplaySize();
4274 wxPoint
*pos
= (wxPoint
*)user_data
;
4276 gint xmax
= sizeScreen
.x
- req
.width
,
4277 ymax
= sizeScreen
.y
- req
.height
;
4279 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4280 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4283 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4285 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4287 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4289 SetInvokingWindow( menu
, this );
4293 bool is_waiting
= true;
4295 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4297 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4298 (gpointer
)&is_waiting
);
4302 GtkMenuPositionFunc posfunc
;
4303 if ( x
== -1 && y
== -1 )
4305 // use GTK's default positioning algorithm
4311 pos
= ClientToScreen(wxPoint(x
, y
));
4313 posfunc
= wxPopupMenuPositionCallback
;
4317 GTK_MENU(menu
->m_menu
),
4318 (GtkWidget
*) NULL
, // parent menu shell
4319 (GtkWidget
*) NULL
, // parent menu item
4320 posfunc
, // function to position it
4321 userdata
, // client data
4322 0, // button used to activate it
4324 gtk_get_current_event_time()
4326 gs_timeLastClick
// the time of activation
4332 gtk_main_iteration();
4338 #endif // wxUSE_MENUS_NATIVE
4340 #if wxUSE_DRAG_AND_DROP
4342 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4344 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4346 GtkWidget
*dnd_widget
= GetConnectWidget();
4348 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4350 if (m_dropTarget
) delete m_dropTarget
;
4351 m_dropTarget
= dropTarget
;
4353 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4356 #endif // wxUSE_DRAG_AND_DROP
4358 GtkWidget
* wxWindowGTK::GetConnectWidget()
4360 GtkWidget
*connect_widget
= m_widget
;
4361 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4363 return connect_widget
;
4366 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4369 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4371 return (window
== m_widget
->window
);
4374 bool wxWindowGTK::SetFont( const wxFont
&font
)
4376 if (!wxWindowBase::SetFont(font
) || !m_widget
)
4381 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4382 if ( sysbg
== m_backgroundColour
)
4384 m_backgroundColour
= wxNullColour
;
4386 m_backgroundColour
= sysbg
;
4396 void wxWindowGTK::DoCaptureMouse()
4398 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4400 GdkWindow
*window
= (GdkWindow
*) NULL
;
4402 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4404 window
= GetConnectWidget()->window
;
4406 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4408 wxCursor
* cursor
= & m_cursor
;
4410 cursor
= wxSTANDARD_CURSOR
;
4412 gdk_pointer_grab( window
, FALSE
,
4414 (GDK_BUTTON_PRESS_MASK
|
4415 GDK_BUTTON_RELEASE_MASK
|
4416 GDK_POINTER_MOTION_HINT_MASK
|
4417 GDK_POINTER_MOTION_MASK
),
4419 cursor
->GetCursor(),
4420 (guint32
)GDK_CURRENT_TIME
);
4421 g_captureWindow
= this;
4422 g_captureWindowHasMouse
= TRUE
;
4425 void wxWindowGTK::DoReleaseMouse()
4427 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4429 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4431 g_captureWindow
= (wxWindowGTK
*) NULL
;
4433 GdkWindow
*window
= (GdkWindow
*) NULL
;
4435 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4437 window
= GetConnectWidget()->window
;
4442 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4446 wxWindow
*wxWindowBase::GetCapture()
4448 return (wxWindow
*)g_captureWindow
;
4451 bool wxWindowGTK::IsRetained() const
4456 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4457 int range
, bool refresh
)
4459 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4461 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4463 m_hasScrolling
= TRUE
;
4465 if (orient
== wxHORIZONTAL
)
4467 float fpos
= (float)pos
;
4468 float frange
= (float)range
;
4469 float fthumb
= (float)thumbVisible
;
4470 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4471 if (fpos
< 0.0) fpos
= 0.0;
4473 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4474 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4476 SetScrollPos( orient
, pos
, refresh
);
4480 m_oldHorizontalPos
= fpos
;
4482 m_hAdjust
->lower
= 0.0;
4483 m_hAdjust
->upper
= frange
;
4484 m_hAdjust
->value
= fpos
;
4485 m_hAdjust
->step_increment
= 1.0;
4486 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4487 m_hAdjust
->page_size
= fthumb
;
4491 float fpos
= (float)pos
;
4492 float frange
= (float)range
;
4493 float fthumb
= (float)thumbVisible
;
4494 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4495 if (fpos
< 0.0) fpos
= 0.0;
4497 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4498 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4500 SetScrollPos( orient
, pos
, refresh
);
4504 m_oldVerticalPos
= fpos
;
4506 m_vAdjust
->lower
= 0.0;
4507 m_vAdjust
->upper
= frange
;
4508 m_vAdjust
->value
= fpos
;
4509 m_vAdjust
->step_increment
= 1.0;
4510 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4511 m_vAdjust
->page_size
= fthumb
;
4514 if (orient
== wxHORIZONTAL
)
4515 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4517 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4520 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4522 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4524 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4526 if (orient
== wxHORIZONTAL
)
4528 float fpos
= (float)pos
;
4529 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4530 if (fpos
< 0.0) fpos
= 0.0;
4531 m_oldHorizontalPos
= fpos
;
4533 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4534 m_hAdjust
->value
= fpos
;
4538 float fpos
= (float)pos
;
4539 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4540 if (fpos
< 0.0) fpos
= 0.0;
4541 m_oldVerticalPos
= fpos
;
4543 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4544 m_vAdjust
->value
= fpos
;
4547 if (m_wxwindow
->window
)
4549 if (orient
== wxHORIZONTAL
)
4551 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4552 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4554 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4556 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4557 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4561 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4562 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4564 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4566 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4567 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4572 int wxWindowGTK::GetScrollThumb( int orient
) const
4574 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4576 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4578 if (orient
== wxHORIZONTAL
)
4579 return (int)(m_hAdjust
->page_size
+0.5);
4581 return (int)(m_vAdjust
->page_size
+0.5);
4584 int wxWindowGTK::GetScrollPos( int orient
) const
4586 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4588 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4590 if (orient
== wxHORIZONTAL
)
4591 return (int)(m_hAdjust
->value
+0.5);
4593 return (int)(m_vAdjust
->value
+0.5);
4596 int wxWindowGTK::GetScrollRange( int orient
) const
4598 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4600 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4602 if (orient
== wxHORIZONTAL
)
4603 return (int)(m_hAdjust
->upper
+0.5);
4605 return (int)(m_vAdjust
->upper
+0.5);
4608 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4610 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4612 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4614 // No scrolling requested.
4615 if ((dx
== 0) && (dy
== 0)) return;
4618 if (!m_updateRegion
.IsEmpty())
4620 m_updateRegion
.Offset( dx
, dy
);
4624 GetClientSize( &cw
, &ch
);
4625 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4628 if (!m_clearRegion
.IsEmpty())
4630 m_clearRegion
.Offset( dx
, dy
);
4634 GetClientSize( &cw
, &ch
);
4635 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4639 m_clipPaintRegion
= TRUE
;
4641 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4643 m_clipPaintRegion
= FALSE
;
4647 // Find the wxWindow at the current mouse position, also returning the mouse
4649 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4651 pt
= wxGetMousePosition();
4652 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4656 // Get the current mouse position.
4657 wxPoint
wxGetMousePosition()
4659 /* This crashes when used within wxHelpContext,
4660 so we have to use the X-specific implementation below.
4662 GdkModifierType *mask;
4663 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4665 return wxPoint(x, y);
4669 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4671 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4672 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4673 Window rootReturn
, childReturn
;
4674 int rootX
, rootY
, winX
, winY
;
4675 unsigned int maskReturn
;
4677 XQueryPointer (display
,
4681 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4682 return wxPoint(rootX
, rootY
);
4686 // ----------------------------------------------------------------------------
4688 // ----------------------------------------------------------------------------
4690 class wxWinModule
: public wxModule
4697 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4700 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4702 bool wxWinModule::OnInit()
4704 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4705 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4710 void wxWinModule::OnExit()
4713 gdk_gc_unref( g_eraseGC
);