1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
19 #define XWarpPointer XWARPPOINTER
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
26 #include "wx/layout.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
32 #if wxUSE_DRAG_AND_DROP
37 #include "wx/tooltip.h"
45 #include "wx/textctrl.h"
49 #include "wx/statusbr.h"
51 #include "wx/settings.h"
53 #include "wx/fontutil.h"
56 #include "wx/thread.h"
62 #include "wx/gtk/private.h"
63 #include <gdk/gdkprivate.h>
64 #include <gdk/gdkkeysyms.h>
68 #include <gtk/gtkprivate.h>
70 #include "wx/gtk/win_gtk.h"
73 #include <pango/pangox.h>
77 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
79 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
89 extern GtkContainerClass
*pizza_parent_class
;
92 //-----------------------------------------------------------------------------
93 // documentation on internals
94 //-----------------------------------------------------------------------------
97 I have been asked several times about writing some documentation about
98 the GTK port of wxWidgets, especially its internal structures. Obviously,
99 you cannot understand wxGTK without knowing a little about the GTK, but
100 some more information about what the wxWindow, which is the base class
101 for all other window classes, does seems required as well.
105 What does wxWindow do? It contains the common interface for the following
106 jobs of its descendants:
108 1) Define the rudimentary behaviour common to all window classes, such as
109 resizing, intercepting user input (so as to make it possible to use these
110 events for special purposes in a derived class), window names etc.
112 2) Provide the possibility to contain and manage children, if the derived
113 class is allowed to contain children, which holds true for those window
114 classes which do not display a native GTK widget. To name them, these
115 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
116 work classes are a special case and are handled a bit differently from
117 the rest. The same holds true for the wxNotebook class.
119 3) Provide the possibility to draw into a client area of a window. This,
120 too, only holds true for classes that do not display a native GTK widget
123 4) Provide the entire mechanism for scrolling widgets. This actual inter-
124 face for this is usually in wxScrolledWindow, but the GTK implementation
127 5) A multitude of helper or extra methods for special purposes, such as
128 Drag'n'Drop, managing validators etc.
130 6) Display a border (sunken, raised, simple or none).
132 Normally one might expect, that one wxWidgets window would always correspond
133 to one GTK widget. Under GTK, there is no such allround widget that has all
134 the functionality. Moreover, the GTK defines a client area as a different
135 widget from the actual widget you are handling. Last but not least some
136 special classes (e.g. wxFrame) handle different categories of widgets and
137 still have the possibility to draw something in the client area.
138 It was therefore required to write a special purpose GTK widget, that would
139 represent a client area in the sense of wxWidgets capable to do the jobs
140 2), 3) and 4). I have written this class and it resides in win_gtk.c of
143 All windows must have a widget, with which they interact with other under-
144 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
145 thw wxWindow class has a member variable called m_widget which holds a
146 pointer to this widget. When the window class represents a GTK native widget,
147 this is (in most cases) the only GTK widget the class manages. E.g. the
148 wxStaticText class handles only a GtkLabel widget a pointer to which you
149 can find in m_widget (defined in wxWindow)
151 When the class has a client area for drawing into and for containing children
152 it has to handle the client area widget (of the type GtkPizza, defined in
153 win_gtk.c), but there could be any number of widgets, handled by a class
154 The common rule for all windows is only, that the widget that interacts with
155 the rest of GTK must be referenced in m_widget and all other widgets must be
156 children of this widget on the GTK level. The top-most widget, which also
157 represents the client area, must be in the m_wxwindow field and must be of
160 As I said, the window classes that display a GTK native widget only have
161 one widget, so in the case of e.g. the wxButton class m_widget holds a
162 pointer to a GtkButton widget. But windows with client areas (for drawing
163 and children) have a m_widget field that is a pointer to a GtkScrolled-
164 Window and a m_wxwindow field that is pointer to a GtkPizza and this
165 one is (in the GTK sense) a child of the GtkScrolledWindow.
167 If the m_wxwindow field is set, then all input to this widget is inter-
168 cepted and sent to the wxWidgets class. If not, all input to the widget
169 that gets pointed to by m_widget gets intercepted and sent to the class.
173 The design of scrolling in wxWidgets is markedly different from that offered
174 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
175 clicking on a scrollbar belonging to scrolled window will inevitably move
176 the window. In wxWidgets, the scrollbar will only emit an event, send this
177 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
178 which actually moves the window and its subchildren. Note that GtkPizza
179 memorizes how much it has been scrolled but that wxWidgets forgets this
180 so that the two coordinates systems have to be kept in synch. This is done
181 in various places using the pizza->xoffset and pizza->yoffset values.
185 Singularily the most broken code in GTK is the code that is supposes to
186 inform subwindows (child windows) about new positions. Very often, duplicate
187 events are sent without changes in size or position, equally often no
188 events are sent at all (All this is due to a bug in the GtkContainer code
189 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
190 GTK's own system and it simply waits for size events for toplevel windows
191 and then iterates down the respective size events to all window. This has
192 the disadvantage, that windows might get size events before the GTK widget
193 actually has the reported size. This doesn't normally pose any problem, but
194 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
195 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
196 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
197 window that is used for OpenGl output really has that size (as reported by
202 If someone at some point of time feels the immense desire to have a look at,
203 change or attempt to optimse the Refresh() logic, this person will need an
204 intimate understanding of what a "draw" and what an "expose" events are and
205 what there are used for, in particular when used in connection with GTK's
206 own windowless widgets. Beware.
210 Cursors, too, have been a constant source of pleasure. The main difficulty
211 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
212 for the parent. To prevent this from doing too much harm, I use idle time
213 to set the cursor over and over again, starting from the toplevel windows
214 and ending with the youngest generation (speaking of parent and child windows).
215 Also don't forget that cursors (like much else) are connected to GdkWindows,
216 not GtkWidgets and that the "window" field of a GtkWidget might very well
217 point to the GdkWindow of the parent widget (-> "window less widget") and
218 that the two obviously have very different meanings.
222 //-----------------------------------------------------------------------------
224 //-----------------------------------------------------------------------------
226 extern wxList wxPendingDelete
;
227 extern bool g_blockEventsOnDrag
;
228 extern bool g_blockEventsOnScroll
;
229 extern wxCursor g_globalCursor
;
231 static GdkGC
*g_eraseGC
= NULL
;
233 // mouse capture state: the window which has it and if the mouse is currently
235 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
236 static bool g_captureWindowHasMouse
= FALSE
;
238 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
240 // the last window which had the focus - this is normally never NULL (except
241 // if we never had focus at all) as even when g_focusWindow is NULL it still
242 // keeps its previous value
243 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
245 // the frame that is currently active (i.e. its child has focus). It is
246 // used to generate wxActivateEvents
247 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
248 static bool g_activeFrameLostFocus
= FALSE
;
250 // If a window get the focus set but has not been realized
251 // yet, defer setting the focus to idle time.
252 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
254 // When GTK+ focus_in/out signal is being processed, we shouldn't do
256 static bool gs_inFocusSignalHandler
= false;
258 struct InFocusHandlerLock
260 InFocusHandlerLock() { gs_inFocusSignalHandler
= true; }
261 ~InFocusHandlerLock() { gs_inFocusSignalHandler
= false; }
264 // if we detect that the app has got/lost the focus, we set this variable to
265 // either TRUE or FALSE and an activate event will be sent during the next
266 // OnIdle() call and it is reset to -1: this value means that we shouldn't
267 // send any activate events at all
268 static int g_sendActivateEvent
= -1;
270 // hack: we need something to pass to gtk_menu_popup, so we store the time of
271 // the last click here
272 static guint32 gs_timeLastClick
= 0;
274 extern bool g_mainThreadLocked
;
276 //-----------------------------------------------------------------------------
278 //-----------------------------------------------------------------------------
283 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
285 # define DEBUG_MAIN_THREAD
288 #define DEBUG_MAIN_THREAD
291 // the trace mask used for the focus debugging messages
292 #define TRACE_FOCUS _T("focus")
294 //-----------------------------------------------------------------------------
295 // missing gdk functions
296 //-----------------------------------------------------------------------------
299 gdk_window_warp_pointer (GdkWindow
*window
,
304 GdkWindowPrivate
*priv
;
308 window
= GDK_ROOT_PARENT();
311 if (!GDK_WINDOW_DESTROYED(window
))
313 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
314 None
, /* not source window -> move from anywhere */
315 GDK_WINDOW_XID(window
), /* dest window */
316 0, 0, 0, 0, /* not source window -> move from anywhere */
320 priv
= (GdkWindowPrivate
*) window
;
322 if (!priv
->destroyed
)
324 XWarpPointer (priv
->xdisplay
,
325 None
, /* not source window -> move from anywhere */
326 priv
->xwindow
, /* dest window */
327 0, 0, 0, 0, /* not source window -> move from anywhere */
333 //-----------------------------------------------------------------------------
335 //-----------------------------------------------------------------------------
337 extern void wxapp_install_idle_handler();
338 extern bool g_isIdle
;
340 //-----------------------------------------------------------------------------
341 // local code (see below)
342 //-----------------------------------------------------------------------------
344 // returns the child of win which currently has focus or NULL if not found
346 // Note: can't be static, needed by textctrl.cpp.
347 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
349 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
351 return (wxWindow
*)NULL
;
353 if ( winFocus
== win
)
354 return (wxWindow
*)win
;
356 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
358 node
= node
->GetNext() )
360 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
365 return (wxWindow
*)NULL
;
368 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
370 // wxUniversal widgets draw the borders and scrollbars themselves
371 #ifndef __WXUNIVERSAL__
378 if (win
->m_hasScrolling
)
380 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
382 GtkRequisition vscroll_req
;
383 vscroll_req
.width
= 2;
384 vscroll_req
.height
= 2;
385 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
386 (scroll_window
->vscrollbar
, &vscroll_req
);
388 GtkRequisition hscroll_req
;
389 hscroll_req
.width
= 2;
390 hscroll_req
.height
= 2;
391 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
392 (scroll_window
->hscrollbar
, &hscroll_req
);
394 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
396 if (scroll_window
->vscrollbar_visible
)
398 dw
+= vscroll_req
.width
;
399 dw
+= scroll_class
->scrollbar_spacing
;
402 if (scroll_window
->hscrollbar_visible
)
404 dh
+= hscroll_req
.height
;
405 dh
+= scroll_class
->scrollbar_spacing
;
411 if (GTK_WIDGET_NO_WINDOW (widget
))
413 dx
+= widget
->allocation
.x
;
414 dy
+= widget
->allocation
.y
;
417 if (win
->HasFlag(wxRAISED_BORDER
))
419 gtk_draw_shadow( widget
->style
,
424 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
428 if (win
->HasFlag(wxSUNKEN_BORDER
))
430 gtk_draw_shadow( widget
->style
,
435 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
439 if (win
->HasFlag(wxSIMPLE_BORDER
))
442 gc
= gdk_gc_new( widget
->window
);
443 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
444 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
446 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
450 #endif // __WXUNIVERSAL__
453 //-----------------------------------------------------------------------------
454 // "expose_event" of m_widget
455 //-----------------------------------------------------------------------------
457 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
459 if (gdk_event
->count
> 0) return FALSE
;
461 draw_frame( widget
, win
);
465 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
471 //-----------------------------------------------------------------------------
472 // "draw" of m_widget
473 //-----------------------------------------------------------------------------
477 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
479 draw_frame( widget
, win
);
484 //-----------------------------------------------------------------------------
485 // "size_request" of m_widget
486 //-----------------------------------------------------------------------------
488 // make it extern because wxStatitText needs to disconnect this one
490 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
491 GtkRequisition
*requisition
,
495 win
->GetSize( &w
, &h
);
501 requisition
->height
= h
;
502 requisition
->width
= w
;
505 //-----------------------------------------------------------------------------
506 // "expose_event" of m_wxwindow
507 //-----------------------------------------------------------------------------
509 static int gtk_window_expose_callback( GtkWidget
*widget
,
510 GdkEventExpose
*gdk_event
,
516 wxapp_install_idle_handler();
519 // This callback gets called in drawing-idle time under
520 // GTK 2.0, so we don't need to defer anything to idle
523 GtkPizza
*pizza
= GTK_PIZZA( widget
);
524 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
529 wxPrintf( wxT("OnExpose from ") );
530 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
531 wxPrintf( win
->GetClassInfo()->GetClassName() );
532 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
533 (int)gdk_event
->area
.y
,
534 (int)gdk_event
->area
.width
,
535 (int)gdk_event
->area
.height
);
540 win
->m_wxwindow
->style
,
544 (GdkRectangle
*) NULL
,
546 (char *)"button", // const_cast
551 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
553 win
->GtkSendPaintEvents();
556 // Let parent window draw window less widgets
557 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
559 // This gets called immediately after an expose event
560 // under GTK 1.2 so we collect the calls and wait for
561 // the idle handler to pick things up.
563 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
565 gdk_event
->area
.width
,
566 gdk_event
->area
.height
);
567 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
569 gdk_event
->area
.width
,
570 gdk_event
->area
.height
);
572 // Actual redrawing takes place in idle time.
579 //-----------------------------------------------------------------------------
580 // "event" of m_wxwindow
581 //-----------------------------------------------------------------------------
583 // GTK thinks it is clever and filters out a certain amount of "unneeded"
584 // expose events. We need them, of course, so we override the main event
585 // procedure in GtkWidget by giving our own handler for all system events.
586 // There, we look for expose events ourselves whereas all other events are
589 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
590 GdkEventExpose
*event
,
593 if (event
->type
== GDK_EXPOSE
)
595 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
602 //-----------------------------------------------------------------------------
603 // "draw" of m_wxwindow
604 //-----------------------------------------------------------------------------
608 // This callback is a complete replacement of the gtk_pizza_draw() function,
609 // which is disabled.
611 static void gtk_window_draw_callback( GtkWidget
*widget
,
618 wxapp_install_idle_handler();
620 // if there are any children we must refresh everything
623 if ( !win
->HasFlag(wxFULL_REPAINT_ON_RESIZE
) &&
624 win
->GetChildren().IsEmpty() )
632 wxPrintf( wxT("OnDraw from ") );
633 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
634 wxPrintf( win
->GetClassInfo()->GetClassName() );
635 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
642 #ifndef __WXUNIVERSAL__
643 GtkPizza
*pizza
= GTK_PIZZA (widget
);
645 if (win
->GetThemeEnabled())
647 wxWindow
*parent
= win
->GetParent();
648 while (parent
&& !parent
->IsTopLevel())
649 parent
= parent
->GetParent();
653 gtk_paint_flat_box (parent
->m_widget
->style
,
664 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
665 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
667 // Update immediately, not in idle time.
670 #ifndef __WXUNIVERSAL__
671 // Redraw child widgets
672 GList
*children
= pizza
->children
;
675 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
676 children
= children
->next
;
678 GdkRectangle child_area
;
679 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
681 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
689 //-----------------------------------------------------------------------------
690 // "key_press_event" from any window
691 //-----------------------------------------------------------------------------
693 // set WXTRACE to this to see the key event codes on the console
694 #define TRACE_KEYS _T("keyevent")
696 // translates an X key symbol to WXK_XXX value
698 // if isChar is true it means that the value returned will be used for EVT_CHAR
699 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
700 // for example, while if it is false it means that the value is going to be
701 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
703 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
709 // Shift, Control and Alt don't generate the CHAR events at all
712 key_code
= isChar
? 0 : WXK_SHIFT
;
716 key_code
= isChar
? 0 : WXK_CONTROL
;
724 key_code
= isChar
? 0 : WXK_ALT
;
727 // neither do the toggle modifies
728 case GDK_Scroll_Lock
:
729 key_code
= isChar
? 0 : WXK_SCROLL
;
733 key_code
= isChar
? 0 : WXK_CAPITAL
;
737 key_code
= isChar
? 0 : WXK_NUMLOCK
;
741 // various other special keys
754 case GDK_ISO_Left_Tab
:
761 key_code
= WXK_RETURN
;
765 key_code
= WXK_CLEAR
;
769 key_code
= WXK_PAUSE
;
773 key_code
= WXK_SELECT
;
777 key_code
= WXK_PRINT
;
781 key_code
= WXK_EXECUTE
;
785 key_code
= WXK_ESCAPE
;
788 // cursor and other extended keyboard keys
790 key_code
= WXK_DELETE
;
806 key_code
= WXK_RIGHT
;
813 case GDK_Prior
: // == GDK_Page_Up
814 key_code
= WXK_PRIOR
;
817 case GDK_Next
: // == GDK_Page_Down
830 key_code
= WXK_INSERT
;
845 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
849 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
853 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
857 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
861 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
865 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
869 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
873 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
877 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
881 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
885 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
889 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
893 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
896 case GDK_KP_Prior
: // == GDK_KP_Page_Up
897 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
900 case GDK_KP_Next
: // == GDK_KP_Page_Down
901 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
905 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
909 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
913 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
917 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
921 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
924 case GDK_KP_Multiply
:
925 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
929 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
932 case GDK_KP_Separator
:
933 // FIXME: what is this?
934 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
937 case GDK_KP_Subtract
:
938 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
942 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
946 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
963 key_code
= WXK_F1
+ keysym
- GDK_F1
;
973 static inline bool wxIsAsciiKeysym(KeySym ks
)
978 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
980 GdkEventKey
*gdk_event
)
984 GdkModifierType state
;
985 if (gdk_event
->window
)
986 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
988 event
.SetTimestamp( gdk_event
->time
);
989 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
990 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
991 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
992 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
993 event
.m_scanCode
= gdk_event
->keyval
;
994 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
995 event
.m_rawFlags
= 0;
998 event
.SetEventObject( win
);
1003 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
1005 GdkEventKey
*gdk_event
)
1007 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
1008 // but only event->keyval which is quite useless to us, so remember
1009 // the last character from GDK_KEY_PRESS and reuse it as last resort
1011 // NB: should be MT-safe as we're always called from the main thread only
1016 } s_lastKeyPress
= { 0, 0 };
1018 KeySym keysym
= gdk_event
->keyval
;
1020 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
1021 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
1025 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
1029 // do we have the translation or is it a plain ASCII character?
1030 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1032 // we should use keysym if it is ASCII as X does some translations
1033 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1034 // which we don't want here (but which we do use for OnChar())
1035 if ( !wxIsAsciiKeysym(keysym
) )
1037 keysym
= (KeySym
)gdk_event
->string
[0];
1040 // we want to always get the same key code when the same key is
1041 // pressed regardless of the state of the modifies, i.e. on a
1042 // standard US keyboard pressing '5' or '%' ('5' key with
1043 // Shift) should result in the same key code in OnKeyDown():
1044 // '5' (although OnChar() will get either '5' or '%').
1046 // to do it we first translate keysym to keycode (== scan code)
1047 // and then back but always using the lower register
1048 Display
*dpy
= (Display
*)wxGetDisplay();
1049 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1051 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1053 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1055 // use the normalized, i.e. lower register, keysym if we've
1057 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1059 // as explained above, we want to have lower register key codes
1060 // normally but for the letter keys we want to have the upper ones
1062 // NB: don't use XConvertCase() here, we want to do it for letters
1064 key_code
= toupper(key_code
);
1066 else // non ASCII key, what to do?
1068 // by default, ignore it
1071 // but if we have cached information from the last KEY_PRESS
1072 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1075 if ( keysym
== s_lastKeyPress
.keysym
)
1077 key_code
= s_lastKeyPress
.keycode
;
1082 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1084 // remember it to be reused for KEY_UP event later
1085 s_lastKeyPress
.keysym
= keysym
;
1086 s_lastKeyPress
.keycode
= key_code
;
1090 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1092 // sending unknown key events doesn't really make sense
1096 // now fill all the other fields
1097 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
1099 event
.m_keyCode
= key_code
;
1108 GtkIMContext
*context
;
1109 GdkEventKey
*lastKeyEvent
;
1113 context
= gtk_im_multicontext_new();
1114 lastKeyEvent
= NULL
;
1118 g_object_unref(context
);
1123 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1124 GdkEventKey
*gdk_event
,
1130 wxapp_install_idle_handler();
1134 if (g_blockEventsOnDrag
)
1138 // We have to pass key press events through GTK+'s Input Method context
1139 // object in order to get correct characters. By doing so, we loose the
1140 // ability to let other GTK+'s handlers (namely, widgets' default signal
1141 // handlers) handle the signal by returning false from this callback.
1142 // Because GTK+ sends the events to parent widgets as well, we can't
1143 // afford loosing it, otherwise native widgets inserted into wxPanel
1144 // would break in subtle ways (e.g. spacebar would no longer toggle
1145 // wxCheckButton's state). Therefore, we only pass the event to IM if it
1146 // originated in this window's widget, which we detect by checking if we've
1147 // seen the same event before (no events from children are lost this way,
1148 // because gtk_window_key_press_callback is installed for native controls
1149 // as well and the wxKeyEvent it creates propagates upwards).
1150 static GdkEventKey s_lastEvent
;
1152 bool useIM
= (win
->m_imData
!= NULL
) &&
1153 memcmp(gdk_event
, &s_lastEvent
, sizeof(GdkEventKey
)) != 0;
1155 s_lastEvent
= *gdk_event
;
1158 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1159 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1161 // unknown key pressed, ignore (the event would be useless anyhow)
1165 // it may be useful for the input method, though:
1166 win
->m_imData
->lastKeyEvent
= gdk_event
;
1167 bool ret
= gtk_im_context_filter_keypress(win
->m_imData
->context
,
1169 win
->m_imData
->lastKeyEvent
= NULL
;
1176 // Emit KEY_DOWN event
1177 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1182 wxWindowGTK
*ancestor
= win
;
1185 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1188 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1189 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1192 if (ancestor
->IsTopLevel())
1194 ancestor
= ancestor
->GetParent();
1197 #endif // wxUSE_ACCEL
1199 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1200 // will only be sent if it is not in an accelerator table.
1206 // In GTK 2.0, we need to hand over the key event to an input method
1207 // and the IM will emit a "commit" event containing the actual utf8
1208 // character. In that case the EVT_CHAR events will be sent from
1210 win
->m_imData
->lastKeyEvent
= gdk_event
;
1211 if ( gtk_im_context_filter_keypress(win
->m_imData
->context
,
1214 win
->m_imData
->lastKeyEvent
= NULL
;
1215 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1219 win
->m_imData
->lastKeyEvent
= NULL
;
1224 KeySym keysym
= gdk_event
->keyval
;
1225 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1226 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1229 if ( gdk_event
->length
== 1 )
1231 key_code
= (unsigned char)gdk_event
->string
[0];
1233 else if ( wxIsAsciiKeysym(keysym
) )
1236 key_code
= (unsigned char)keysym
;
1242 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1244 event
.m_keyCode
= key_code
;
1246 // Implement OnCharHook by checking ancesteror top level windows
1247 wxWindow
*parent
= win
;
1248 while (parent
&& !parent
->IsTopLevel())
1249 parent
= parent
->GetParent();
1252 event
.SetEventType( wxEVT_CHAR_HOOK
);
1253 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1258 event
.SetEventType(wxEVT_CHAR
);
1259 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1264 // win is a control: tab can be propagated up
1266 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1267 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1268 // have this style, yet choose not to process this particular TAB in which
1269 // case TAB must still work as a navigational character
1270 // JS: enabling again to make consistent with other platforms
1271 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1272 // navigation behaviour)
1274 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1276 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1278 wxNavigationKeyEvent new_event
;
1279 new_event
.SetEventObject( win
->GetParent() );
1280 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1281 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1282 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1283 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1284 new_event
.SetCurrentFocus( win
);
1285 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1288 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1290 (gdk_event
->keyval
== GDK_Escape
) )
1292 // however only do it if we have a Cancel button in the dialog,
1293 // otherwise the user code may get confused by the events from a
1294 // non-existing button and, worse, a wxButton might get button event
1295 // from another button which is not really expected
1296 wxWindow
*winForCancel
= win
,
1298 while ( winForCancel
)
1300 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1303 // found a cancel button
1307 if ( winForCancel
->IsTopLevel() )
1309 // no need to look further
1313 // maybe our parent has a cancel button?
1314 winForCancel
= winForCancel
->GetParent();
1319 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1320 event
.SetEventObject(btnCancel
);
1321 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1327 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1335 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1339 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1341 // take modifiers, cursor position, timestamp etc. from the last
1342 // key_press_event that was fed into Input Method:
1343 if (window
->m_imData
->lastKeyEvent
)
1345 wxFillOtherKeyEventFields(event
,
1346 window
, window
->m_imData
->lastKeyEvent
);
1350 event
.m_uniChar
= g_utf8_get_char( str
);
1352 // Backward compatible for ISO-8859
1353 if (event
.m_uniChar
< 256)
1354 event
.m_keyCode
= event
.m_uniChar
;
1355 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1358 unistr
[0] = g_utf8_get_char(str
);
1360 wxCharBuffer
ansistr(wxConvLocal
.cWC2MB(unistr
));
1361 // We cannot handle characters that cannot be represented in
1362 // current locale's charset in non-Unicode mode:
1363 if (ansistr
.data() == NULL
)
1365 event
.m_keyCode
= ansistr
[0u];
1366 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), (wxChar
)event
.m_keyCode
);
1367 #endif // wxUSE_UNICODE
1371 // Implement OnCharHook by checking ancestor top level windows
1372 wxWindow
*parent
= window
;
1373 while (parent
&& !parent
->IsTopLevel())
1374 parent
= parent
->GetParent();
1377 event
.SetEventType( wxEVT_CHAR_HOOK
);
1378 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1383 event
.SetEventType(wxEVT_CHAR
);
1384 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1390 //-----------------------------------------------------------------------------
1391 // "key_release_event" from any window
1392 //-----------------------------------------------------------------------------
1394 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1395 GdkEventKey
*gdk_event
,
1401 wxapp_install_idle_handler();
1406 if (g_blockEventsOnDrag
)
1409 wxKeyEvent
event( wxEVT_KEY_UP
);
1410 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1412 // unknown key pressed, ignore (the event would be useless anyhow
1416 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1419 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1423 // ============================================================================
1425 // ============================================================================
1427 // ----------------------------------------------------------------------------
1428 // mouse event processing helpers
1429 // ----------------------------------------------------------------------------
1431 // init wxMouseEvent with the info from GdkEventXXX struct
1432 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1433 wxMouseEvent
& event
,
1436 event
.SetTimestamp( gdk_event
->time
);
1437 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1438 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1439 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1440 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1441 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1442 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1443 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1444 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1446 event
.m_linesPerAction
= 3;
1447 event
.m_wheelDelta
= 120;
1448 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1449 event
.m_wheelRotation
= 120;
1450 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1451 event
.m_wheelRotation
= -120;
1454 wxPoint pt
= win
->GetClientAreaOrigin();
1455 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1456 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1458 event
.SetEventObject( win
);
1459 event
.SetId( win
->GetId() );
1460 event
.SetTimestamp( gdk_event
->time
);
1463 static void AdjustEventButtonState(wxMouseEvent
& event
)
1465 // GDK reports the old state of the button for a button press event, but
1466 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1467 // for a LEFT_DOWN event, not FALSE, so we will invert
1468 // left/right/middleDown for the corresponding click events
1470 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1471 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1472 (event
.GetEventType() == wxEVT_LEFT_UP
))
1474 event
.m_leftDown
= !event
.m_leftDown
;
1478 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1479 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1480 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1482 event
.m_middleDown
= !event
.m_middleDown
;
1486 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1487 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1488 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1490 event
.m_rightDown
= !event
.m_rightDown
;
1495 // find the window to send the mouse event too
1497 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1502 if (win
->m_wxwindow
)
1504 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1505 xx
+= pizza
->xoffset
;
1506 yy
+= pizza
->yoffset
;
1509 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1512 wxWindowGTK
*child
= node
->GetData();
1514 node
= node
->GetNext();
1515 if (!child
->IsShown())
1518 if (child
->IsTransparentForMouse())
1520 // wxStaticBox is transparent in the box itself
1521 int xx1
= child
->m_x
;
1522 int yy1
= child
->m_y
;
1523 int xx2
= child
->m_x
+ child
->m_width
;
1524 int yy2
= child
->m_y
+ child
->m_height
;
1527 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1529 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1531 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1533 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1544 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1545 (child
->m_x
<= xx
) &&
1546 (child
->m_y
<= yy
) &&
1547 (child
->m_x
+child
->m_width
>= xx
) &&
1548 (child
->m_y
+child
->m_height
>= yy
))
1561 //-----------------------------------------------------------------------------
1562 // "button_press_event"
1563 //-----------------------------------------------------------------------------
1565 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1566 GdkEventButton
*gdk_event
,
1572 wxapp_install_idle_handler();
1575 wxPrintf( wxT("1) OnButtonPress from ") );
1576 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1577 wxPrintf( win->GetClassInfo()->GetClassName() );
1578 wxPrintf( wxT(".\n") );
1580 if (!win
->m_hasVMT
) return FALSE
;
1581 if (g_blockEventsOnDrag
) return TRUE
;
1582 if (g_blockEventsOnScroll
) return TRUE
;
1584 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1586 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1588 gtk_widget_grab_focus( win
->m_wxwindow
);
1590 wxPrintf( wxT("GrabFocus from ") );
1591 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1592 wxPrintf( win->GetClassInfo()->GetClassName() );
1593 wxPrintf( wxT(".\n") );
1597 // GDK sends surplus button down event
1598 // before a double click event. We
1599 // need to filter these out.
1600 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1602 GdkEvent
*peek_event
= gdk_event_peek();
1605 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1606 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1608 gdk_event_free( peek_event
);
1613 gdk_event_free( peek_event
);
1618 wxEventType event_type
= wxEVT_NULL
;
1620 // GdkDisplay is a GTK+ 2.2.0 thing
1621 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1622 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1623 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1625 // Reset GDK internal timestamp variables in order to disable GDK
1626 // triple click events. GDK will then next time believe no button has
1627 // been clicked just before, and send a normal button click event.
1628 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1629 display
->button_click_time
[1] = 0;
1630 display
->button_click_time
[0] = 0;
1634 if (gdk_event
->button
== 1)
1636 // note that GDK generates triple click events which are not supported
1637 // by wxWidgets but still have to be passed to the app as otherwise
1638 // clicks would simply go missing
1639 switch (gdk_event
->type
)
1641 // we shouldn't get triple clicks at all for GTK2 because we
1642 // suppress them artificially using the code above but we still
1643 // should map them to something for GTK1 and not just ignore them
1644 // as this would lose clicks
1645 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1646 case GDK_BUTTON_PRESS
:
1647 event_type
= wxEVT_LEFT_DOWN
;
1650 case GDK_2BUTTON_PRESS
:
1651 event_type
= wxEVT_LEFT_DCLICK
;
1655 // just to silence gcc warnings
1659 else if (gdk_event
->button
== 2)
1661 switch (gdk_event
->type
)
1663 case GDK_3BUTTON_PRESS
:
1664 case GDK_BUTTON_PRESS
:
1665 event_type
= wxEVT_MIDDLE_DOWN
;
1668 case GDK_2BUTTON_PRESS
:
1669 event_type
= wxEVT_MIDDLE_DCLICK
;
1676 else if (gdk_event
->button
== 3)
1678 switch (gdk_event
->type
)
1680 case GDK_3BUTTON_PRESS
:
1681 case GDK_BUTTON_PRESS
:
1682 event_type
= wxEVT_RIGHT_DOWN
;
1685 case GDK_2BUTTON_PRESS
:
1686 event_type
= wxEVT_RIGHT_DCLICK
;
1693 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1695 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1697 event_type
= wxEVT_MOUSEWHEEL
;
1701 if ( event_type
== wxEVT_NULL
)
1703 // unknown mouse button or click type
1707 wxMouseEvent
event( event_type
);
1708 InitMouseEvent( win
, event
, gdk_event
);
1710 AdjustEventButtonState(event
);
1712 // wxListBox actually get mouse events from the item, so we need to give it
1713 // a chance to correct this
1714 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1716 if ( event_type
== wxEVT_RIGHT_DOWN
)
1718 // generate a "context menu" event: this is similar to right mouse
1719 // click under many GUIs except that it is generated differently
1720 // (right up under MSW, ctrl-click under Mac, right down here) and
1722 // (a) it's a command event and so is propagated to the parent
1723 // (b) under MSW it can be generated from kbd too
1724 // (c) it uses screen coords (because of (a))
1725 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1727 win
->ClientToScreen(event
.GetPosition()));
1728 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1731 // find the correct window to send the event too: it may be a different one
1732 // from the one which got it at GTK+ level because some control don't have
1733 // their own X window and thus cannot get any events.
1734 if ( !g_captureWindow
)
1735 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1737 gs_timeLastClick
= gdk_event
->time
;
1740 if (event_type
== wxEVT_LEFT_DCLICK
)
1742 // GTK 1.2 crashes when intercepting double
1743 // click events from both wxSpinButton and
1745 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1747 // Just disable this event for now.
1753 if (win
->GetEventHandler()->ProcessEvent( event
))
1755 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1762 //-----------------------------------------------------------------------------
1763 // "button_release_event"
1764 //-----------------------------------------------------------------------------
1766 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1767 GdkEventButton
*gdk_event
,
1773 wxapp_install_idle_handler();
1775 if (!win
->m_hasVMT
) return FALSE
;
1776 if (g_blockEventsOnDrag
) return FALSE
;
1777 if (g_blockEventsOnScroll
) return FALSE
;
1779 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1781 wxEventType event_type
= wxEVT_NULL
;
1783 switch (gdk_event
->button
)
1786 event_type
= wxEVT_LEFT_UP
;
1790 event_type
= wxEVT_MIDDLE_UP
;
1794 event_type
= wxEVT_RIGHT_UP
;
1798 // unknwon button, don't process
1802 wxMouseEvent
event( event_type
);
1803 InitMouseEvent( win
, event
, gdk_event
);
1805 AdjustEventButtonState(event
);
1807 // same wxListBox hack as above
1808 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1810 if ( !g_captureWindow
)
1811 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1813 if (win
->GetEventHandler()->ProcessEvent( event
))
1815 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1822 //-----------------------------------------------------------------------------
1823 // "motion_notify_event"
1824 //-----------------------------------------------------------------------------
1826 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1827 GdkEventMotion
*gdk_event
,
1833 wxapp_install_idle_handler();
1835 if (!win
->m_hasVMT
) return FALSE
;
1836 if (g_blockEventsOnDrag
) return FALSE
;
1837 if (g_blockEventsOnScroll
) return FALSE
;
1839 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1841 if (gdk_event
->is_hint
)
1845 GdkModifierType state
;
1846 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1852 printf( "OnMotion from " );
1853 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1854 printf( win->GetClassInfo()->GetClassName() );
1858 wxMouseEvent
event( wxEVT_MOTION
);
1859 InitMouseEvent(win
, event
, gdk_event
);
1861 if ( g_captureWindow
)
1863 // synthetize a mouse enter or leave event if needed
1864 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1865 // This seems to be necessary and actually been added to
1866 // GDK itself in version 2.0.X
1869 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1870 if ( hasMouse
!= g_captureWindowHasMouse
)
1872 // the mouse changed window
1873 g_captureWindowHasMouse
= hasMouse
;
1875 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1876 : wxEVT_LEAVE_WINDOW
);
1877 InitMouseEvent(win
, event
, gdk_event
);
1878 event
.SetEventObject(win
);
1879 win
->GetEventHandler()->ProcessEvent(event
);
1884 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1887 if (win
->GetEventHandler()->ProcessEvent( event
))
1889 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1897 //-----------------------------------------------------------------------------
1898 // "mouse_wheel_event"
1899 //-----------------------------------------------------------------------------
1901 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1902 GdkEventScroll
* gdk_event
,
1908 wxapp_install_idle_handler();
1910 wxEventType event_type
= wxEVT_NULL
;
1911 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1912 event_type
= wxEVT_MOUSEWHEEL
;
1913 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1914 event_type
= wxEVT_MOUSEWHEEL
;
1918 wxMouseEvent
event( event_type
);
1919 // Can't use InitMouse macro because scroll events don't have button
1920 event
.SetTimestamp( gdk_event
->time
);
1921 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1922 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1923 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1924 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1925 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1926 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1927 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1928 event
.m_linesPerAction
= 3;
1929 event
.m_wheelDelta
= 120;
1930 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1931 event
.m_wheelRotation
= 120;
1933 event
.m_wheelRotation
= -120;
1935 wxPoint pt
= win
->GetClientAreaOrigin();
1936 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1937 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1939 event
.SetEventObject( win
);
1940 event
.SetId( win
->GetId() );
1941 event
.SetTimestamp( gdk_event
->time
);
1943 if (win
->GetEventHandler()->ProcessEvent( event
))
1945 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1953 //-----------------------------------------------------------------------------
1955 //-----------------------------------------------------------------------------
1957 // send the wxChildFocusEvent and wxFocusEvent, common code of
1958 // gtk_window_focus_in_callback() and SetFocus()
1959 static bool DoSendFocusEvents(wxWindow
*win
)
1961 // Notify the parent keeping track of focus for the kbd navigation
1962 // purposes that we got it.
1963 wxChildFocusEvent
eventChildFocus(win
);
1964 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1966 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1967 eventFocus
.SetEventObject(win
);
1969 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1972 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1973 GdkEvent
*WXUNUSED(event
),
1976 InFocusHandlerLock flock
;
1981 wxapp_install_idle_handler();
1985 gtk_im_context_focus_in(win
->m_imData
->context
);
1988 if (!win
->m_hasVMT
) return FALSE
;
1989 if (g_blockEventsOnDrag
) return FALSE
;
1991 switch ( g_sendActivateEvent
)
1994 // we've got focus from outside, synthetize wxActivateEvent
1995 g_sendActivateEvent
= 1;
1999 // another our window just lost focus, it was already ours before
2000 // - don't send any wxActivateEvent
2001 g_sendActivateEvent
= -1;
2006 g_focusWindow
= win
;
2008 wxLogTrace(TRACE_FOCUS
,
2009 _T("%s: focus in"), win
->GetName().c_str());
2013 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
2017 // caret needs to be informed about focus change
2018 wxCaret
*caret
= win
->GetCaret();
2021 caret
->OnSetFocus();
2023 #endif // wxUSE_CARET
2025 g_activeFrameLostFocus
= FALSE
;
2027 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
2028 if ( active
!= g_activeFrame
)
2030 if ( g_activeFrame
)
2032 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
2033 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2034 event
.SetEventObject(g_activeFrame
);
2035 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2038 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
2039 g_activeFrame
= active
;
2040 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
2041 event
.SetEventObject(g_activeFrame
);
2042 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2044 // Don't send focus events in addition to activate
2045 // if (win == g_activeFrame)
2049 // does the window itself think that it has the focus?
2050 if ( !win
->m_hasFocus
)
2052 // not yet, notify it
2053 win
->m_hasFocus
= TRUE
;
2055 if ( DoSendFocusEvents(win
) )
2057 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2065 //-----------------------------------------------------------------------------
2066 // "focus_out_event"
2067 //-----------------------------------------------------------------------------
2069 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2073 InFocusHandlerLock flock
;
2076 wxapp_install_idle_handler();
2080 gtk_im_context_focus_out(win
->m_imData
->context
);
2083 if (!win
->m_hasVMT
) return FALSE
;
2084 if (g_blockEventsOnDrag
) return FALSE
;
2086 wxLogTrace( TRACE_FOCUS
,
2087 _T("%s: focus out"), win
->GetName().c_str() );
2089 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
2091 // VZ: commenting this out because it does happen (although not easy
2092 // to reproduce, I only see it when using wxMiniFrame and not
2093 // always) and makes using Mahogany quite annoying
2095 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
2096 wxT("unfocusing window that hasn't gained focus properly") );
2099 g_activeFrameLostFocus
= TRUE
;
2102 // if the focus goes out of our app alltogether, OnIdle() will send
2103 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
2104 // g_sendActivateEvent to -1
2105 g_sendActivateEvent
= 0;
2107 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2111 g_focusWindow
= (wxWindowGTK
*)NULL
;
2119 // caret needs to be informed about focus change
2120 wxCaret
*caret
= win
->GetCaret();
2123 caret
->OnKillFocus();
2125 #endif // wxUSE_CARET
2127 // don't send the window a kill focus event if it thinks that it doesn't
2128 // have focus already
2129 if ( win
->m_hasFocus
)
2131 win
->m_hasFocus
= FALSE
;
2133 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2134 event
.SetEventObject( win
);
2136 if (win
->GetEventHandler()->ProcessEvent( event
))
2138 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
2146 //-----------------------------------------------------------------------------
2147 // "enter_notify_event"
2148 //-----------------------------------------------------------------------------
2151 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2152 GdkEventCrossing
*gdk_event
,
2158 wxapp_install_idle_handler();
2160 if (!win
->m_hasVMT
) return FALSE
;
2161 if (g_blockEventsOnDrag
) return FALSE
;
2163 // Event was emitted after a grab
2164 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2166 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2170 GdkModifierType state
= (GdkModifierType
)0;
2172 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2174 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2175 InitMouseEvent(win
, event
, gdk_event
);
2176 wxPoint pt
= win
->GetClientAreaOrigin();
2177 event
.m_x
= x
+ pt
.x
;
2178 event
.m_y
= y
+ pt
.y
;
2180 if (win
->GetEventHandler()->ProcessEvent( event
))
2182 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2189 //-----------------------------------------------------------------------------
2190 // "leave_notify_event"
2191 //-----------------------------------------------------------------------------
2193 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2198 wxapp_install_idle_handler();
2200 if (!win
->m_hasVMT
) return FALSE
;
2201 if (g_blockEventsOnDrag
) return FALSE
;
2203 // Event was emitted after an ungrab
2204 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2206 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2208 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2209 event
.SetTimestamp( gdk_event
->time
);
2210 event
.SetEventObject( win
);
2214 GdkModifierType state
= (GdkModifierType
)0;
2216 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2218 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2219 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2220 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2221 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2222 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2223 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2224 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2226 wxPoint pt
= win
->GetClientAreaOrigin();
2227 event
.m_x
= x
+ pt
.x
;
2228 event
.m_y
= y
+ pt
.y
;
2230 if (win
->GetEventHandler()->ProcessEvent( event
))
2232 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2239 //-----------------------------------------------------------------------------
2240 // "value_changed" from m_vAdjust
2241 //-----------------------------------------------------------------------------
2243 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2250 wxapp_install_idle_handler();
2252 if (g_blockEventsOnDrag
) return;
2254 if (!win
->m_hasVMT
) return;
2256 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2257 if (fabs(diff
) < 0.2) return;
2259 win
->m_oldVerticalPos
= adjust
->value
;
2262 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2264 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2266 int value
= (int)(adjust
->value
+0.5);
2268 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2269 event
.SetEventObject( win
);
2270 win
->GetEventHandler()->ProcessEvent( event
);
2273 //-----------------------------------------------------------------------------
2274 // "value_changed" from m_hAdjust
2275 //-----------------------------------------------------------------------------
2277 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2284 wxapp_install_idle_handler();
2286 if (g_blockEventsOnDrag
) return;
2287 if (!win
->m_hasVMT
) return;
2289 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2290 if (fabs(diff
) < 0.2) return;
2293 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2295 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2297 win
->m_oldHorizontalPos
= adjust
->value
;
2299 int value
= (int)(adjust
->value
+0.5);
2301 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2302 event
.SetEventObject( win
);
2303 win
->GetEventHandler()->ProcessEvent( event
);
2306 //-----------------------------------------------------------------------------
2307 // "button_press_event" from scrollbar
2308 //-----------------------------------------------------------------------------
2310 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2311 GdkEventButton
*gdk_event
,
2317 wxapp_install_idle_handler();
2320 g_blockEventsOnScroll
= TRUE
;
2322 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2324 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2330 //-----------------------------------------------------------------------------
2331 // "button_release_event" from scrollbar
2332 //-----------------------------------------------------------------------------
2334 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2335 GdkEventButton
*WXUNUSED(gdk_event
),
2340 // don't test here as we can release the mouse while being over
2341 // a different window than the slider
2343 // if (gdk_event->window != widget->slider) return FALSE;
2345 g_blockEventsOnScroll
= FALSE
;
2347 if (win
->m_isScrolling
)
2349 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2353 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2354 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2356 value
= (int)(win
->m_hAdjust
->value
+0.5);
2359 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2361 value
= (int)(win
->m_vAdjust
->value
+0.5);
2365 wxScrollWinEvent
event( command
, value
, dir
);
2366 event
.SetEventObject( win
);
2367 win
->GetEventHandler()->ProcessEvent( event
);
2370 win
->m_isScrolling
= FALSE
;
2375 // ----------------------------------------------------------------------------
2376 // this wxWindowBase function is implemented here (in platform-specific file)
2377 // because it is static and so couldn't be made virtual
2378 // ----------------------------------------------------------------------------
2380 wxWindow
*wxWindowBase::FindFocus()
2382 // the cast is necessary when we compile in wxUniversal mode
2383 return (wxWindow
*)g_focusWindow
;
2387 //-----------------------------------------------------------------------------
2388 // "realize" from m_widget
2389 //-----------------------------------------------------------------------------
2391 /* We cannot set colours and fonts before the widget has
2392 been realized, so we do this directly after realization. */
2395 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2400 wxapp_install_idle_handler();
2405 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2406 gtk_im_context_set_client_window( win
->m_imData
->context
,
2407 pizza
->bin_window
);
2411 wxWindowCreateEvent
event( win
);
2412 event
.SetEventObject( win
);
2413 win
->GetEventHandler()->ProcessEvent( event
);
2418 //-----------------------------------------------------------------------------
2420 //-----------------------------------------------------------------------------
2423 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2424 GtkAllocation
*WXUNUSED(alloc
),
2428 wxapp_install_idle_handler();
2430 if (!win
->m_hasScrolling
) return;
2432 int client_width
= 0;
2433 int client_height
= 0;
2434 win
->GetClientSize( &client_width
, &client_height
);
2435 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2438 win
->m_oldClientWidth
= client_width
;
2439 win
->m_oldClientHeight
= client_height
;
2441 if (!win
->m_nativeSizeEvent
)
2443 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2444 event
.SetEventObject( win
);
2445 win
->GetEventHandler()->ProcessEvent( event
);
2451 #define WXUNUSED_UNLESS_XIM(param) param
2453 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2456 /* Resize XIM window */
2459 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2460 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2461 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2464 wxapp_install_idle_handler();
2470 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2474 gdk_window_get_size (widget
->window
, &width
, &height
);
2475 win
->m_icattr
->preedit_area
.width
= width
;
2476 win
->m_icattr
->preedit_area
.height
= height
;
2477 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2482 //-----------------------------------------------------------------------------
2483 // "realize" from m_wxwindow
2484 //-----------------------------------------------------------------------------
2486 /* Initialize XIM support */
2489 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2490 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2493 wxapp_install_idle_handler();
2496 if (win
->m_ic
) return FALSE
;
2497 if (!widget
) return FALSE
;
2498 if (!gdk_im_ready()) return FALSE
;
2500 win
->m_icattr
= gdk_ic_attr_new();
2501 if (!win
->m_icattr
) return FALSE
;
2505 GdkColormap
*colormap
;
2506 GdkICAttr
*attr
= win
->m_icattr
;
2507 unsigned attrmask
= GDK_IC_ALL_REQ
;
2509 GdkIMStyle supported_style
= (GdkIMStyle
)
2510 (GDK_IM_PREEDIT_NONE
|
2511 GDK_IM_PREEDIT_NOTHING
|
2512 GDK_IM_PREEDIT_POSITION
|
2513 GDK_IM_STATUS_NONE
|
2514 GDK_IM_STATUS_NOTHING
);
2516 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2517 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2519 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2520 attr
->client_window
= widget
->window
;
2522 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2523 gtk_widget_get_default_colormap ())
2525 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2526 attr
->preedit_colormap
= colormap
;
2529 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2530 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2531 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2532 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2534 switch (style
& GDK_IM_PREEDIT_MASK
)
2536 case GDK_IM_PREEDIT_POSITION
:
2537 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2539 g_warning ("over-the-spot style requires fontset");
2543 gdk_window_get_size (widget
->window
, &width
, &height
);
2545 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2546 attr
->spot_location
.x
= 0;
2547 attr
->spot_location
.y
= height
;
2548 attr
->preedit_area
.x
= 0;
2549 attr
->preedit_area
.y
= 0;
2550 attr
->preedit_area
.width
= width
;
2551 attr
->preedit_area
.height
= height
;
2552 attr
->preedit_fontset
= widget
->style
->font
;
2557 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2559 if (win
->m_ic
== NULL
)
2560 g_warning ("Can't create input context.");
2563 mask
= gdk_window_get_events (widget
->window
);
2564 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2565 gdk_window_set_events (widget
->window
, mask
);
2567 if (GTK_WIDGET_HAS_FOCUS(widget
))
2568 gdk_im_begin (win
->m_ic
, widget
->window
);
2575 //-----------------------------------------------------------------------------
2576 // InsertChild for wxWindowGTK.
2577 //-----------------------------------------------------------------------------
2579 /* Callback for wxWindowGTK. This very strange beast has to be used because
2580 * C++ has no virtual methods in a constructor. We have to emulate a
2581 * virtual function here as wxNotebook requires a different way to insert
2582 * a child in it. I had opted for creating a wxNotebookPage window class
2583 * which would have made this superfluous (such in the MDI window system),
2584 * but no-one was listening to me... */
2586 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2588 /* the window might have been scrolled already, do we
2589 have to adapt the position */
2590 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2591 child
->m_x
+= pizza
->xoffset
;
2592 child
->m_y
+= pizza
->yoffset
;
2594 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2595 GTK_WIDGET(child
->m_widget
),
2602 //-----------------------------------------------------------------------------
2604 //-----------------------------------------------------------------------------
2606 wxWindow
*wxGetActiveWindow()
2608 return wxWindow::FindFocus();
2611 //-----------------------------------------------------------------------------
2613 //-----------------------------------------------------------------------------
2615 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2617 #ifdef __WXUNIVERSAL__
2618 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2620 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2621 #endif // __WXUNIVERSAL__/__WXGTK__
2623 void wxWindowGTK::Init()
2626 m_widget
= (GtkWidget
*) NULL
;
2627 m_wxwindow
= (GtkWidget
*) NULL
;
2628 m_focusWidget
= (GtkWidget
*) NULL
;
2638 m_needParent
= TRUE
;
2639 m_isBeingDeleted
= FALSE
;
2642 m_nativeSizeEvent
= FALSE
;
2644 m_hasScrolling
= FALSE
;
2645 m_isScrolling
= FALSE
;
2647 m_hAdjust
= (GtkAdjustment
*) NULL
;
2648 m_vAdjust
= (GtkAdjustment
*) NULL
;
2649 m_oldHorizontalPos
=
2650 m_oldVerticalPos
= 0.0;
2652 m_oldClientHeight
= 0;
2656 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2658 m_acceptsFocus
= FALSE
;
2661 m_clipPaintRegion
= FALSE
;
2663 m_cursor
= *wxSTANDARD_CURSOR
;
2667 m_x11Context
= NULL
;
2668 m_dirtyTabOrder
= false;
2671 m_ic
= (GdkIC
*) NULL
;
2672 m_icattr
= (GdkICAttr
*) NULL
;
2677 wxWindowGTK::wxWindowGTK()
2682 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2687 const wxString
&name
)
2691 Create( parent
, id
, pos
, size
, style
, name
);
2694 bool wxWindowGTK::Create( wxWindow
*parent
,
2699 const wxString
&name
)
2701 if (!PreCreation( parent
, pos
, size
) ||
2702 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2704 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2708 m_insertCallback
= wxInsertChildInWindow
;
2710 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2711 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2713 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2715 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2716 scroll_class
->scrollbar_spacing
= 0;
2718 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2720 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2721 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2723 m_wxwindow
= gtk_pizza_new();
2725 #ifndef __WXUNIVERSAL__
2726 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2728 if (HasFlag(wxRAISED_BORDER
))
2730 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2732 else if (HasFlag(wxSUNKEN_BORDER
))
2734 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2736 else if (HasFlag(wxSIMPLE_BORDER
))
2738 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2742 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2744 #endif // __WXUNIVERSAL__
2746 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2748 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2749 m_acceptsFocus
= TRUE
;
2751 // I _really_ don't want scrollbars in the beginning
2752 m_vAdjust
->lower
= 0.0;
2753 m_vAdjust
->upper
= 1.0;
2754 m_vAdjust
->value
= 0.0;
2755 m_vAdjust
->step_increment
= 1.0;
2756 m_vAdjust
->page_increment
= 1.0;
2757 m_vAdjust
->page_size
= 5.0;
2758 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2759 m_hAdjust
->lower
= 0.0;
2760 m_hAdjust
->upper
= 1.0;
2761 m_hAdjust
->value
= 0.0;
2762 m_hAdjust
->step_increment
= 1.0;
2763 m_hAdjust
->page_increment
= 1.0;
2764 m_hAdjust
->page_size
= 5.0;
2765 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2767 // these handlers block mouse events to any window during scrolling such as
2768 // motion events and prevent GTK and wxWidgets from fighting over where the
2771 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2772 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2774 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2775 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2777 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2778 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2780 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2781 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2783 // these handlers get notified when screen updates are required either when
2784 // scrolling or when the window size (and therefore scrollbar configuration)
2787 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2788 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2789 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2790 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2792 gtk_widget_show( m_wxwindow
);
2795 m_parent
->DoAddChild( this );
2797 m_focusWidget
= m_wxwindow
;
2804 wxWindowGTK::~wxWindowGTK()
2808 if (g_focusWindow
== this)
2809 g_focusWindow
= NULL
;
2811 if (g_activeFrame
== this)
2812 g_activeFrame
= NULL
;
2814 if ( g_delayedFocus
== this )
2815 g_delayedFocus
= NULL
;
2817 m_isBeingDeleted
= TRUE
;
2827 gdk_ic_destroy (m_ic
);
2829 gdk_ic_attr_destroy (m_icattr
);
2834 gtk_widget_destroy( m_wxwindow
);
2835 m_wxwindow
= (GtkWidget
*) NULL
;
2840 gtk_widget_destroy( m_widget
);
2841 m_widget
= (GtkWidget
*) NULL
;
2849 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2851 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2853 // Use either the given size, or the default if -1 is given.
2854 // See wxWindowBase for these functions.
2855 m_width
= WidthDefault(size
.x
) ;
2856 m_height
= HeightDefault(size
.y
);
2864 void wxWindowGTK::PostCreation()
2866 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2872 // these get reported to wxWidgets -> wxPaintEvent
2874 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2876 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2877 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2880 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2881 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2883 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2885 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2886 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2889 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2894 // Create input method handler
2895 m_imData
= new wxGtkIMData
;
2897 // Cannot handle drawing preedited text yet
2898 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2900 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2901 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2904 // these are called when the "sunken" or "raised" borders are drawn
2905 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2906 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2909 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2910 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2916 if (m_focusWidget
== NULL
)
2917 m_focusWidget
= m_widget
;
2919 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2920 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2922 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2923 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2925 // connect to the various key and mouse handlers
2927 GtkWidget
*connect_widget
= GetConnectWidget();
2929 ConnectWidget( connect_widget
);
2931 /* We cannot set colours, fonts and cursors before the widget has
2932 been realized, so we do this directly after realization */
2933 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2934 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2938 // Catch native resize events
2939 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2940 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2942 // Initialize XIM support
2943 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2944 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2946 // And resize XIM window
2947 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2948 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2951 if ( !GTK_IS_COMBO(m_widget
))
2953 // This is needed if we want to add our windows into native
2954 // GTK control, such as the toolbar. With this callback, the
2955 // toolbar gets to know the correct size (the one set by the
2956 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2957 // when moving to GTK 2.0.
2958 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2959 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2963 InheritAttributes();
2967 // unless the window was created initially hidden (i.e. Hide() had been
2968 // called before Create()), we should show it at GTK+ level as well
2970 gtk_widget_show( m_widget
);
2973 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2975 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2976 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2978 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2979 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2981 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2982 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2984 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2985 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2987 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2988 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2991 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2992 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2995 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2996 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2998 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2999 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
3002 bool wxWindowGTK::Destroy()
3004 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3008 return wxWindowBase::Destroy();
3011 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
3013 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
3016 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
3018 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3019 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
3022 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
3025 if (m_resizing
) return; /* I don't like recursions */
3028 int currentX
, currentY
;
3029 GetPosition(¤tX
, ¤tY
);
3030 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3032 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3034 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
3036 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
3038 /* don't set the size for children of wxNotebook, just take the values. */
3046 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3047 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
3049 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
3050 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
3054 m_x
= x
+ pizza
->xoffset
;
3055 m_y
= y
+ pizza
->yoffset
;
3058 // calculate the best size if we should auto size the window
3059 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
3060 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
3062 const wxSize sizeBest
= GetBestSize();
3063 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
3065 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
3066 height
= sizeBest
.y
;
3074 int minWidth
= GetMinWidth(),
3075 minHeight
= GetMinHeight(),
3076 maxWidth
= GetMaxWidth(),
3077 maxHeight
= GetMaxHeight();
3079 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3080 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3081 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3082 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3085 int bottom_border
= 0;
3088 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3090 /* the default button has a border around it */
3096 DoMoveWindow( m_x
-border
,
3099 m_height
+border
+bottom_border
);
3104 /* Sometimes the client area changes size without the
3105 whole windows's size changing, but if the whole
3106 windows's size doesn't change, no wxSizeEvent will
3107 normally be sent. Here we add an extra test if
3108 the client test has been changed and this will
3110 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3114 wxPrintf( "OnSize sent from " );
3115 if (GetClassInfo() && GetClassInfo()->GetClassName())
3116 wxPrintf( GetClassInfo()->GetClassName() );
3117 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3120 if (!m_nativeSizeEvent
)
3122 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3123 event
.SetEventObject( this );
3124 GetEventHandler()->ProcessEvent( event
);
3130 void wxWindowGTK::OnInternalIdle()
3133 if ( m_dirtyTabOrder
)
3137 // Update invalidated regions.
3140 // Synthetize activate events.
3141 if ( g_sendActivateEvent
!= -1 )
3143 bool activate
= g_sendActivateEvent
!= 0;
3146 g_sendActivateEvent
= -1;
3148 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
3151 if ( g_activeFrameLostFocus
)
3153 if ( g_activeFrame
)
3155 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3156 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3157 event
.SetEventObject(g_activeFrame
);
3158 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3159 g_activeFrame
= NULL
;
3161 g_activeFrameLostFocus
= FALSE
;
3164 wxCursor cursor
= m_cursor
;
3165 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3169 /* I now set the cursor anew in every OnInternalIdle call
3170 as setting the cursor in a parent window also effects the
3171 windows above so that checking for the current cursor is
3176 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3178 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3180 if (!g_globalCursor
.Ok())
3181 cursor
= *wxSTANDARD_CURSOR
;
3183 window
= m_widget
->window
;
3184 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3185 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3191 GdkWindow
*window
= m_widget
->window
;
3192 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3193 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3198 if (wxUpdateUIEvent::CanUpdate(this))
3199 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3202 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3204 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3206 if (width
) (*width
) = m_width
;
3207 if (height
) (*height
) = m_height
;
3210 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3212 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3216 SetSize( width
, height
);
3223 #ifndef __WXUNIVERSAL__
3224 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3226 /* when using GTK 1.2 we set the shadow border size to 2 */
3230 if (HasFlag(wxSIMPLE_BORDER
))
3232 /* when using GTK 1.2 we set the simple border size to 1 */
3236 #endif // __WXUNIVERSAL__
3240 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3242 GtkRequisition vscroll_req
;
3243 vscroll_req
.width
= 2;
3244 vscroll_req
.height
= 2;
3245 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3246 (scroll_window
->vscrollbar
, &vscroll_req
);
3248 GtkRequisition hscroll_req
;
3249 hscroll_req
.width
= 2;
3250 hscroll_req
.height
= 2;
3251 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3252 (scroll_window
->hscrollbar
, &hscroll_req
);
3254 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3256 if (scroll_window
->vscrollbar_visible
)
3258 dw
+= vscroll_req
.width
;
3259 dw
+= scroll_class
->scrollbar_spacing
;
3262 if (scroll_window
->hscrollbar_visible
)
3264 dh
+= hscroll_req
.height
;
3265 dh
+= scroll_class
->scrollbar_spacing
;
3269 SetSize( width
+dw
, height
+dh
);
3273 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3275 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3279 if (width
) (*width
) = m_width
;
3280 if (height
) (*height
) = m_height
;
3287 #ifndef __WXUNIVERSAL__
3288 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3290 /* when using GTK 1.2 we set the shadow border size to 2 */
3294 if (HasFlag(wxSIMPLE_BORDER
))
3296 /* when using GTK 1.2 we set the simple border size to 1 */
3300 #endif // __WXUNIVERSAL__
3304 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3306 GtkRequisition vscroll_req
;
3307 vscroll_req
.width
= 2;
3308 vscroll_req
.height
= 2;
3309 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3310 (scroll_window
->vscrollbar
, &vscroll_req
);
3312 GtkRequisition hscroll_req
;
3313 hscroll_req
.width
= 2;
3314 hscroll_req
.height
= 2;
3315 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3316 (scroll_window
->hscrollbar
, &hscroll_req
);
3318 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3320 if (scroll_window
->vscrollbar_visible
)
3322 dw
+= vscroll_req
.width
;
3323 dw
+= scroll_class
->scrollbar_spacing
;
3326 if (scroll_window
->hscrollbar_visible
)
3328 dh
+= hscroll_req
.height
;
3329 dh
+= scroll_class
->scrollbar_spacing
;
3333 if (width
) (*width
) = m_width
- dw
;
3334 if (height
) (*height
) = m_height
- dh
;
3338 printf( "GetClientSize, name %s ", GetName().c_str() );
3339 if (width) printf( " width = %d", (*width) );
3340 if (height) printf( " height = %d", (*height) );
3345 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3347 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3351 if (m_parent
&& m_parent
->m_wxwindow
)
3353 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3354 dx
= pizza
->xoffset
;
3355 dy
= pizza
->yoffset
;
3358 if (x
) (*x
) = m_x
- dx
;
3359 if (y
) (*y
) = m_y
- dy
;
3362 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3364 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3366 if (!m_widget
->window
) return;
3368 GdkWindow
*source
= (GdkWindow
*) NULL
;
3370 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3372 source
= m_widget
->window
;
3376 gdk_window_get_origin( source
, &org_x
, &org_y
);
3380 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3382 org_x
+= m_widget
->allocation
.x
;
3383 org_y
+= m_widget
->allocation
.y
;
3391 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3393 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3395 if (!m_widget
->window
) return;
3397 GdkWindow
*source
= (GdkWindow
*) NULL
;
3399 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3401 source
= m_widget
->window
;
3405 gdk_window_get_origin( source
, &org_x
, &org_y
);
3409 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3411 org_x
+= m_widget
->allocation
.x
;
3412 org_y
+= m_widget
->allocation
.y
;
3420 bool wxWindowGTK::Show( bool show
)
3422 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3424 if (!wxWindowBase::Show(show
))
3431 gtk_widget_show( m_widget
);
3433 gtk_widget_hide( m_widget
);
3435 wxShowEvent
eventShow(GetId(), show
);
3436 eventShow
.m_eventObject
= this;
3438 GetEventHandler()->ProcessEvent(eventShow
);
3443 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3445 win
->OnParentEnable(enable
);
3447 // Recurse, so that children have the opportunity to Do The Right Thing
3448 // and reset colours that have been messed up by a parent's (really ancestor's)
3450 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3452 node
= node
->GetNext() )
3454 wxWindow
*child
= node
->GetData();
3455 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3456 wxWindowNotifyEnable(child
, enable
);
3460 bool wxWindowGTK::Enable( bool enable
)
3462 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3464 if (!wxWindowBase::Enable(enable
))
3470 gtk_widget_set_sensitive( m_widget
, enable
);
3472 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3474 wxWindowNotifyEnable(this, enable
);
3479 int wxWindowGTK::GetCharHeight() const
3481 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3483 wxFont font
= GetFont();
3484 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3487 PangoContext
*context
= NULL
;
3489 context
= gtk_widget_get_pango_context( m_widget
);
3494 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3495 PangoLayout
*layout
= pango_layout_new(context
);
3496 pango_layout_set_font_description(layout
, desc
);
3497 pango_layout_set_text(layout
, "H", 1);
3498 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3500 PangoRectangle rect
;
3501 pango_layout_line_get_extents(line
, NULL
, &rect
);
3503 g_object_unref( G_OBJECT( layout
) );
3505 return (int) PANGO_PIXELS(rect
.height
);
3507 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3509 return gfont
->ascent
+ gfont
->descent
;
3513 int wxWindowGTK::GetCharWidth() const
3515 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3517 wxFont font
= GetFont();
3518 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3521 PangoContext
*context
= NULL
;
3523 context
= gtk_widget_get_pango_context( m_widget
);
3528 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3529 PangoLayout
*layout
= pango_layout_new(context
);
3530 pango_layout_set_font_description(layout
, desc
);
3531 pango_layout_set_text(layout
, "g", 1);
3532 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3534 PangoRectangle rect
;
3535 pango_layout_line_get_extents(line
, NULL
, &rect
);
3537 g_object_unref( G_OBJECT( layout
) );
3539 return (int) PANGO_PIXELS(rect
.width
);
3541 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3543 return gdk_string_width( gfont
, "g" );
3547 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3551 int *externalLeading
,
3552 const wxFont
*theFont
) const
3554 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3556 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3558 if (string
.IsEmpty())
3566 PangoContext
*context
= NULL
;
3568 context
= gtk_widget_get_pango_context( m_widget
);
3577 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3578 PangoLayout
*layout
= pango_layout_new(context
);
3579 pango_layout_set_font_description(layout
, desc
);
3582 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3583 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3585 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3586 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3587 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3591 PangoRectangle rect
;
3592 pango_layout_get_extents(layout
, NULL
, &rect
);
3594 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3595 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3598 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3599 int baseline
= pango_layout_iter_get_baseline(iter
);
3600 pango_layout_iter_free(iter
);
3601 *descent
= *y
- PANGO_PIXELS(baseline
);
3603 if (externalLeading
) (*externalLeading
) = 0; // ??
3605 g_object_unref( G_OBJECT( layout
) );
3607 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3608 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3609 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3610 if (descent
) (*descent
) = font
->descent
;
3611 if (externalLeading
) (*externalLeading
) = 0; // ??
3615 void wxWindowGTK::SetFocus()
3617 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3621 // don't do anything if we already have focus
3625 if (gs_inFocusSignalHandler
)
3627 wxLogTrace(TRACE_FOCUS
,
3628 _T("in focus handler, delaying SetFocus(%p)"), this);
3629 g_delayedFocus
= this;
3635 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3637 gtk_widget_grab_focus (m_wxwindow
);
3642 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3644 if (!GTK_WIDGET_REALIZED(m_widget
))
3646 // we can't set the focus to the widget now so we remember that
3647 // it should be focused and will do it later, during the idle
3648 // time, as soon as we can
3649 wxLogTrace(TRACE_FOCUS
,
3650 _T("Delaying setting focus to %s(%s)"),
3651 GetClassInfo()->GetClassName(), GetLabel().c_str());
3653 g_delayedFocus
= this;
3657 wxLogTrace(TRACE_FOCUS
,
3658 _T("Setting focus to %s(%s)"),
3659 GetClassInfo()->GetClassName(), GetLabel().c_str());
3661 gtk_widget_grab_focus (m_widget
);
3664 else if (GTK_IS_CONTAINER(m_widget
))
3666 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3670 wxLogTrace(TRACE_FOCUS
,
3671 _T("Can't set focus to %s(%s)"),
3672 GetClassInfo()->GetClassName(), GetLabel().c_str());
3677 bool wxWindowGTK::AcceptsFocus() const
3679 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3682 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3684 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3686 wxWindowGTK
*oldParent
= m_parent
,
3687 *newParent
= (wxWindowGTK
*)newParentBase
;
3689 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3691 if ( !wxWindowBase::Reparent(newParent
) )
3694 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3696 /* prevent GTK from deleting the widget arbitrarily */
3697 gtk_widget_ref( m_widget
);
3701 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3704 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3708 /* insert GTK representation */
3709 (*(newParent
->m_insertCallback
))(newParent
, this);
3712 /* reverse: prevent GTK from deleting the widget arbitrarily */
3713 gtk_widget_unref( m_widget
);
3718 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3720 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3722 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3724 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3729 /* insert GTK representation */
3730 (*m_insertCallback
)(this, child
);
3735 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3737 wxWindowBase::AddChild(child
);
3738 m_dirtyTabOrder
= true;
3740 wxapp_install_idle_handler();
3743 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3745 wxWindowBase::RemoveChild(child
);
3746 m_dirtyTabOrder
= true;
3748 wxapp_install_idle_handler();
3751 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3753 wxWindowBase::DoMoveInTabOrder(win
, move
);
3754 m_dirtyTabOrder
= true;
3756 wxapp_install_idle_handler();
3759 void wxWindowGTK::RealizeTabOrder()
3763 if (m_children
.size() > 0)
3765 GList
*chain
= NULL
;
3767 for (wxWindowList::const_iterator i
= m_children
.begin();
3768 i
!= m_children
.end(); ++i
)
3770 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3773 chain
= g_list_reverse(chain
);
3775 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3780 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3784 m_dirtyTabOrder
= false;
3787 #endif // __WXGTK20__
3789 void wxWindowGTK::Raise()
3791 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3793 if (!m_widget
->window
) return;
3795 gdk_window_raise( m_widget
->window
);
3798 void wxWindowGTK::Lower()
3800 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3802 if (!m_widget
->window
) return;
3804 gdk_window_lower( m_widget
->window
);
3807 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3809 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3811 if (cursor
== m_cursor
)
3815 wxapp_install_idle_handler();
3817 if (cursor
== wxNullCursor
)
3818 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3820 return wxWindowBase::SetCursor( cursor
);
3823 void wxWindowGTK::WarpPointer( int x
, int y
)
3825 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3827 // We provide this function ourselves as it is
3828 // missing in GDK (top of this file).
3830 GdkWindow
*window
= (GdkWindow
*) NULL
;
3832 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3834 window
= GetConnectWidget()->window
;
3837 gdk_window_warp_pointer( window
, x
, y
);
3841 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3843 if (!m_widget
) return;
3844 if (!m_widget
->window
) return;
3848 wxapp_install_idle_handler();
3850 wxRect
myRect(0,0,0,0);
3851 if (m_wxwindow
&& rect
)
3853 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3854 m_wxwindow
->allocation
.height
));
3855 myRect
.Intersect(*rect
);
3856 if (!myRect
.width
|| !myRect
.height
)
3857 // nothing to do, rectangle is empty
3862 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3866 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3867 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3871 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3872 m_clearRegion
.Clear();
3873 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3881 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3882 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3886 GdkRectangle gdk_rect
;
3887 gdk_rect
.x
= rect
->x
;
3888 gdk_rect
.y
= rect
->y
;
3889 gdk_rect
.width
= rect
->width
;
3890 gdk_rect
.height
= rect
->height
;
3891 gtk_widget_draw( m_widget
, &gdk_rect
);
3898 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3899 m_updateRegion
.Clear();
3900 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3904 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3912 GdkRectangle gdk_rect
;
3913 gdk_rect
.x
= rect
->x
;
3914 gdk_rect
.y
= rect
->y
;
3915 gdk_rect
.width
= rect
->width
;
3916 gdk_rect
.height
= rect
->height
;
3917 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3921 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3927 void wxWindowGTK::Update()
3932 void wxWindowGTK::GtkUpdate()
3935 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3936 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3938 if (!m_updateRegion
.IsEmpty())
3939 GtkSendPaintEvents();
3943 void wxWindowGTK::GtkSendPaintEvents()
3948 m_clearRegion
.Clear();
3950 m_updateRegion
.Clear();
3954 // Clip to paint region in wxClientDC
3955 m_clipPaintRegion
= TRUE
;
3957 // widget to draw on
3958 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3960 if (GetThemeEnabled())
3962 // find ancestor from which to steal background
3963 wxWindow
*parent
= GetParent();
3964 while (parent
&& !parent
->IsTopLevel())
3965 parent
= parent
->GetParent();
3967 parent
= (wxWindow
*)this;
3969 wxRegionIterator
upd( m_updateRegion
);
3973 rect
.x
= upd
.GetX();
3974 rect
.y
= upd
.GetY();
3975 rect
.width
= upd
.GetWidth();
3976 rect
.height
= upd
.GetHeight();
3978 gtk_paint_flat_box( parent
->m_widget
->style
,
3980 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3994 wxWindowDC
dc( (wxWindow
*)this );
3995 dc
.SetClippingRegion( m_updateRegion
);
3997 wxEraseEvent
erase_event( GetId(), &dc
);
3998 erase_event
.SetEventObject( this );
4000 GetEventHandler()->ProcessEvent(erase_event
);
4003 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
4005 wxWindowDC
dc( (wxWindow
*)this );
4006 if (m_clearRegion
.IsEmpty())
4007 dc
.SetClippingRegion( m_updateRegion
);
4009 dc
.SetClippingRegion( m_clearRegion
);
4011 wxEraseEvent
erase_event( GetId(), &dc
);
4012 erase_event
.SetEventObject( this );
4014 if (!GetEventHandler()->ProcessEvent(erase_event
))
4018 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
4019 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4021 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
4023 wxRegionIterator
upd( m_clearRegion
);
4026 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
4027 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
4031 m_clearRegion
.Clear();
4035 wxNcPaintEvent
nc_paint_event( GetId() );
4036 nc_paint_event
.SetEventObject( this );
4037 GetEventHandler()->ProcessEvent( nc_paint_event
);
4039 wxPaintEvent
paint_event( GetId() );
4040 paint_event
.SetEventObject( this );
4041 GetEventHandler()->ProcessEvent( paint_event
);
4043 m_clipPaintRegion
= FALSE
;
4045 #ifndef __WXUNIVERSAL__
4047 // The following code will result in all window-less widgets
4048 // being redrawn because the wxWidgets class is allowed to
4049 // paint over the window-less widgets.
4051 GList
*children
= pizza
->children
;
4054 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
4055 children
= children
->next
;
4057 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
4058 GTK_WIDGET_DRAWABLE (child
->widget
))
4060 // Get intersection of widget area and update region
4061 wxRegion
region( m_updateRegion
);
4063 GdkEventExpose gdk_event
;
4064 gdk_event
.type
= GDK_EXPOSE
;
4065 gdk_event
.window
= pizza
->bin_window
;
4066 gdk_event
.count
= 0;
4068 wxRegionIterator
upd( m_updateRegion
);
4072 rect
.x
= upd
.GetX();
4073 rect
.y
= upd
.GetY();
4074 rect
.width
= upd
.GetWidth();
4075 rect
.height
= upd
.GetHeight();
4077 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
4079 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
4089 m_updateRegion
.Clear();
4092 void wxWindowGTK::ClearBackground()
4094 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4097 if (m_wxwindow
&& m_wxwindow
->window
)
4099 m_clearRegion
.Clear();
4100 wxSize
size( GetClientSize() );
4101 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4103 // Better do this in idle?
4110 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4112 wxWindowBase::DoSetToolTip(tip
);
4115 m_tooltip
->Apply( (wxWindow
*)this );
4118 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4120 wxString
tmp( tip
);
4121 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4123 #endif // wxUSE_TOOLTIPS
4125 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4127 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4129 if (!wxWindowBase::SetBackgroundColour(colour
))
4134 // We need the pixel value e.g. for background clearing.
4135 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4138 // apply style change (forceStyle=true so that new style is applied
4139 // even if the bg colour changed from valid to wxNullColour):
4140 ApplyWidgetStyle(true);
4145 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4147 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4149 if (!wxWindowBase::SetForegroundColour(colour
))
4156 // We need the pixel value e.g. for background clearing.
4157 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4160 // apply style change (forceStyle=true so that new style is applied
4161 // even if the bg colour changed from valid to wxNullColour):
4162 ApplyWidgetStyle(true);
4168 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4170 return gtk_widget_get_pango_context( m_widget
);
4173 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4176 m_x11Context
= pango_x_get_context( gdk_display
);
4178 return m_x11Context
;
4182 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4184 // do we need to apply any changes at all?
4187 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4192 GtkRcStyle
*style
= gtk_rc_style_new();
4198 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4200 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4201 style
->fontset_name
= g_strdup(xfontname
.c_str());
4205 if ( m_foregroundColour
.Ok() )
4207 GdkColor
*fg
= m_foregroundColour
.GetColor();
4209 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4210 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4212 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4213 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4215 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4216 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4219 if ( m_backgroundColour
.Ok() )
4221 GdkColor
*bg
= m_backgroundColour
.GetColor();
4223 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4224 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4225 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4226 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4228 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4229 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4230 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4231 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4233 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4234 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4235 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4236 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4238 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4239 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4240 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4241 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4247 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4249 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4252 DoApplyWidgetStyle(style
);
4253 gtk_rc_style_unref(style
);
4257 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4260 gtk_widget_modify_style(m_wxwindow
, style
);
4261 gtk_widget_modify_style(m_widget
, style
);
4265 //-----------------------------------------------------------------------------
4266 // Pop-up menu stuff
4267 //-----------------------------------------------------------------------------
4269 #if wxUSE_MENUS_NATIVE
4272 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4274 *is_waiting
= FALSE
;
4277 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4279 menu
->SetInvokingWindow( win
);
4280 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4283 wxMenuItem
*menuitem
= node
->GetData();
4284 if (menuitem
->IsSubMenu())
4286 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4289 node
= node
->GetNext();
4293 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4296 gboolean
* WXUNUSED(whatever
),
4298 gpointer user_data
)
4300 // ensure that the menu appears entirely on screen
4302 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4304 wxSize sizeScreen
= wxGetDisplaySize();
4305 wxPoint
*pos
= (wxPoint
*)user_data
;
4307 gint xmax
= sizeScreen
.x
- req
.width
,
4308 ymax
= sizeScreen
.y
- req
.height
;
4310 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4311 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4314 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4316 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4318 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4320 SetInvokingWindow( menu
, this );
4324 bool is_waiting
= true;
4326 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4328 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4329 (gpointer
)&is_waiting
);
4333 GtkMenuPositionFunc posfunc
;
4334 if ( x
== -1 && y
== -1 )
4336 // use GTK's default positioning algorithm
4342 pos
= ClientToScreen(wxPoint(x
, y
));
4344 posfunc
= wxPopupMenuPositionCallback
;
4348 GTK_MENU(menu
->m_menu
),
4349 (GtkWidget
*) NULL
, // parent menu shell
4350 (GtkWidget
*) NULL
, // parent menu item
4351 posfunc
, // function to position it
4352 userdata
, // client data
4353 0, // button used to activate it
4355 gtk_get_current_event_time()
4357 gs_timeLastClick
// the time of activation
4363 gtk_main_iteration();
4369 #endif // wxUSE_MENUS_NATIVE
4371 #if wxUSE_DRAG_AND_DROP
4373 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4375 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4377 GtkWidget
*dnd_widget
= GetConnectWidget();
4379 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4381 if (m_dropTarget
) delete m_dropTarget
;
4382 m_dropTarget
= dropTarget
;
4384 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4387 #endif // wxUSE_DRAG_AND_DROP
4389 GtkWidget
* wxWindowGTK::GetConnectWidget()
4391 GtkWidget
*connect_widget
= m_widget
;
4392 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4394 return connect_widget
;
4397 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4400 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4402 return (window
== m_widget
->window
);
4405 bool wxWindowGTK::SetFont( const wxFont
&font
)
4407 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4409 if (!wxWindowBase::SetFont(font
))
4412 // apply style change (forceStyle=true so that new style is applied
4413 // even if the font changed from valid to wxNullFont):
4414 ApplyWidgetStyle(true);
4419 void wxWindowGTK::DoCaptureMouse()
4421 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4423 GdkWindow
*window
= (GdkWindow
*) NULL
;
4425 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4427 window
= GetConnectWidget()->window
;
4429 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4431 wxCursor
* cursor
= & m_cursor
;
4433 cursor
= wxSTANDARD_CURSOR
;
4435 gdk_pointer_grab( window
, FALSE
,
4437 (GDK_BUTTON_PRESS_MASK
|
4438 GDK_BUTTON_RELEASE_MASK
|
4439 GDK_POINTER_MOTION_HINT_MASK
|
4440 GDK_POINTER_MOTION_MASK
),
4442 cursor
->GetCursor(),
4443 (guint32
)GDK_CURRENT_TIME
);
4444 g_captureWindow
= this;
4445 g_captureWindowHasMouse
= TRUE
;
4448 void wxWindowGTK::DoReleaseMouse()
4450 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4452 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4454 g_captureWindow
= (wxWindowGTK
*) NULL
;
4456 GdkWindow
*window
= (GdkWindow
*) NULL
;
4458 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4460 window
= GetConnectWidget()->window
;
4465 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4469 wxWindow
*wxWindowBase::GetCapture()
4471 return (wxWindow
*)g_captureWindow
;
4474 bool wxWindowGTK::IsRetained() const
4479 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4480 int range
, bool refresh
)
4482 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4484 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4486 m_hasScrolling
= TRUE
;
4488 if (orient
== wxHORIZONTAL
)
4490 float fpos
= (float)pos
;
4491 float frange
= (float)range
;
4492 float fthumb
= (float)thumbVisible
;
4493 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4494 if (fpos
< 0.0) fpos
= 0.0;
4496 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4497 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4499 SetScrollPos( orient
, pos
, refresh
);
4503 m_oldHorizontalPos
= fpos
;
4505 m_hAdjust
->lower
= 0.0;
4506 m_hAdjust
->upper
= frange
;
4507 m_hAdjust
->value
= fpos
;
4508 m_hAdjust
->step_increment
= 1.0;
4509 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4510 m_hAdjust
->page_size
= fthumb
;
4514 float fpos
= (float)pos
;
4515 float frange
= (float)range
;
4516 float fthumb
= (float)thumbVisible
;
4517 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4518 if (fpos
< 0.0) fpos
= 0.0;
4520 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4521 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4523 SetScrollPos( orient
, pos
, refresh
);
4527 m_oldVerticalPos
= fpos
;
4529 m_vAdjust
->lower
= 0.0;
4530 m_vAdjust
->upper
= frange
;
4531 m_vAdjust
->value
= fpos
;
4532 m_vAdjust
->step_increment
= 1.0;
4533 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4534 m_vAdjust
->page_size
= fthumb
;
4537 if (orient
== wxHORIZONTAL
)
4538 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4540 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4543 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4545 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4547 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4549 if (orient
== wxHORIZONTAL
)
4551 float fpos
= (float)pos
;
4552 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4553 if (fpos
< 0.0) fpos
= 0.0;
4554 m_oldHorizontalPos
= fpos
;
4556 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4557 m_hAdjust
->value
= fpos
;
4561 float fpos
= (float)pos
;
4562 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4563 if (fpos
< 0.0) fpos
= 0.0;
4564 m_oldVerticalPos
= fpos
;
4566 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4567 m_vAdjust
->value
= fpos
;
4570 if (m_wxwindow
->window
)
4572 if (orient
== wxHORIZONTAL
)
4574 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4575 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4577 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4579 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4580 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4584 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4585 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4587 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4589 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4590 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4595 int wxWindowGTK::GetScrollThumb( int orient
) const
4597 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4599 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4601 if (orient
== wxHORIZONTAL
)
4602 return (int)(m_hAdjust
->page_size
+0.5);
4604 return (int)(m_vAdjust
->page_size
+0.5);
4607 int wxWindowGTK::GetScrollPos( int orient
) const
4609 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4611 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4613 if (orient
== wxHORIZONTAL
)
4614 return (int)(m_hAdjust
->value
+0.5);
4616 return (int)(m_vAdjust
->value
+0.5);
4619 int wxWindowGTK::GetScrollRange( int orient
) const
4621 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4623 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4625 if (orient
== wxHORIZONTAL
)
4626 return (int)(m_hAdjust
->upper
+0.5);
4628 return (int)(m_vAdjust
->upper
+0.5);
4631 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4633 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4635 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4637 // No scrolling requested.
4638 if ((dx
== 0) && (dy
== 0)) return;
4641 if (!m_updateRegion
.IsEmpty())
4643 m_updateRegion
.Offset( dx
, dy
);
4647 GetClientSize( &cw
, &ch
);
4648 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4651 if (!m_clearRegion
.IsEmpty())
4653 m_clearRegion
.Offset( dx
, dy
);
4657 GetClientSize( &cw
, &ch
);
4658 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4662 m_clipPaintRegion
= TRUE
;
4664 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4666 m_clipPaintRegion
= FALSE
;
4670 // Find the wxWindow at the current mouse position, also returning the mouse
4672 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4674 pt
= wxGetMousePosition();
4675 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4679 // Get the current mouse position.
4680 wxPoint
wxGetMousePosition()
4682 /* This crashes when used within wxHelpContext,
4683 so we have to use the X-specific implementation below.
4685 GdkModifierType *mask;
4686 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4688 return wxPoint(x, y);
4692 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4694 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4695 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4696 Window rootReturn
, childReturn
;
4697 int rootX
, rootY
, winX
, winY
;
4698 unsigned int maskReturn
;
4700 XQueryPointer (display
,
4704 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4705 return wxPoint(rootX
, rootY
);
4709 // ----------------------------------------------------------------------------
4711 // ----------------------------------------------------------------------------
4713 class wxWinModule
: public wxModule
4720 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4723 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4725 bool wxWinModule::OnInit()
4727 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4728 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4733 void wxWinModule::OnExit()
4736 gdk_gc_unref( g_eraseGC
);