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>
84 extern GtkContainerClass
*pizza_parent_class
;
87 //-----------------------------------------------------------------------------
88 // documentation on internals
89 //-----------------------------------------------------------------------------
92 I have been asked several times about writing some documentation about
93 the GTK port of wxWidgets, especially its internal structures. Obviously,
94 you cannot understand wxGTK without knowing a little about the GTK, but
95 some more information about what the wxWindow, which is the base class
96 for all other window classes, does seems required as well.
100 What does wxWindow do? It contains the common interface for the following
101 jobs of its descendants:
103 1) Define the rudimentary behaviour common to all window classes, such as
104 resizing, intercepting user input (so as to make it possible to use these
105 events for special purposes in a derived class), window names etc.
107 2) Provide the possibility to contain and manage children, if the derived
108 class is allowed to contain children, which holds true for those window
109 classes which do not display a native GTK widget. To name them, these
110 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
111 work classes are a special case and are handled a bit differently from
112 the rest. The same holds true for the wxNotebook class.
114 3) Provide the possibility to draw into a client area of a window. This,
115 too, only holds true for classes that do not display a native GTK widget
118 4) Provide the entire mechanism for scrolling widgets. This actual inter-
119 face for this is usually in wxScrolledWindow, but the GTK implementation
122 5) A multitude of helper or extra methods for special purposes, such as
123 Drag'n'Drop, managing validators etc.
125 6) Display a border (sunken, raised, simple or none).
127 Normally one might expect, that one wxWidgets window would always correspond
128 to one GTK widget. Under GTK, there is no such allround widget that has all
129 the functionality. Moreover, the GTK defines a client area as a different
130 widget from the actual widget you are handling. Last but not least some
131 special classes (e.g. wxFrame) handle different categories of widgets and
132 still have the possibility to draw something in the client area.
133 It was therefore required to write a special purpose GTK widget, that would
134 represent a client area in the sense of wxWidgets capable to do the jobs
135 2), 3) and 4). I have written this class and it resides in win_gtk.c of
138 All windows must have a widget, with which they interact with other under-
139 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
140 thw wxWindow class has a member variable called m_widget which holds a
141 pointer to this widget. When the window class represents a GTK native widget,
142 this is (in most cases) the only GTK widget the class manages. E.g. the
143 wxStaticText class handles only a GtkLabel widget a pointer to which you
144 can find in m_widget (defined in wxWindow)
146 When the class has a client area for drawing into and for containing children
147 it has to handle the client area widget (of the type GtkPizza, defined in
148 win_gtk.c), but there could be any number of widgets, handled by a class
149 The common rule for all windows is only, that the widget that interacts with
150 the rest of GTK must be referenced in m_widget and all other widgets must be
151 children of this widget on the GTK level. The top-most widget, which also
152 represents the client area, must be in the m_wxwindow field and must be of
155 As I said, the window classes that display a GTK native widget only have
156 one widget, so in the case of e.g. the wxButton class m_widget holds a
157 pointer to a GtkButton widget. But windows with client areas (for drawing
158 and children) have a m_widget field that is a pointer to a GtkScrolled-
159 Window and a m_wxwindow field that is pointer to a GtkPizza and this
160 one is (in the GTK sense) a child of the GtkScrolledWindow.
162 If the m_wxwindow field is set, then all input to this widget is inter-
163 cepted and sent to the wxWidgets class. If not, all input to the widget
164 that gets pointed to by m_widget gets intercepted and sent to the class.
168 The design of scrolling in wxWidgets is markedly different from that offered
169 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
170 clicking on a scrollbar belonging to scrolled window will inevitably move
171 the window. In wxWidgets, the scrollbar will only emit an event, send this
172 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
173 which actually moves the window and its subchildren. Note that GtkPizza
174 memorizes how much it has been scrolled but that wxWidgets forgets this
175 so that the two coordinates systems have to be kept in synch. This is done
176 in various places using the pizza->xoffset and pizza->yoffset values.
180 Singularily the most broken code in GTK is the code that is supposes to
181 inform subwindows (child windows) about new positions. Very often, duplicate
182 events are sent without changes in size or position, equally often no
183 events are sent at all (All this is due to a bug in the GtkContainer code
184 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
185 GTK's own system and it simply waits for size events for toplevel windows
186 and then iterates down the respective size events to all window. This has
187 the disadvantage, that windows might get size events before the GTK widget
188 actually has the reported size. This doesn't normally pose any problem, but
189 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
190 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
191 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
192 window that is used for OpenGl output really has that size (as reported by
197 If someone at some point of time feels the immense desire to have a look at,
198 change or attempt to optimse the Refresh() logic, this person will need an
199 intimate understanding of what a "draw" and what an "expose" events are and
200 what there are used for, in particular when used in connection with GTK's
201 own windowless widgets. Beware.
205 Cursors, too, have been a constant source of pleasure. The main difficulty
206 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
207 for the parent. To prevent this from doing too much harm, I use idle time
208 to set the cursor over and over again, starting from the toplevel windows
209 and ending with the youngest generation (speaking of parent and child windows).
210 Also don't forget that cursors (like much else) are connected to GdkWindows,
211 not GtkWidgets and that the "window" field of a GtkWidget might very well
212 point to the GdkWindow of the parent widget (-> "window less widget") and
213 that the two obviously have very different meanings.
217 //-----------------------------------------------------------------------------
219 //-----------------------------------------------------------------------------
221 extern wxList wxPendingDelete
;
222 extern bool g_blockEventsOnDrag
;
223 extern bool g_blockEventsOnScroll
;
224 extern wxCursor g_globalCursor
;
226 static GdkGC
*g_eraseGC
= NULL
;
228 // mouse capture state: the window which has it and if the mouse is currently
230 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
231 static bool g_captureWindowHasMouse
= FALSE
;
233 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
235 // the last window which had the focus - this is normally never NULL (except
236 // if we never had focus at all) as even when g_focusWindow is NULL it still
237 // keeps its previous value
238 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
240 // the frame that is currently active (i.e. its child has focus). It is
241 // used to generate wxActivateEvents
242 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
243 static bool g_activeFrameLostFocus
= FALSE
;
245 // If a window get the focus set but has not been realized
246 // yet, defer setting the focus to idle time.
247 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
249 // if we detect that the app has got/lost the focus, we set this variable to
250 // either TRUE or FALSE and an activate event will be sent during the next
251 // OnIdle() call and it is reset to -1: this value means that we shouldn't
252 // send any activate events at all
253 static int g_sendActivateEvent
= -1;
255 // hack: we need something to pass to gtk_menu_popup, so we store the time of
256 // the last click here
257 static guint32 gs_timeLastClick
= 0;
259 extern bool g_mainThreadLocked
;
261 //-----------------------------------------------------------------------------
263 //-----------------------------------------------------------------------------
268 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
270 # define DEBUG_MAIN_THREAD
273 #define DEBUG_MAIN_THREAD
276 // the trace mask used for the focus debugging messages
277 #define TRACE_FOCUS _T("focus")
279 //-----------------------------------------------------------------------------
280 // missing gdk functions
281 //-----------------------------------------------------------------------------
284 gdk_window_warp_pointer (GdkWindow
*window
,
289 GdkWindowPrivate
*priv
;
293 window
= GDK_ROOT_PARENT();
296 if (!GDK_WINDOW_DESTROYED(window
))
298 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
299 None
, /* not source window -> move from anywhere */
300 GDK_WINDOW_XID(window
), /* dest window */
301 0, 0, 0, 0, /* not source window -> move from anywhere */
305 priv
= (GdkWindowPrivate
*) window
;
307 if (!priv
->destroyed
)
309 XWarpPointer (priv
->xdisplay
,
310 None
, /* not source window -> move from anywhere */
311 priv
->xwindow
, /* dest window */
312 0, 0, 0, 0, /* not source window -> move from anywhere */
318 //-----------------------------------------------------------------------------
320 //-----------------------------------------------------------------------------
322 extern void wxapp_install_idle_handler();
323 extern bool g_isIdle
;
325 //-----------------------------------------------------------------------------
326 // local code (see below)
327 //-----------------------------------------------------------------------------
329 // returns the child of win which currently has focus or NULL if not found
331 // Note: can't be static, needed by textctrl.cpp.
332 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
334 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
336 return (wxWindow
*)NULL
;
338 if ( winFocus
== win
)
339 return (wxWindow
*)win
;
341 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
343 node
= node
->GetNext() )
345 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
350 return (wxWindow
*)NULL
;
353 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
355 // wxUniversal widgets draw the borders and scrollbars themselves
356 #ifndef __WXUNIVERSAL__
363 if (win
->m_hasScrolling
)
365 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
367 GtkRequisition vscroll_req
;
368 vscroll_req
.width
= 2;
369 vscroll_req
.height
= 2;
370 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
371 (scroll_window
->vscrollbar
, &vscroll_req
);
373 GtkRequisition hscroll_req
;
374 hscroll_req
.width
= 2;
375 hscroll_req
.height
= 2;
376 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
377 (scroll_window
->hscrollbar
, &hscroll_req
);
379 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
381 if (scroll_window
->vscrollbar_visible
)
383 dw
+= vscroll_req
.width
;
384 dw
+= scroll_class
->scrollbar_spacing
;
387 if (scroll_window
->hscrollbar_visible
)
389 dh
+= hscroll_req
.height
;
390 dh
+= scroll_class
->scrollbar_spacing
;
396 if (GTK_WIDGET_NO_WINDOW (widget
))
398 dx
+= widget
->allocation
.x
;
399 dy
+= widget
->allocation
.y
;
402 if (win
->HasFlag(wxRAISED_BORDER
))
404 gtk_draw_shadow( widget
->style
,
409 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
413 if (win
->HasFlag(wxSUNKEN_BORDER
))
415 gtk_draw_shadow( widget
->style
,
420 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
424 if (win
->HasFlag(wxSIMPLE_BORDER
))
427 gc
= gdk_gc_new( widget
->window
);
428 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
429 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
431 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
435 #endif // __WXUNIVERSAL__
438 //-----------------------------------------------------------------------------
439 // "expose_event" of m_widget
440 //-----------------------------------------------------------------------------
442 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
444 if (gdk_event
->count
> 0) return FALSE
;
446 draw_frame( widget
, win
);
450 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
456 //-----------------------------------------------------------------------------
457 // "draw" of m_widget
458 //-----------------------------------------------------------------------------
462 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
464 draw_frame( widget
, win
);
469 //-----------------------------------------------------------------------------
470 // "size_request" of m_widget
471 //-----------------------------------------------------------------------------
473 // make it extern because wxStatitText needs to disconnect this one
475 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
476 GtkRequisition
*requisition
,
480 win
->GetSize( &w
, &h
);
486 requisition
->height
= h
;
487 requisition
->width
= w
;
490 //-----------------------------------------------------------------------------
491 // "expose_event" of m_wxwindow
492 //-----------------------------------------------------------------------------
494 static int gtk_window_expose_callback( GtkWidget
*widget
,
495 GdkEventExpose
*gdk_event
,
501 wxapp_install_idle_handler();
504 // This callback gets called in drawing-idle time under
505 // GTK 2.0, so we don't need to defer anything to idle
508 GtkPizza
*pizza
= GTK_PIZZA( widget
);
509 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
514 wxPrintf( wxT("OnExpose from ") );
515 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
516 wxPrintf( win
->GetClassInfo()->GetClassName() );
517 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
518 (int)gdk_event
->area
.y
,
519 (int)gdk_event
->area
.width
,
520 (int)gdk_event
->area
.height
);
525 win
->m_wxwindow
->style
,
529 (GdkRectangle
*) NULL
,
531 (char *)"button", // const_cast
536 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
538 win
->GtkSendPaintEvents();
541 // Let parent window draw window less widgets
542 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
544 // This gets called immediately after an expose event
545 // under GTK 1.2 so we collect the calls and wait for
546 // the idle handler to pick things up.
548 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
550 gdk_event
->area
.width
,
551 gdk_event
->area
.height
);
552 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
554 gdk_event
->area
.width
,
555 gdk_event
->area
.height
);
557 // Actual redrawing takes place in idle time.
564 //-----------------------------------------------------------------------------
565 // "event" of m_wxwindow
566 //-----------------------------------------------------------------------------
568 // GTK thinks it is clever and filters out a certain amount of "unneeded"
569 // expose events. We need them, of course, so we override the main event
570 // procedure in GtkWidget by giving our own handler for all system events.
571 // There, we look for expose events ourselves whereas all other events are
574 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
575 GdkEventExpose
*event
,
578 if (event
->type
== GDK_EXPOSE
)
580 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
587 //-----------------------------------------------------------------------------
588 // "draw" of m_wxwindow
589 //-----------------------------------------------------------------------------
593 // This callback is a complete replacement of the gtk_pizza_draw() function,
594 // which is disabled.
596 static void gtk_window_draw_callback( GtkWidget
*widget
,
603 wxapp_install_idle_handler();
605 // if there are any children we must refresh everything
608 if ( !win
->HasFlag(wxFULL_REPAINT_ON_RESIZE
) &&
609 win
->GetChildren().IsEmpty() )
617 wxPrintf( wxT("OnDraw from ") );
618 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
619 wxPrintf( win
->GetClassInfo()->GetClassName() );
620 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
627 #ifndef __WXUNIVERSAL__
628 GtkPizza
*pizza
= GTK_PIZZA (widget
);
630 if (win
->GetThemeEnabled() && win
->GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
632 wxWindow
*parent
= win
->GetParent();
633 while (parent
&& !parent
->IsTopLevel())
634 parent
= parent
->GetParent();
638 gtk_paint_flat_box (parent
->m_widget
->style
,
649 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
650 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
652 // Update immediately, not in idle time.
655 #ifndef __WXUNIVERSAL__
656 // Redraw child widgets
657 GList
*children
= pizza
->children
;
660 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
661 children
= children
->next
;
663 GdkRectangle child_area
;
664 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
666 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
674 //-----------------------------------------------------------------------------
675 // "key_press_event" from any window
676 //-----------------------------------------------------------------------------
678 // set WXTRACE to this to see the key event codes on the console
679 #define TRACE_KEYS _T("keyevent")
681 // translates an X key symbol to WXK_XXX value
683 // if isChar is true it means that the value returned will be used for EVT_CHAR
684 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
685 // for example, while if it is false it means that the value is going to be
686 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
688 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
694 // Shift, Control and Alt don't generate the CHAR events at all
697 key_code
= isChar
? 0 : WXK_SHIFT
;
701 key_code
= isChar
? 0 : WXK_CONTROL
;
709 key_code
= isChar
? 0 : WXK_ALT
;
712 // neither do the toggle modifies
713 case GDK_Scroll_Lock
:
714 key_code
= isChar
? 0 : WXK_SCROLL
;
718 key_code
= isChar
? 0 : WXK_CAPITAL
;
722 key_code
= isChar
? 0 : WXK_NUMLOCK
;
726 // various other special keys
739 case GDK_ISO_Left_Tab
:
746 key_code
= WXK_RETURN
;
750 key_code
= WXK_CLEAR
;
754 key_code
= WXK_PAUSE
;
758 key_code
= WXK_SELECT
;
762 key_code
= WXK_PRINT
;
766 key_code
= WXK_EXECUTE
;
770 key_code
= WXK_ESCAPE
;
773 // cursor and other extended keyboard keys
775 key_code
= WXK_DELETE
;
791 key_code
= WXK_RIGHT
;
798 case GDK_Prior
: // == GDK_Page_Up
799 key_code
= WXK_PRIOR
;
802 case GDK_Next
: // == GDK_Page_Down
815 key_code
= WXK_INSERT
;
830 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
834 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
838 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
842 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
846 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
850 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
854 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
858 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
862 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
866 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
870 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
874 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
878 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
881 case GDK_KP_Prior
: // == GDK_KP_Page_Up
882 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
885 case GDK_KP_Next
: // == GDK_KP_Page_Down
886 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
890 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
894 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
898 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
902 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
906 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
909 case GDK_KP_Multiply
:
910 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
914 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
917 case GDK_KP_Separator
:
918 // FIXME: what is this?
919 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
922 case GDK_KP_Subtract
:
923 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
927 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
931 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
948 key_code
= WXK_F1
+ keysym
- GDK_F1
;
958 static inline bool wxIsAsciiKeysym(KeySym ks
)
963 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
965 GdkEventKey
*gdk_event
)
969 GdkModifierType state
;
970 if (gdk_event
->window
)
971 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
973 event
.SetTimestamp( gdk_event
->time
);
974 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
975 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
976 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
977 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
978 event
.m_scanCode
= gdk_event
->keyval
;
979 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
980 event
.m_rawFlags
= 0;
983 event
.SetEventObject( win
);
988 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
990 GdkEventKey
*gdk_event
)
992 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
993 // but only event->keyval which is quite useless to us, so remember
994 // the last character from GDK_KEY_PRESS and reuse it as last resort
996 // NB: should be MT-safe as we're always called from the main thread only
1001 } s_lastKeyPress
= { 0, 0 };
1003 KeySym keysym
= gdk_event
->keyval
;
1005 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
1006 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
1010 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
1014 // do we have the translation or is it a plain ASCII character?
1015 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1017 // we should use keysym if it is ASCII as X does some translations
1018 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1019 // which we don't want here (but which we do use for OnChar())
1020 if ( !wxIsAsciiKeysym(keysym
) )
1022 keysym
= (KeySym
)gdk_event
->string
[0];
1025 // we want to always get the same key code when the same key is
1026 // pressed regardless of the state of the modifies, i.e. on a
1027 // standard US keyboard pressing '5' or '%' ('5' key with
1028 // Shift) should result in the same key code in OnKeyDown():
1029 // '5' (although OnChar() will get either '5' or '%').
1031 // to do it we first translate keysym to keycode (== scan code)
1032 // and then back but always using the lower register
1033 Display
*dpy
= (Display
*)wxGetDisplay();
1034 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1036 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1038 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1040 // use the normalized, i.e. lower register, keysym if we've
1042 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1044 // as explained above, we want to have lower register key codes
1045 // normally but for the letter keys we want to have the upper ones
1047 // NB: don't use XConvertCase() here, we want to do it for letters
1049 key_code
= toupper(key_code
);
1051 else // non ASCII key, what to do?
1053 // by default, ignore it
1056 // but if we have cached information from the last KEY_PRESS
1057 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1060 if ( keysym
== s_lastKeyPress
.keysym
)
1062 key_code
= s_lastKeyPress
.keycode
;
1067 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1069 // remember it to be reused for KEY_UP event later
1070 s_lastKeyPress
.keysym
= keysym
;
1071 s_lastKeyPress
.keycode
= key_code
;
1075 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1077 // sending unknown key events doesn't really make sense
1081 // now fill all the other fields
1082 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
1084 event
.m_keyCode
= key_code
;
1093 GtkIMContext
*context
;
1094 GdkEventKey
*lastKeyEvent
;
1098 context
= gtk_im_multicontext_new();
1099 lastKeyEvent
= NULL
;
1103 g_object_unref(context
);
1108 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1109 GdkEventKey
*gdk_event
,
1115 wxapp_install_idle_handler();
1119 if (g_blockEventsOnDrag
)
1123 // We have to pass key press events through GTK+'s Input Method context
1124 // object in order to get correct characters. By doing so, we loose the
1125 // ability to let other GTK+'s handlers (namely, widgets' default signal
1126 // handlers) handle the signal by returning false from this callback.
1127 // Because GTK+ sends the events to parent widgets as well, we can't
1128 // afford loosing it, otherwise native widgets inserted into wxPanel
1129 // would break in subtle ways (e.g. spacebar would no longer toggle
1130 // wxCheckButton's state). Therefore, we only pass the event to IM if it
1131 // originated in this window's widget, which we detect by checking if we've
1132 // seen the same event before (no events from children are lost this way,
1133 // because gtk_window_key_press_callback is installed for native controls
1134 // as well and the wxKeyEvent it creates propagates upwards).
1135 static GdkEventKey s_lastEvent
;
1137 bool useIM
= (win
->m_imData
!= NULL
) &&
1138 memcmp(gdk_event
, &s_lastEvent
, sizeof(GdkEventKey
)) != 0;
1140 s_lastEvent
= *gdk_event
;
1143 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1144 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1146 // unknown key pressed, ignore (the event would be useless anyhow)
1150 // it may be useful for the input method, though:
1151 win
->m_imData
->lastKeyEvent
= gdk_event
;
1152 bool ret
= gtk_im_context_filter_keypress(win
->m_imData
->context
,
1154 win
->m_imData
->lastKeyEvent
= NULL
;
1161 // Emit KEY_DOWN event
1162 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1167 wxWindowGTK
*ancestor
= win
;
1170 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1173 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1174 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1177 if (ancestor
->IsTopLevel())
1179 ancestor
= ancestor
->GetParent();
1182 #endif // wxUSE_ACCEL
1184 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1185 // will only be sent if it is not in an accelerator table.
1191 // In GTK 2.0, we need to hand over the key event to an input method
1192 // and the IM will emit a "commit" event containing the actual utf8
1193 // character. In that case the EVT_CHAR events will be sent from
1195 win
->m_imData
->lastKeyEvent
= gdk_event
;
1196 if ( gtk_im_context_filter_keypress(win
->m_imData
->context
,
1199 win
->m_imData
->lastKeyEvent
= NULL
;
1200 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1204 win
->m_imData
->lastKeyEvent
= NULL
;
1209 KeySym keysym
= gdk_event
->keyval
;
1210 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1211 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1214 if ( gdk_event
->length
== 1 )
1216 key_code
= (unsigned char)gdk_event
->string
[0];
1218 else if ( wxIsAsciiKeysym(keysym
) )
1221 key_code
= (unsigned char)keysym
;
1227 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1229 event
.m_keyCode
= key_code
;
1231 // Implement OnCharHook by checking ancesteror top level windows
1232 wxWindow
*parent
= win
;
1233 while (parent
&& !parent
->IsTopLevel())
1234 parent
= parent
->GetParent();
1237 event
.SetEventType( wxEVT_CHAR_HOOK
);
1238 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1243 event
.SetEventType(wxEVT_CHAR
);
1244 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1249 // win is a control: tab can be propagated up
1251 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1252 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1253 // have this style, yet choose not to process this particular TAB in which
1254 // case TAB must still work as a navigational character
1255 // JS: enabling again to make consistent with other platforms
1256 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1257 // navigation behaviour)
1259 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1261 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1263 wxNavigationKeyEvent new_event
;
1264 new_event
.SetEventObject( win
->GetParent() );
1265 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1266 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1267 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1268 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1269 new_event
.SetCurrentFocus( win
);
1270 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1273 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1275 (gdk_event
->keyval
== GDK_Escape
) )
1277 // however only do it if we have a Cancel button in the dialog,
1278 // otherwise the user code may get confused by the events from a
1279 // non-existing button and, worse, a wxButton might get button event
1280 // from another button which is not really expected
1281 wxWindow
*winForCancel
= win
,
1283 while ( winForCancel
)
1285 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1288 // found a cancel button
1292 if ( winForCancel
->IsTopLevel() )
1294 // no need to look further
1298 // maybe our parent has a cancel button?
1299 winForCancel
= winForCancel
->GetParent();
1304 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1305 event
.SetEventObject(btnCancel
);
1306 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1312 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1320 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1324 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1326 // take modifiers, cursor position, timestamp etc. from the last
1327 // key_press_event that was fed into Input Method:
1328 if (window
->m_imData
->lastKeyEvent
)
1330 wxFillOtherKeyEventFields(event
,
1331 window
, window
->m_imData
->lastKeyEvent
);
1335 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1337 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1338 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1339 #endif // wxUSE_UNICODE
1340 if( !(const wxChar
*)data
)
1345 // Implement OnCharHook by checking ancestor top level windows
1346 wxWindow
*parent
= window
;
1347 while (parent
&& !parent
->IsTopLevel())
1348 parent
= parent
->GetParent();
1350 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1353 event
.m_uniChar
= *pstr
;
1354 // Backward compatible for ISO-8859
1355 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1356 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1358 event
.m_keyCode
= *pstr
;
1359 #endif // wxUSE_UNICODE
1362 event
.SetEventType( wxEVT_CHAR_HOOK
);
1363 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1368 event
.SetEventType(wxEVT_CHAR
);
1369 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1376 //-----------------------------------------------------------------------------
1377 // "key_release_event" from any window
1378 //-----------------------------------------------------------------------------
1380 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1381 GdkEventKey
*gdk_event
,
1387 wxapp_install_idle_handler();
1392 if (g_blockEventsOnDrag
)
1395 wxKeyEvent
event( wxEVT_KEY_UP
);
1396 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1398 // unknown key pressed, ignore (the event would be useless anyhow
1402 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1405 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1409 // ============================================================================
1411 // ============================================================================
1413 // ----------------------------------------------------------------------------
1414 // mouse event processing helpers
1415 // ----------------------------------------------------------------------------
1417 // init wxMouseEvent with the info from GdkEventXXX struct
1418 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1419 wxMouseEvent
& event
,
1422 event
.SetTimestamp( gdk_event
->time
);
1423 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1424 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1425 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1426 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1427 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1428 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1429 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1430 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1432 event
.m_linesPerAction
= 3;
1433 event
.m_wheelDelta
= 120;
1434 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1435 event
.m_wheelRotation
= 120;
1436 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1437 event
.m_wheelRotation
= -120;
1440 wxPoint pt
= win
->GetClientAreaOrigin();
1441 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1442 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1444 event
.SetEventObject( win
);
1445 event
.SetId( win
->GetId() );
1446 event
.SetTimestamp( gdk_event
->time
);
1449 static void AdjustEventButtonState(wxMouseEvent
& event
)
1451 // GDK reports the old state of the button for a button press event, but
1452 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1453 // for a LEFT_DOWN event, not FALSE, so we will invert
1454 // left/right/middleDown for the corresponding click events
1456 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1457 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1458 (event
.GetEventType() == wxEVT_LEFT_UP
))
1460 event
.m_leftDown
= !event
.m_leftDown
;
1464 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1465 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1466 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1468 event
.m_middleDown
= !event
.m_middleDown
;
1472 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1473 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1474 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1476 event
.m_rightDown
= !event
.m_rightDown
;
1481 // find the window to send the mouse event too
1483 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1488 if (win
->m_wxwindow
)
1490 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1491 xx
+= pizza
->xoffset
;
1492 yy
+= pizza
->yoffset
;
1495 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1498 wxWindowGTK
*child
= node
->GetData();
1500 node
= node
->GetNext();
1501 if (!child
->IsShown())
1504 if (child
->IsTransparentForMouse())
1506 // wxStaticBox is transparent in the box itself
1507 int xx1
= child
->m_x
;
1508 int yy1
= child
->m_y
;
1509 int xx2
= child
->m_x
+ child
->m_width
;
1510 int yy2
= child
->m_y
+ child
->m_height
;
1513 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1515 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1517 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1519 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1530 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1531 (child
->m_x
<= xx
) &&
1532 (child
->m_y
<= yy
) &&
1533 (child
->m_x
+child
->m_width
>= xx
) &&
1534 (child
->m_y
+child
->m_height
>= yy
))
1547 //-----------------------------------------------------------------------------
1548 // "button_press_event"
1549 //-----------------------------------------------------------------------------
1551 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1552 GdkEventButton
*gdk_event
,
1558 wxapp_install_idle_handler();
1561 wxPrintf( wxT("1) OnButtonPress from ") );
1562 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1563 wxPrintf( win->GetClassInfo()->GetClassName() );
1564 wxPrintf( wxT(".\n") );
1566 if (!win
->m_hasVMT
) return FALSE
;
1567 if (g_blockEventsOnDrag
) return TRUE
;
1568 if (g_blockEventsOnScroll
) return TRUE
;
1570 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1572 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1574 gtk_widget_grab_focus( win
->m_wxwindow
);
1576 wxPrintf( wxT("GrabFocus from ") );
1577 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1578 wxPrintf( win->GetClassInfo()->GetClassName() );
1579 wxPrintf( wxT(".\n") );
1583 // GDK sends surplus button down event
1584 // before a double click event. We
1585 // need to filter these out.
1586 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1588 GdkEvent
*peek_event
= gdk_event_peek();
1591 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1592 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1594 gdk_event_free( peek_event
);
1599 gdk_event_free( peek_event
);
1604 wxEventType event_type
= wxEVT_NULL
;
1606 // GdkDisplay is a GTK+ 2.2.0 thing
1607 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1608 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1609 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1611 // Reset GDK internal timestamp variables in order to disable GDK
1612 // triple click events. GDK will then next time believe no button has
1613 // been clicked just before, and send a normal button click event.
1614 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1615 display
->button_click_time
[1] = 0;
1616 display
->button_click_time
[0] = 0;
1620 if (gdk_event
->button
== 1)
1622 // note that GDK generates triple click events which are not supported
1623 // by wxWidgets but still have to be passed to the app as otherwise
1624 // clicks would simply go missing
1625 switch (gdk_event
->type
)
1627 // we shouldn't get triple clicks at all for GTK2 because we
1628 // suppress them artificially using the code above but we still
1629 // should map them to something for GTK1 and not just ignore them
1630 // as this would lose clicks
1631 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1632 case GDK_BUTTON_PRESS
:
1633 event_type
= wxEVT_LEFT_DOWN
;
1636 case GDK_2BUTTON_PRESS
:
1637 event_type
= wxEVT_LEFT_DCLICK
;
1641 // just to silence gcc warnings
1645 else if (gdk_event
->button
== 2)
1647 switch (gdk_event
->type
)
1649 case GDK_3BUTTON_PRESS
:
1650 case GDK_BUTTON_PRESS
:
1651 event_type
= wxEVT_MIDDLE_DOWN
;
1654 case GDK_2BUTTON_PRESS
:
1655 event_type
= wxEVT_MIDDLE_DCLICK
;
1662 else if (gdk_event
->button
== 3)
1664 switch (gdk_event
->type
)
1666 case GDK_3BUTTON_PRESS
:
1667 case GDK_BUTTON_PRESS
:
1668 event_type
= wxEVT_RIGHT_DOWN
;
1671 case GDK_2BUTTON_PRESS
:
1672 event_type
= wxEVT_RIGHT_DCLICK
;
1679 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1681 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1683 event_type
= wxEVT_MOUSEWHEEL
;
1687 if ( event_type
== wxEVT_NULL
)
1689 // unknown mouse button or click type
1693 wxMouseEvent
event( event_type
);
1694 InitMouseEvent( win
, event
, gdk_event
);
1696 AdjustEventButtonState(event
);
1698 // wxListBox actually get mouse events from the item, so we need to give it
1699 // a chance to correct this
1700 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1702 if ( event_type
== wxEVT_RIGHT_DOWN
)
1704 // generate a "context menu" event: this is similar to right mouse
1705 // click under many GUIs except that it is generated differently
1706 // (right up under MSW, ctrl-click under Mac, right down here) and
1708 // (a) it's a command event and so is propagated to the parent
1709 // (b) under MSW it can be generated from kbd too
1710 // (c) it uses screen coords (because of (a))
1711 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1713 win
->ClientToScreen(event
.GetPosition()));
1714 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1717 // find the correct window to send the event too: it may be a different one
1718 // from the one which got it at GTK+ level because some control don't have
1719 // their own X window and thus cannot get any events.
1720 if ( !g_captureWindow
)
1721 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1723 gs_timeLastClick
= gdk_event
->time
;
1726 if (event_type
== wxEVT_LEFT_DCLICK
)
1728 // GTK 1.2 crashes when intercepting double
1729 // click events from both wxSpinButton and
1731 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1733 // Just disable this event for now.
1739 if (win
->GetEventHandler()->ProcessEvent( event
))
1741 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1748 //-----------------------------------------------------------------------------
1749 // "button_release_event"
1750 //-----------------------------------------------------------------------------
1752 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1753 GdkEventButton
*gdk_event
,
1759 wxapp_install_idle_handler();
1761 if (!win
->m_hasVMT
) return FALSE
;
1762 if (g_blockEventsOnDrag
) return FALSE
;
1763 if (g_blockEventsOnScroll
) return FALSE
;
1765 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1767 wxEventType event_type
= wxEVT_NULL
;
1769 switch (gdk_event
->button
)
1772 event_type
= wxEVT_LEFT_UP
;
1776 event_type
= wxEVT_MIDDLE_UP
;
1780 event_type
= wxEVT_RIGHT_UP
;
1784 // unknwon button, don't process
1788 wxMouseEvent
event( event_type
);
1789 InitMouseEvent( win
, event
, gdk_event
);
1791 AdjustEventButtonState(event
);
1793 // same wxListBox hack as above
1794 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1796 if ( !g_captureWindow
)
1797 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1799 if (win
->GetEventHandler()->ProcessEvent( event
))
1801 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1808 //-----------------------------------------------------------------------------
1809 // "motion_notify_event"
1810 //-----------------------------------------------------------------------------
1812 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1813 GdkEventMotion
*gdk_event
,
1819 wxapp_install_idle_handler();
1821 if (!win
->m_hasVMT
) return FALSE
;
1822 if (g_blockEventsOnDrag
) return FALSE
;
1823 if (g_blockEventsOnScroll
) return FALSE
;
1825 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1827 if (gdk_event
->is_hint
)
1831 GdkModifierType state
;
1832 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1838 printf( "OnMotion from " );
1839 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1840 printf( win->GetClassInfo()->GetClassName() );
1844 wxMouseEvent
event( wxEVT_MOTION
);
1845 InitMouseEvent(win
, event
, gdk_event
);
1847 if ( g_captureWindow
)
1849 // synthetize a mouse enter or leave event if needed
1850 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1851 // This seems to be necessary and actually been added to
1852 // GDK itself in version 2.0.X
1855 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1856 if ( hasMouse
!= g_captureWindowHasMouse
)
1858 // the mouse changed window
1859 g_captureWindowHasMouse
= hasMouse
;
1861 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1862 : wxEVT_LEAVE_WINDOW
);
1863 InitMouseEvent(win
, event
, gdk_event
);
1864 event
.SetEventObject(win
);
1865 win
->GetEventHandler()->ProcessEvent(event
);
1870 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1873 if (win
->GetEventHandler()->ProcessEvent( event
))
1875 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1883 //-----------------------------------------------------------------------------
1884 // "mouse_wheel_event"
1885 //-----------------------------------------------------------------------------
1887 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1888 GdkEventScroll
* gdk_event
,
1894 wxapp_install_idle_handler();
1896 wxEventType event_type
= wxEVT_NULL
;
1897 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1898 event_type
= wxEVT_MOUSEWHEEL
;
1899 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1900 event_type
= wxEVT_MOUSEWHEEL
;
1904 wxMouseEvent
event( event_type
);
1905 // Can't use InitMouse macro because scroll events don't have button
1906 event
.SetTimestamp( gdk_event
->time
);
1907 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1908 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1909 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1910 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1911 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1912 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1913 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1914 event
.m_linesPerAction
= 3;
1915 event
.m_wheelDelta
= 120;
1916 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1917 event
.m_wheelRotation
= 120;
1919 event
.m_wheelRotation
= -120;
1921 wxPoint pt
= win
->GetClientAreaOrigin();
1922 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1923 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1925 event
.SetEventObject( win
);
1926 event
.SetId( win
->GetId() );
1927 event
.SetTimestamp( gdk_event
->time
);
1929 if (win
->GetEventHandler()->ProcessEvent( event
))
1931 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1939 //-----------------------------------------------------------------------------
1941 //-----------------------------------------------------------------------------
1943 // send the wxChildFocusEvent and wxFocusEvent, common code of
1944 // gtk_window_focus_in_callback() and SetFocus()
1945 static bool DoSendFocusEvents(wxWindow
*win
)
1947 // Notify the parent keeping track of focus for the kbd navigation
1948 // purposes that we got it.
1949 wxChildFocusEvent
eventChildFocus(win
);
1950 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1952 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1953 eventFocus
.SetEventObject(win
);
1955 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1958 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1959 GdkEvent
*WXUNUSED(event
),
1965 wxapp_install_idle_handler();
1969 gtk_im_context_focus_in(win
->m_imData
->context
);
1972 if (!win
->m_hasVMT
) return FALSE
;
1973 if (g_blockEventsOnDrag
) return FALSE
;
1975 switch ( g_sendActivateEvent
)
1978 // we've got focus from outside, synthetize wxActivateEvent
1979 g_sendActivateEvent
= 1;
1983 // another our window just lost focus, it was already ours before
1984 // - don't send any wxActivateEvent
1985 g_sendActivateEvent
= -1;
1990 g_focusWindow
= win
;
1992 wxLogTrace(TRACE_FOCUS
,
1993 _T("%s: focus in"), win
->GetName().c_str());
1997 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
2001 // caret needs to be informed about focus change
2002 wxCaret
*caret
= win
->GetCaret();
2005 caret
->OnSetFocus();
2007 #endif // wxUSE_CARET
2009 g_activeFrameLostFocus
= FALSE
;
2011 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
2012 if ( active
!= g_activeFrame
)
2014 if ( g_activeFrame
)
2016 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
2017 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2018 event
.SetEventObject(g_activeFrame
);
2019 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2022 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
2023 g_activeFrame
= active
;
2024 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
2025 event
.SetEventObject(g_activeFrame
);
2026 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2028 // Don't send focus events in addition to activate
2029 // if (win == g_activeFrame)
2033 // does the window itself think that it has the focus?
2034 if ( !win
->m_hasFocus
)
2036 // not yet, notify it
2037 win
->m_hasFocus
= TRUE
;
2039 if ( DoSendFocusEvents(win
) )
2041 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2049 //-----------------------------------------------------------------------------
2050 // "focus_out_event"
2051 //-----------------------------------------------------------------------------
2053 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2058 wxapp_install_idle_handler();
2062 gtk_im_context_focus_out(win
->m_imData
->context
);
2065 if (!win
->m_hasVMT
) return FALSE
;
2066 if (g_blockEventsOnDrag
) return FALSE
;
2068 wxLogTrace( TRACE_FOCUS
,
2069 _T("%s: focus out"), win
->GetName().c_str() );
2071 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
2073 // VZ: commenting this out because it does happen (although not easy
2074 // to reproduce, I only see it when using wxMiniFrame and not
2075 // always) and makes using Mahogany quite annoying
2077 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
2078 wxT("unfocusing window that hasn't gained focus properly") );
2081 g_activeFrameLostFocus
= TRUE
;
2084 // if the focus goes out of our app alltogether, OnIdle() will send
2085 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
2086 // g_sendActivateEvent to -1
2087 g_sendActivateEvent
= 0;
2089 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2093 g_focusWindow
= (wxWindowGTK
*)NULL
;
2101 // caret needs to be informed about focus change
2102 wxCaret
*caret
= win
->GetCaret();
2105 caret
->OnKillFocus();
2107 #endif // wxUSE_CARET
2109 // don't send the window a kill focus event if it thinks that it doesn't
2110 // have focus already
2111 if ( win
->m_hasFocus
)
2113 win
->m_hasFocus
= FALSE
;
2115 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2116 event
.SetEventObject( win
);
2118 if (win
->GetEventHandler()->ProcessEvent( event
))
2120 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
2128 //-----------------------------------------------------------------------------
2129 // "enter_notify_event"
2130 //-----------------------------------------------------------------------------
2133 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2134 GdkEventCrossing
*gdk_event
,
2140 wxapp_install_idle_handler();
2142 if (!win
->m_hasVMT
) return FALSE
;
2143 if (g_blockEventsOnDrag
) return FALSE
;
2145 // Event was emitted after a grab
2146 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2148 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2152 GdkModifierType state
= (GdkModifierType
)0;
2154 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2156 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2157 InitMouseEvent(win
, event
, gdk_event
);
2158 wxPoint pt
= win
->GetClientAreaOrigin();
2159 event
.m_x
= x
+ pt
.x
;
2160 event
.m_y
= y
+ pt
.y
;
2162 if (win
->GetEventHandler()->ProcessEvent( event
))
2164 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2171 //-----------------------------------------------------------------------------
2172 // "leave_notify_event"
2173 //-----------------------------------------------------------------------------
2175 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2180 wxapp_install_idle_handler();
2182 if (!win
->m_hasVMT
) return FALSE
;
2183 if (g_blockEventsOnDrag
) return FALSE
;
2185 // Event was emitted after an ungrab
2186 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2188 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2190 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2191 event
.SetTimestamp( gdk_event
->time
);
2192 event
.SetEventObject( win
);
2196 GdkModifierType state
= (GdkModifierType
)0;
2198 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2200 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2201 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2202 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2203 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2204 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2205 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2206 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2208 wxPoint pt
= win
->GetClientAreaOrigin();
2209 event
.m_x
= x
+ pt
.x
;
2210 event
.m_y
= y
+ pt
.y
;
2212 if (win
->GetEventHandler()->ProcessEvent( event
))
2214 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2221 //-----------------------------------------------------------------------------
2222 // "value_changed" from m_vAdjust
2223 //-----------------------------------------------------------------------------
2225 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2232 wxapp_install_idle_handler();
2234 if (g_blockEventsOnDrag
) return;
2236 if (!win
->m_hasVMT
) return;
2238 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2239 if (fabs(diff
) < 0.2) return;
2241 win
->m_oldVerticalPos
= adjust
->value
;
2244 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2246 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2248 int value
= (int)(adjust
->value
+0.5);
2250 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2251 event
.SetEventObject( win
);
2252 win
->GetEventHandler()->ProcessEvent( event
);
2255 //-----------------------------------------------------------------------------
2256 // "value_changed" from m_hAdjust
2257 //-----------------------------------------------------------------------------
2259 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2266 wxapp_install_idle_handler();
2268 if (g_blockEventsOnDrag
) return;
2269 if (!win
->m_hasVMT
) return;
2271 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2272 if (fabs(diff
) < 0.2) return;
2275 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2277 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2279 win
->m_oldHorizontalPos
= adjust
->value
;
2281 int value
= (int)(adjust
->value
+0.5);
2283 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2284 event
.SetEventObject( win
);
2285 win
->GetEventHandler()->ProcessEvent( event
);
2288 //-----------------------------------------------------------------------------
2289 // "button_press_event" from scrollbar
2290 //-----------------------------------------------------------------------------
2292 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2293 GdkEventButton
*gdk_event
,
2299 wxapp_install_idle_handler();
2302 g_blockEventsOnScroll
= TRUE
;
2304 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2306 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2312 //-----------------------------------------------------------------------------
2313 // "button_release_event" from scrollbar
2314 //-----------------------------------------------------------------------------
2316 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2317 GdkEventButton
*WXUNUSED(gdk_event
),
2322 // don't test here as we can release the mouse while being over
2323 // a different window than the slider
2325 // if (gdk_event->window != widget->slider) return FALSE;
2327 g_blockEventsOnScroll
= FALSE
;
2329 if (win
->m_isScrolling
)
2331 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2335 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2336 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2338 value
= (int)(win
->m_hAdjust
->value
+0.5);
2341 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2343 value
= (int)(win
->m_vAdjust
->value
+0.5);
2347 wxScrollWinEvent
event( command
, value
, dir
);
2348 event
.SetEventObject( win
);
2349 win
->GetEventHandler()->ProcessEvent( event
);
2352 win
->m_isScrolling
= FALSE
;
2357 // ----------------------------------------------------------------------------
2358 // this wxWindowBase function is implemented here (in platform-specific file)
2359 // because it is static and so couldn't be made virtual
2360 // ----------------------------------------------------------------------------
2362 wxWindow
*wxWindowBase::DoFindFocus()
2364 // the cast is necessary when we compile in wxUniversal mode
2365 return (wxWindow
*)g_focusWindow
;
2369 //-----------------------------------------------------------------------------
2370 // "realize" from m_widget
2371 //-----------------------------------------------------------------------------
2373 /* We cannot set colours and fonts before the widget has
2374 been realized, so we do this directly after realization. */
2377 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2382 wxapp_install_idle_handler();
2387 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2388 gtk_im_context_set_client_window( win
->m_imData
->context
,
2389 pizza
->bin_window
);
2393 wxWindowCreateEvent
event( win
);
2394 event
.SetEventObject( win
);
2395 win
->GetEventHandler()->ProcessEvent( event
);
2400 //-----------------------------------------------------------------------------
2402 //-----------------------------------------------------------------------------
2405 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2406 GtkAllocation
*WXUNUSED(alloc
),
2410 wxapp_install_idle_handler();
2412 if (!win
->m_hasScrolling
) return;
2414 int client_width
= 0;
2415 int client_height
= 0;
2416 win
->GetClientSize( &client_width
, &client_height
);
2417 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2420 win
->m_oldClientWidth
= client_width
;
2421 win
->m_oldClientHeight
= client_height
;
2423 if (!win
->m_nativeSizeEvent
)
2425 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2426 event
.SetEventObject( win
);
2427 win
->GetEventHandler()->ProcessEvent( event
);
2433 #define WXUNUSED_UNLESS_XIM(param) param
2435 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2438 /* Resize XIM window */
2441 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2442 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2443 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2446 wxapp_install_idle_handler();
2452 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2456 gdk_window_get_size (widget
->window
, &width
, &height
);
2457 win
->m_icattr
->preedit_area
.width
= width
;
2458 win
->m_icattr
->preedit_area
.height
= height
;
2459 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2464 //-----------------------------------------------------------------------------
2465 // "realize" from m_wxwindow
2466 //-----------------------------------------------------------------------------
2468 /* Initialize XIM support */
2471 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2472 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2475 wxapp_install_idle_handler();
2478 if (win
->m_ic
) return FALSE
;
2479 if (!widget
) return FALSE
;
2480 if (!gdk_im_ready()) return FALSE
;
2482 win
->m_icattr
= gdk_ic_attr_new();
2483 if (!win
->m_icattr
) return FALSE
;
2487 GdkColormap
*colormap
;
2488 GdkICAttr
*attr
= win
->m_icattr
;
2489 unsigned attrmask
= GDK_IC_ALL_REQ
;
2491 GdkIMStyle supported_style
= (GdkIMStyle
)
2492 (GDK_IM_PREEDIT_NONE
|
2493 GDK_IM_PREEDIT_NOTHING
|
2494 GDK_IM_PREEDIT_POSITION
|
2495 GDK_IM_STATUS_NONE
|
2496 GDK_IM_STATUS_NOTHING
);
2498 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2499 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2501 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2502 attr
->client_window
= widget
->window
;
2504 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2505 gtk_widget_get_default_colormap ())
2507 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2508 attr
->preedit_colormap
= colormap
;
2511 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2512 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2513 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2514 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2516 switch (style
& GDK_IM_PREEDIT_MASK
)
2518 case GDK_IM_PREEDIT_POSITION
:
2519 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2521 g_warning ("over-the-spot style requires fontset");
2525 gdk_window_get_size (widget
->window
, &width
, &height
);
2527 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2528 attr
->spot_location
.x
= 0;
2529 attr
->spot_location
.y
= height
;
2530 attr
->preedit_area
.x
= 0;
2531 attr
->preedit_area
.y
= 0;
2532 attr
->preedit_area
.width
= width
;
2533 attr
->preedit_area
.height
= height
;
2534 attr
->preedit_fontset
= widget
->style
->font
;
2539 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2541 if (win
->m_ic
== NULL
)
2542 g_warning ("Can't create input context.");
2545 mask
= gdk_window_get_events (widget
->window
);
2546 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2547 gdk_window_set_events (widget
->window
, mask
);
2549 if (GTK_WIDGET_HAS_FOCUS(widget
))
2550 gdk_im_begin (win
->m_ic
, widget
->window
);
2557 //-----------------------------------------------------------------------------
2558 // InsertChild for wxWindowGTK.
2559 //-----------------------------------------------------------------------------
2561 /* Callback for wxWindowGTK. This very strange beast has to be used because
2562 * C++ has no virtual methods in a constructor. We have to emulate a
2563 * virtual function here as wxNotebook requires a different way to insert
2564 * a child in it. I had opted for creating a wxNotebookPage window class
2565 * which would have made this superfluous (such in the MDI window system),
2566 * but no-one was listening to me... */
2568 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2570 /* the window might have been scrolled already, do we
2571 have to adapt the position */
2572 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2573 child
->m_x
+= pizza
->xoffset
;
2574 child
->m_y
+= pizza
->yoffset
;
2576 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2577 GTK_WIDGET(child
->m_widget
),
2584 //-----------------------------------------------------------------------------
2586 //-----------------------------------------------------------------------------
2588 wxWindow
*wxGetActiveWindow()
2590 return wxWindow::FindFocus();
2593 //-----------------------------------------------------------------------------
2595 //-----------------------------------------------------------------------------
2597 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2599 #ifdef __WXUNIVERSAL__
2600 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2602 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2603 #endif // __WXUNIVERSAL__/__WXGTK__
2605 void wxWindowGTK::Init()
2608 m_widget
= (GtkWidget
*) NULL
;
2609 m_wxwindow
= (GtkWidget
*) NULL
;
2610 m_focusWidget
= (GtkWidget
*) NULL
;
2620 m_needParent
= TRUE
;
2621 m_isBeingDeleted
= FALSE
;
2624 m_nativeSizeEvent
= FALSE
;
2626 m_hasScrolling
= FALSE
;
2627 m_isScrolling
= FALSE
;
2629 m_hAdjust
= (GtkAdjustment
*) NULL
;
2630 m_vAdjust
= (GtkAdjustment
*) NULL
;
2631 m_oldHorizontalPos
=
2632 m_oldVerticalPos
= 0.0;
2634 m_oldClientHeight
= 0;
2638 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2640 m_acceptsFocus
= FALSE
;
2643 m_clipPaintRegion
= FALSE
;
2645 m_needsStyleChange
= false;
2647 m_cursor
= *wxSTANDARD_CURSOR
;
2651 m_x11Context
= NULL
;
2652 m_dirtyTabOrder
= false;
2655 m_ic
= (GdkIC
*) NULL
;
2656 m_icattr
= (GdkICAttr
*) NULL
;
2661 wxWindowGTK::wxWindowGTK()
2666 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2671 const wxString
&name
)
2675 Create( parent
, id
, pos
, size
, style
, name
);
2678 bool wxWindowGTK::Create( wxWindow
*parent
,
2683 const wxString
&name
)
2685 if (!PreCreation( parent
, pos
, size
) ||
2686 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2688 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2692 m_insertCallback
= wxInsertChildInWindow
;
2694 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2695 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2697 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2699 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2700 scroll_class
->scrollbar_spacing
= 0;
2702 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2704 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2705 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2707 m_wxwindow
= gtk_pizza_new();
2709 #ifndef __WXUNIVERSAL__
2710 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2712 if (HasFlag(wxRAISED_BORDER
))
2714 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2716 else if (HasFlag(wxSUNKEN_BORDER
))
2718 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2720 else if (HasFlag(wxSIMPLE_BORDER
))
2722 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2726 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2728 #endif // __WXUNIVERSAL__
2730 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2732 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2733 m_acceptsFocus
= TRUE
;
2735 // I _really_ don't want scrollbars in the beginning
2736 m_vAdjust
->lower
= 0.0;
2737 m_vAdjust
->upper
= 1.0;
2738 m_vAdjust
->value
= 0.0;
2739 m_vAdjust
->step_increment
= 1.0;
2740 m_vAdjust
->page_increment
= 1.0;
2741 m_vAdjust
->page_size
= 5.0;
2742 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2743 m_hAdjust
->lower
= 0.0;
2744 m_hAdjust
->upper
= 1.0;
2745 m_hAdjust
->value
= 0.0;
2746 m_hAdjust
->step_increment
= 1.0;
2747 m_hAdjust
->page_increment
= 1.0;
2748 m_hAdjust
->page_size
= 5.0;
2749 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2751 // these handlers block mouse events to any window during scrolling such as
2752 // motion events and prevent GTK and wxWidgets from fighting over where the
2755 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2756 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2758 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2759 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2761 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2762 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2764 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2765 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2767 // these handlers get notified when screen updates are required either when
2768 // scrolling or when the window size (and therefore scrollbar configuration)
2771 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2772 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2773 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2774 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2776 gtk_widget_show( m_wxwindow
);
2779 m_parent
->DoAddChild( this );
2781 m_focusWidget
= m_wxwindow
;
2788 wxWindowGTK::~wxWindowGTK()
2792 if (g_focusWindow
== this)
2793 g_focusWindow
= NULL
;
2795 if (g_activeFrame
== this)
2796 g_activeFrame
= NULL
;
2798 if ( g_delayedFocus
== this )
2799 g_delayedFocus
= NULL
;
2801 m_isBeingDeleted
= TRUE
;
2811 gdk_ic_destroy (m_ic
);
2813 gdk_ic_attr_destroy (m_icattr
);
2818 gtk_widget_destroy( m_wxwindow
);
2819 m_wxwindow
= (GtkWidget
*) NULL
;
2824 gtk_widget_destroy( m_widget
);
2825 m_widget
= (GtkWidget
*) NULL
;
2833 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2835 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2837 // Use either the given size, or the default if -1 is given.
2838 // See wxWindowBase for these functions.
2839 m_width
= WidthDefault(size
.x
) ;
2840 m_height
= HeightDefault(size
.y
);
2848 void wxWindowGTK::PostCreation()
2850 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2856 // these get reported to wxWidgets -> wxPaintEvent
2858 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2860 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2861 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2864 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2865 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2867 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2869 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2870 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2873 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2878 // Create input method handler
2879 m_imData
= new wxGtkIMData
;
2881 // Cannot handle drawing preedited text yet
2882 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2884 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2885 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2888 // these are called when the "sunken" or "raised" borders are drawn
2889 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2890 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2893 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2894 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2900 if (m_focusWidget
== NULL
)
2901 m_focusWidget
= m_widget
;
2903 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2904 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2906 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2907 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2909 // connect to the various key and mouse handlers
2911 GtkWidget
*connect_widget
= GetConnectWidget();
2913 ConnectWidget( connect_widget
);
2915 /* We cannot set colours, fonts and cursors before the widget has
2916 been realized, so we do this directly after realization */
2917 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2918 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2922 // Catch native resize events
2923 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2924 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2926 // Initialize XIM support
2927 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2928 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2930 // And resize XIM window
2931 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2932 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2935 if ( !GTK_IS_COMBO(m_widget
))
2937 // This is needed if we want to add our windows into native
2938 // GTK control, such as the toolbar. With this callback, the
2939 // toolbar gets to know the correct size (the one set by the
2940 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2941 // when moving to GTK 2.0.
2942 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2943 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2947 InheritAttributes();
2951 // unless the window was created initially hidden (i.e. Hide() had been
2952 // called before Create()), we should show it at GTK+ level as well
2954 gtk_widget_show( m_widget
);
2957 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2959 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2960 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2962 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2963 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2965 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2966 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2968 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2969 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2971 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2972 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2975 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2976 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2979 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2980 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2982 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2983 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2986 bool wxWindowGTK::Destroy()
2988 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2992 return wxWindowBase::Destroy();
2995 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2997 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
3000 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
3002 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3003 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
3006 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
3009 if (m_resizing
) return; /* I don't like recursions */
3012 int currentX
, currentY
;
3013 GetPosition(¤tX
, ¤tY
);
3014 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3016 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3018 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
3020 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
3022 /* don't set the size for children of wxNotebook, just take the values. */
3030 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3031 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
3033 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
3034 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
3038 m_x
= x
+ pizza
->xoffset
;
3039 m_y
= y
+ pizza
->yoffset
;
3042 // calculate the best size if we should auto size the window
3043 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
3044 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
3046 const wxSize sizeBest
= GetBestSize();
3047 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
3049 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
3050 height
= sizeBest
.y
;
3058 int minWidth
= GetMinWidth(),
3059 minHeight
= GetMinHeight(),
3060 maxWidth
= GetMaxWidth(),
3061 maxHeight
= GetMaxHeight();
3063 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3064 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3065 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3066 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3069 int bottom_border
= 0;
3072 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3074 /* the default button has a border around it */
3080 DoMoveWindow( m_x
-border
,
3083 m_height
+border
+bottom_border
);
3088 /* Sometimes the client area changes size without the
3089 whole windows's size changing, but if the whole
3090 windows's size doesn't change, no wxSizeEvent will
3091 normally be sent. Here we add an extra test if
3092 the client test has been changed and this will
3094 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3098 wxPrintf( "OnSize sent from " );
3099 if (GetClassInfo() && GetClassInfo()->GetClassName())
3100 wxPrintf( GetClassInfo()->GetClassName() );
3101 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3104 if (!m_nativeSizeEvent
)
3106 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3107 event
.SetEventObject( this );
3108 GetEventHandler()->ProcessEvent( event
);
3114 void wxWindowGTK::OnInternalIdle()
3117 if ( m_dirtyTabOrder
)
3120 // Update style if the window was not yet realized
3121 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3122 if (m_needsStyleChange
)
3124 SetBackgroundStyle(GetBackgroundStyle());
3125 m_needsStyleChange
= false;
3128 // Update invalidated regions.
3131 // Synthetize activate events.
3132 if ( g_sendActivateEvent
!= -1 )
3134 bool activate
= g_sendActivateEvent
!= 0;
3137 g_sendActivateEvent
= -1;
3139 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
3142 if ( g_activeFrameLostFocus
)
3144 if ( g_activeFrame
)
3146 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3147 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3148 event
.SetEventObject(g_activeFrame
);
3149 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3150 g_activeFrame
= NULL
;
3152 g_activeFrameLostFocus
= FALSE
;
3155 wxCursor cursor
= m_cursor
;
3156 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3160 /* I now set the cursor anew in every OnInternalIdle call
3161 as setting the cursor in a parent window also effects the
3162 windows above so that checking for the current cursor is
3167 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3169 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3171 if (!g_globalCursor
.Ok())
3172 cursor
= *wxSTANDARD_CURSOR
;
3174 window
= m_widget
->window
;
3175 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3176 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3182 GdkWindow
*window
= m_widget
->window
;
3183 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3184 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3189 if (wxUpdateUIEvent::CanUpdate(this))
3190 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3193 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3195 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3197 if (width
) (*width
) = m_width
;
3198 if (height
) (*height
) = m_height
;
3201 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3203 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3207 SetSize( width
, height
);
3214 #ifndef __WXUNIVERSAL__
3215 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3217 /* when using GTK 1.2 we set the shadow border size to 2 */
3221 if (HasFlag(wxSIMPLE_BORDER
))
3223 /* when using GTK 1.2 we set the simple border size to 1 */
3227 #endif // __WXUNIVERSAL__
3231 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3233 GtkRequisition vscroll_req
;
3234 vscroll_req
.width
= 2;
3235 vscroll_req
.height
= 2;
3236 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3237 (scroll_window
->vscrollbar
, &vscroll_req
);
3239 GtkRequisition hscroll_req
;
3240 hscroll_req
.width
= 2;
3241 hscroll_req
.height
= 2;
3242 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3243 (scroll_window
->hscrollbar
, &hscroll_req
);
3245 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3247 if (scroll_window
->vscrollbar_visible
)
3249 dw
+= vscroll_req
.width
;
3250 dw
+= scroll_class
->scrollbar_spacing
;
3253 if (scroll_window
->hscrollbar_visible
)
3255 dh
+= hscroll_req
.height
;
3256 dh
+= scroll_class
->scrollbar_spacing
;
3260 SetSize( width
+dw
, height
+dh
);
3264 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3266 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3270 if (width
) (*width
) = m_width
;
3271 if (height
) (*height
) = m_height
;
3278 #ifndef __WXUNIVERSAL__
3279 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3281 /* when using GTK 1.2 we set the shadow border size to 2 */
3285 if (HasFlag(wxSIMPLE_BORDER
))
3287 /* when using GTK 1.2 we set the simple border size to 1 */
3291 #endif // __WXUNIVERSAL__
3295 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3297 GtkRequisition vscroll_req
;
3298 vscroll_req
.width
= 2;
3299 vscroll_req
.height
= 2;
3300 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3301 (scroll_window
->vscrollbar
, &vscroll_req
);
3303 GtkRequisition hscroll_req
;
3304 hscroll_req
.width
= 2;
3305 hscroll_req
.height
= 2;
3306 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3307 (scroll_window
->hscrollbar
, &hscroll_req
);
3309 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3311 if (scroll_window
->vscrollbar_visible
)
3313 dw
+= vscroll_req
.width
;
3314 dw
+= scroll_class
->scrollbar_spacing
;
3317 if (scroll_window
->hscrollbar_visible
)
3319 dh
+= hscroll_req
.height
;
3320 dh
+= scroll_class
->scrollbar_spacing
;
3324 if (width
) (*width
) = m_width
- dw
;
3325 if (height
) (*height
) = m_height
- dh
;
3329 printf( "GetClientSize, name %s ", GetName().c_str() );
3330 if (width) printf( " width = %d", (*width) );
3331 if (height) printf( " height = %d", (*height) );
3336 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3338 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3342 if (m_parent
&& m_parent
->m_wxwindow
)
3344 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3345 dx
= pizza
->xoffset
;
3346 dy
= pizza
->yoffset
;
3349 if (x
) (*x
) = m_x
- dx
;
3350 if (y
) (*y
) = m_y
- dy
;
3353 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3355 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3357 if (!m_widget
->window
) return;
3359 GdkWindow
*source
= (GdkWindow
*) NULL
;
3361 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3363 source
= m_widget
->window
;
3367 gdk_window_get_origin( source
, &org_x
, &org_y
);
3371 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3373 org_x
+= m_widget
->allocation
.x
;
3374 org_y
+= m_widget
->allocation
.y
;
3382 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3384 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3386 if (!m_widget
->window
) return;
3388 GdkWindow
*source
= (GdkWindow
*) NULL
;
3390 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3392 source
= m_widget
->window
;
3396 gdk_window_get_origin( source
, &org_x
, &org_y
);
3400 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3402 org_x
+= m_widget
->allocation
.x
;
3403 org_y
+= m_widget
->allocation
.y
;
3411 bool wxWindowGTK::Show( bool show
)
3413 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3415 if (!wxWindowBase::Show(show
))
3422 gtk_widget_show( m_widget
);
3424 gtk_widget_hide( m_widget
);
3426 wxShowEvent
eventShow(GetId(), show
);
3427 eventShow
.m_eventObject
= this;
3429 GetEventHandler()->ProcessEvent(eventShow
);
3434 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3436 win
->OnParentEnable(enable
);
3438 // Recurse, so that children have the opportunity to Do The Right Thing
3439 // and reset colours that have been messed up by a parent's (really ancestor's)
3441 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3443 node
= node
->GetNext() )
3445 wxWindow
*child
= node
->GetData();
3446 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3447 wxWindowNotifyEnable(child
, enable
);
3451 bool wxWindowGTK::Enable( bool enable
)
3453 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3455 if (!wxWindowBase::Enable(enable
))
3461 gtk_widget_set_sensitive( m_widget
, enable
);
3463 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3465 wxWindowNotifyEnable(this, enable
);
3470 int wxWindowGTK::GetCharHeight() const
3472 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3474 wxFont font
= GetFont();
3475 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3478 PangoContext
*context
= NULL
;
3480 context
= gtk_widget_get_pango_context( m_widget
);
3485 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3486 PangoLayout
*layout
= pango_layout_new(context
);
3487 pango_layout_set_font_description(layout
, desc
);
3488 pango_layout_set_text(layout
, "H", 1);
3489 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3491 PangoRectangle rect
;
3492 pango_layout_line_get_extents(line
, NULL
, &rect
);
3494 g_object_unref( G_OBJECT( layout
) );
3496 return (int) PANGO_PIXELS(rect
.height
);
3498 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3500 return gfont
->ascent
+ gfont
->descent
;
3504 int wxWindowGTK::GetCharWidth() const
3506 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3508 wxFont font
= GetFont();
3509 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3512 PangoContext
*context
= NULL
;
3514 context
= gtk_widget_get_pango_context( m_widget
);
3519 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3520 PangoLayout
*layout
= pango_layout_new(context
);
3521 pango_layout_set_font_description(layout
, desc
);
3522 pango_layout_set_text(layout
, "g", 1);
3523 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3525 PangoRectangle rect
;
3526 pango_layout_line_get_extents(line
, NULL
, &rect
);
3528 g_object_unref( G_OBJECT( layout
) );
3530 return (int) PANGO_PIXELS(rect
.width
);
3532 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3534 return gdk_string_width( gfont
, "g" );
3538 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3542 int *externalLeading
,
3543 const wxFont
*theFont
) const
3545 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3547 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3549 if (string
.IsEmpty())
3557 PangoContext
*context
= NULL
;
3559 context
= gtk_widget_get_pango_context( m_widget
);
3568 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3569 PangoLayout
*layout
= pango_layout_new(context
);
3570 pango_layout_set_font_description(layout
, desc
);
3573 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3574 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3576 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3577 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3578 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3582 PangoRectangle rect
;
3583 pango_layout_get_extents(layout
, NULL
, &rect
);
3585 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3586 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3589 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3590 int baseline
= pango_layout_iter_get_baseline(iter
);
3591 pango_layout_iter_free(iter
);
3592 *descent
= *y
- PANGO_PIXELS(baseline
);
3594 if (externalLeading
) (*externalLeading
) = 0; // ??
3596 g_object_unref( G_OBJECT( layout
) );
3598 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3599 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3600 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3601 if (descent
) (*descent
) = font
->descent
;
3602 if (externalLeading
) (*externalLeading
) = 0; // ??
3606 void wxWindowGTK::SetFocus()
3608 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3611 // don't do anything if we already have focus
3617 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3619 gtk_widget_grab_focus (m_wxwindow
);
3625 if (GTK_IS_CONTAINER(m_widget
))
3627 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3631 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3634 if (!GTK_WIDGET_REALIZED(m_widget
))
3636 // we can't set the focus to the widget now so we remember that
3637 // it should be focused and will do it later, during the idle
3638 // time, as soon as we can
3639 wxLogTrace(TRACE_FOCUS
,
3640 _T("Delaying setting focus to %s(%s)"),
3641 GetClassInfo()->GetClassName(), GetLabel().c_str());
3643 g_delayedFocus
= this;
3647 wxLogTrace(TRACE_FOCUS
,
3648 _T("Setting focus to %s(%s)"),
3649 GetClassInfo()->GetClassName(), GetLabel().c_str());
3651 gtk_widget_grab_focus (m_widget
);
3656 if (GTK_IS_CONTAINER(m_widget
))
3658 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3663 wxLogTrace(TRACE_FOCUS
,
3664 _T("Can't set focus to %s(%s)"),
3665 GetClassInfo()->GetClassName(), GetLabel().c_str());
3670 bool wxWindowGTK::AcceptsFocus() const
3672 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3675 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3677 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3679 wxWindowGTK
*oldParent
= m_parent
,
3680 *newParent
= (wxWindowGTK
*)newParentBase
;
3682 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3684 if ( !wxWindowBase::Reparent(newParent
) )
3687 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3689 /* prevent GTK from deleting the widget arbitrarily */
3690 gtk_widget_ref( m_widget
);
3694 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3697 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3701 /* insert GTK representation */
3702 (*(newParent
->m_insertCallback
))(newParent
, this);
3705 /* reverse: prevent GTK from deleting the widget arbitrarily */
3706 gtk_widget_unref( m_widget
);
3711 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3713 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3715 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3717 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3722 /* insert GTK representation */
3723 (*m_insertCallback
)(this, child
);
3728 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3730 wxWindowBase::AddChild(child
);
3731 m_dirtyTabOrder
= true;
3733 wxapp_install_idle_handler();
3736 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3738 wxWindowBase::RemoveChild(child
);
3739 m_dirtyTabOrder
= true;
3741 wxapp_install_idle_handler();
3744 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3746 wxWindowBase::DoMoveInTabOrder(win
, move
);
3747 m_dirtyTabOrder
= true;
3749 wxapp_install_idle_handler();
3752 void wxWindowGTK::RealizeTabOrder()
3756 if (m_children
.size() > 0)
3758 GList
*chain
= NULL
;
3760 for (wxWindowList::const_iterator i
= m_children
.begin();
3761 i
!= m_children
.end(); ++i
)
3763 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3766 chain
= g_list_reverse(chain
);
3768 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3773 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3777 m_dirtyTabOrder
= false;
3780 #endif // __WXGTK20__
3782 void wxWindowGTK::Raise()
3784 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3786 if (!m_widget
->window
) return;
3788 gdk_window_raise( m_widget
->window
);
3791 void wxWindowGTK::Lower()
3793 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3795 if (!m_widget
->window
) return;
3797 gdk_window_lower( m_widget
->window
);
3800 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3802 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3804 if (cursor
== m_cursor
)
3808 wxapp_install_idle_handler();
3810 if (cursor
== wxNullCursor
)
3811 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3813 return wxWindowBase::SetCursor( cursor
);
3816 void wxWindowGTK::WarpPointer( int x
, int y
)
3818 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3820 // We provide this function ourselves as it is
3821 // missing in GDK (top of this file).
3823 GdkWindow
*window
= (GdkWindow
*) NULL
;
3825 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3827 window
= GetConnectWidget()->window
;
3830 gdk_window_warp_pointer( window
, x
, y
);
3834 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3836 if (!m_widget
) return;
3837 if (!m_widget
->window
) return;
3841 wxapp_install_idle_handler();
3843 wxRect
myRect(0,0,0,0);
3844 if (m_wxwindow
&& rect
)
3846 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3847 m_wxwindow
->allocation
.height
));
3848 myRect
.Intersect(*rect
);
3849 if (!myRect
.width
|| !myRect
.height
)
3850 // nothing to do, rectangle is empty
3855 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3859 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3860 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3864 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3865 m_clearRegion
.Clear();
3866 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3874 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3875 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3879 GdkRectangle gdk_rect
;
3880 gdk_rect
.x
= rect
->x
;
3881 gdk_rect
.y
= rect
->y
;
3882 gdk_rect
.width
= rect
->width
;
3883 gdk_rect
.height
= rect
->height
;
3884 gtk_widget_draw( m_widget
, &gdk_rect
);
3891 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3892 m_updateRegion
.Clear();
3893 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3897 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3905 GdkRectangle gdk_rect
;
3906 gdk_rect
.x
= rect
->x
;
3907 gdk_rect
.y
= rect
->y
;
3908 gdk_rect
.width
= rect
->width
;
3909 gdk_rect
.height
= rect
->height
;
3910 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3914 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3920 void wxWindowGTK::Update()
3925 void wxWindowGTK::GtkUpdate()
3928 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3929 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3931 if (!m_updateRegion
.IsEmpty())
3932 GtkSendPaintEvents();
3936 void wxWindowGTK::GtkSendPaintEvents()
3941 m_clearRegion
.Clear();
3943 m_updateRegion
.Clear();
3947 // Clip to paint region in wxClientDC
3948 m_clipPaintRegion
= TRUE
;
3950 // widget to draw on
3951 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3953 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
3955 // find ancestor from which to steal background
3956 wxWindow
*parent
= GetParent();
3957 while (parent
&& !parent
->IsTopLevel())
3958 parent
= parent
->GetParent();
3960 parent
= (wxWindow
*)this;
3962 wxRegionIterator
upd( m_updateRegion
);
3966 rect
.x
= upd
.GetX();
3967 rect
.y
= upd
.GetY();
3968 rect
.width
= upd
.GetWidth();
3969 rect
.height
= upd
.GetHeight();
3971 gtk_paint_flat_box( parent
->m_widget
->style
,
3973 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3987 wxWindowDC
dc( (wxWindow
*)this );
3988 dc
.SetClippingRegion( m_updateRegion
);
3990 wxEraseEvent
erase_event( GetId(), &dc
);
3991 erase_event
.SetEventObject( this );
3993 GetEventHandler()->ProcessEvent(erase_event
);
3996 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3998 wxWindowDC
dc( (wxWindow
*)this );
3999 if (m_clearRegion
.IsEmpty())
4000 dc
.SetClippingRegion( m_updateRegion
);
4002 dc
.SetClippingRegion( m_clearRegion
);
4004 wxEraseEvent
erase_event( GetId(), &dc
);
4005 erase_event
.SetEventObject( this );
4007 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4011 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
4012 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4014 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
4016 wxRegionIterator
upd( m_clearRegion
);
4019 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
4020 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
4024 m_clearRegion
.Clear();
4028 wxNcPaintEvent
nc_paint_event( GetId() );
4029 nc_paint_event
.SetEventObject( this );
4030 GetEventHandler()->ProcessEvent( nc_paint_event
);
4032 wxPaintEvent
paint_event( GetId() );
4033 paint_event
.SetEventObject( this );
4034 GetEventHandler()->ProcessEvent( paint_event
);
4036 m_clipPaintRegion
= FALSE
;
4038 #ifndef __WXUNIVERSAL__
4040 // The following code will result in all window-less widgets
4041 // being redrawn because the wxWidgets class is allowed to
4042 // paint over the window-less widgets.
4044 GList
*children
= pizza
->children
;
4047 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
4048 children
= children
->next
;
4050 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
4051 GTK_WIDGET_DRAWABLE (child
->widget
))
4053 // Get intersection of widget area and update region
4054 wxRegion
region( m_updateRegion
);
4056 GdkEventExpose gdk_event
;
4057 gdk_event
.type
= GDK_EXPOSE
;
4058 gdk_event
.window
= pizza
->bin_window
;
4059 gdk_event
.count
= 0;
4061 wxRegionIterator
upd( m_updateRegion
);
4065 rect
.x
= upd
.GetX();
4066 rect
.y
= upd
.GetY();
4067 rect
.width
= upd
.GetWidth();
4068 rect
.height
= upd
.GetHeight();
4070 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
4072 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
4082 m_updateRegion
.Clear();
4085 void wxWindowGTK::ClearBackground()
4087 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4090 if (m_wxwindow
&& m_wxwindow
->window
)
4092 m_clearRegion
.Clear();
4093 wxSize
size( GetClientSize() );
4094 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4096 // Better do this in idle?
4103 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4105 wxWindowBase::DoSetToolTip(tip
);
4108 m_tooltip
->Apply( (wxWindow
*)this );
4111 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4113 wxString
tmp( tip
);
4114 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4116 #endif // wxUSE_TOOLTIPS
4118 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4120 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4122 if (!wxWindowBase::SetBackgroundColour(colour
))
4127 // We need the pixel value e.g. for background clearing.
4128 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4131 // apply style change (forceStyle=true so that new style is applied
4132 // even if the bg colour changed from valid to wxNullColour)
4133 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4134 ApplyWidgetStyle(true);
4139 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4141 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4143 if (!wxWindowBase::SetForegroundColour(colour
))
4150 // We need the pixel value e.g. for background clearing.
4151 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4154 // apply style change (forceStyle=true so that new style is applied
4155 // even if the bg colour changed from valid to wxNullColour):
4156 ApplyWidgetStyle(true);
4162 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4164 return gtk_widget_get_pango_context( m_widget
);
4167 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4170 m_x11Context
= pango_x_get_context( gdk_display
);
4172 return m_x11Context
;
4176 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4178 // do we need to apply any changes at all?
4181 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4186 GtkRcStyle
*style
= gtk_rc_style_new();
4192 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4194 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4195 style
->fontset_name
= g_strdup(xfontname
.c_str());
4199 if ( m_foregroundColour
.Ok() )
4201 GdkColor
*fg
= m_foregroundColour
.GetColor();
4203 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4204 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4206 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4207 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4209 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4210 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4213 if ( m_backgroundColour
.Ok() )
4215 GdkColor
*bg
= m_backgroundColour
.GetColor();
4217 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4218 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4219 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4220 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4222 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4223 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4224 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4225 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4227 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4228 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4229 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4230 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4232 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4233 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4234 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4235 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4241 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4243 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4246 DoApplyWidgetStyle(style
);
4247 gtk_rc_style_unref(style
);
4250 // Style change may affect GTK+'s size calculation:
4251 InvalidateBestSize();
4254 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4257 gtk_widget_modify_style(m_wxwindow
, style
);
4258 gtk_widget_modify_style(m_widget
, style
);
4261 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4263 wxWindowBase::SetBackgroundStyle(style
);
4265 if (style
== wxBG_STYLE_CUSTOM
)
4267 GdkWindow
*window
= (GdkWindow
*) NULL
;
4269 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4271 window
= GetConnectWidget()->window
;
4275 // Make sure GDK/X11 doesn't refresh the window
4277 gdk_window_set_back_pixmap( window
, None
, False
);
4279 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4282 m_needsStyleChange
= false;
4285 // Do in OnIdle, because the window is not yet available
4286 m_needsStyleChange
= true;
4288 // Don't apply widget style, or we get a grey background
4292 // apply style change (forceStyle=true so that new style is applied
4293 // even if the bg colour changed from valid to wxNullColour):
4294 ApplyWidgetStyle(true);
4299 //-----------------------------------------------------------------------------
4300 // Pop-up menu stuff
4301 //-----------------------------------------------------------------------------
4303 #if wxUSE_MENUS_NATIVE
4306 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4308 *is_waiting
= FALSE
;
4311 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4313 menu
->SetInvokingWindow( win
);
4314 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4317 wxMenuItem
*menuitem
= node
->GetData();
4318 if (menuitem
->IsSubMenu())
4320 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4323 node
= node
->GetNext();
4327 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4330 gboolean
* WXUNUSED(whatever
),
4332 gpointer user_data
)
4334 // ensure that the menu appears entirely on screen
4336 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4338 wxSize sizeScreen
= wxGetDisplaySize();
4339 wxPoint
*pos
= (wxPoint
*)user_data
;
4341 gint xmax
= sizeScreen
.x
- req
.width
,
4342 ymax
= sizeScreen
.y
- req
.height
;
4344 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4345 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4348 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4350 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4352 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4354 SetInvokingWindow( menu
, this );
4358 bool is_waiting
= true;
4360 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4362 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4363 (gpointer
)&is_waiting
);
4367 GtkMenuPositionFunc posfunc
;
4368 if ( x
== -1 && y
== -1 )
4370 // use GTK's default positioning algorithm
4376 pos
= ClientToScreen(wxPoint(x
, y
));
4378 posfunc
= wxPopupMenuPositionCallback
;
4382 GTK_MENU(menu
->m_menu
),
4383 (GtkWidget
*) NULL
, // parent menu shell
4384 (GtkWidget
*) NULL
, // parent menu item
4385 posfunc
, // function to position it
4386 userdata
, // client data
4387 0, // button used to activate it
4389 gtk_get_current_event_time()
4391 gs_timeLastClick
// the time of activation
4397 gtk_main_iteration();
4400 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4405 #endif // wxUSE_MENUS_NATIVE
4407 #if wxUSE_DRAG_AND_DROP
4409 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4411 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4413 GtkWidget
*dnd_widget
= GetConnectWidget();
4415 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4417 if (m_dropTarget
) delete m_dropTarget
;
4418 m_dropTarget
= dropTarget
;
4420 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4423 #endif // wxUSE_DRAG_AND_DROP
4425 GtkWidget
* wxWindowGTK::GetConnectWidget()
4427 GtkWidget
*connect_widget
= m_widget
;
4428 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4430 return connect_widget
;
4433 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4436 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4438 return (window
== m_widget
->window
);
4441 bool wxWindowGTK::SetFont( const wxFont
&font
)
4443 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4445 if (!wxWindowBase::SetFont(font
))
4448 // apply style change (forceStyle=true so that new style is applied
4449 // even if the font changed from valid to wxNullFont):
4450 ApplyWidgetStyle(true);
4455 void wxWindowGTK::DoCaptureMouse()
4457 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4459 GdkWindow
*window
= (GdkWindow
*) NULL
;
4461 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4463 window
= GetConnectWidget()->window
;
4465 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4467 wxCursor
* cursor
= & m_cursor
;
4469 cursor
= wxSTANDARD_CURSOR
;
4471 gdk_pointer_grab( window
, FALSE
,
4473 (GDK_BUTTON_PRESS_MASK
|
4474 GDK_BUTTON_RELEASE_MASK
|
4475 GDK_POINTER_MOTION_HINT_MASK
|
4476 GDK_POINTER_MOTION_MASK
),
4478 cursor
->GetCursor(),
4479 (guint32
)GDK_CURRENT_TIME
);
4480 g_captureWindow
= this;
4481 g_captureWindowHasMouse
= TRUE
;
4484 void wxWindowGTK::DoReleaseMouse()
4486 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4488 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4490 g_captureWindow
= (wxWindowGTK
*) NULL
;
4492 GdkWindow
*window
= (GdkWindow
*) NULL
;
4494 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4496 window
= GetConnectWidget()->window
;
4501 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4505 wxWindow
*wxWindowBase::GetCapture()
4507 return (wxWindow
*)g_captureWindow
;
4510 bool wxWindowGTK::IsRetained() const
4515 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4516 int range
, bool refresh
)
4518 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4520 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4522 m_hasScrolling
= TRUE
;
4524 if (orient
== wxHORIZONTAL
)
4526 float fpos
= (float)pos
;
4527 float frange
= (float)range
;
4528 float fthumb
= (float)thumbVisible
;
4529 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4530 if (fpos
< 0.0) fpos
= 0.0;
4532 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4533 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4535 SetScrollPos( orient
, pos
, refresh
);
4539 m_oldHorizontalPos
= fpos
;
4541 m_hAdjust
->lower
= 0.0;
4542 m_hAdjust
->upper
= frange
;
4543 m_hAdjust
->value
= fpos
;
4544 m_hAdjust
->step_increment
= 1.0;
4545 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4546 m_hAdjust
->page_size
= fthumb
;
4550 float fpos
= (float)pos
;
4551 float frange
= (float)range
;
4552 float fthumb
= (float)thumbVisible
;
4553 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4554 if (fpos
< 0.0) fpos
= 0.0;
4556 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4557 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4559 SetScrollPos( orient
, pos
, refresh
);
4563 m_oldVerticalPos
= fpos
;
4565 m_vAdjust
->lower
= 0.0;
4566 m_vAdjust
->upper
= frange
;
4567 m_vAdjust
->value
= fpos
;
4568 m_vAdjust
->step_increment
= 1.0;
4569 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4570 m_vAdjust
->page_size
= fthumb
;
4573 if (orient
== wxHORIZONTAL
)
4574 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4576 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4579 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4581 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4583 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4585 if (orient
== wxHORIZONTAL
)
4587 float fpos
= (float)pos
;
4588 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4589 if (fpos
< 0.0) fpos
= 0.0;
4590 m_oldHorizontalPos
= fpos
;
4592 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4593 m_hAdjust
->value
= fpos
;
4597 float fpos
= (float)pos
;
4598 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4599 if (fpos
< 0.0) fpos
= 0.0;
4600 m_oldVerticalPos
= fpos
;
4602 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4603 m_vAdjust
->value
= fpos
;
4606 if (m_wxwindow
->window
)
4608 if (orient
== wxHORIZONTAL
)
4610 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4611 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4613 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4615 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4616 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4620 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4621 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4623 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4625 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4626 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4631 int wxWindowGTK::GetScrollThumb( int orient
) const
4633 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4635 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4637 if (orient
== wxHORIZONTAL
)
4638 return (int)(m_hAdjust
->page_size
+0.5);
4640 return (int)(m_vAdjust
->page_size
+0.5);
4643 int wxWindowGTK::GetScrollPos( int orient
) const
4645 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4647 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4649 if (orient
== wxHORIZONTAL
)
4650 return (int)(m_hAdjust
->value
+0.5);
4652 return (int)(m_vAdjust
->value
+0.5);
4655 int wxWindowGTK::GetScrollRange( int orient
) const
4657 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4659 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4661 if (orient
== wxHORIZONTAL
)
4662 return (int)(m_hAdjust
->upper
+0.5);
4664 return (int)(m_vAdjust
->upper
+0.5);
4667 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4669 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4671 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4673 // No scrolling requested.
4674 if ((dx
== 0) && (dy
== 0)) return;
4677 if (!m_updateRegion
.IsEmpty())
4679 m_updateRegion
.Offset( dx
, dy
);
4683 GetClientSize( &cw
, &ch
);
4684 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4687 if (!m_clearRegion
.IsEmpty())
4689 m_clearRegion
.Offset( dx
, dy
);
4693 GetClientSize( &cw
, &ch
);
4694 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4698 m_clipPaintRegion
= TRUE
;
4700 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4702 m_clipPaintRegion
= FALSE
;
4706 // Find the wxWindow at the current mouse position, also returning the mouse
4708 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4710 pt
= wxGetMousePosition();
4711 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4715 // Get the current mouse position.
4716 wxPoint
wxGetMousePosition()
4718 /* This crashes when used within wxHelpContext,
4719 so we have to use the X-specific implementation below.
4721 GdkModifierType *mask;
4722 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4724 return wxPoint(x, y);
4728 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4730 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4731 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4732 Window rootReturn
, childReturn
;
4733 int rootX
, rootY
, winX
, winY
;
4734 unsigned int maskReturn
;
4736 XQueryPointer (display
,
4740 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4741 return wxPoint(rootX
, rootY
);
4745 // ----------------------------------------------------------------------------
4747 // ----------------------------------------------------------------------------
4749 class wxWinModule
: public wxModule
4756 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4759 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4761 bool wxWinModule::OnInit()
4763 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4764 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4769 void wxWinModule::OnExit()
4772 gdk_gc_unref( g_eraseGC
);