1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
19 #define XWarpPointer XWARPPOINTER
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
26 #include "wx/layout.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
32 #if wxUSE_DRAG_AND_DROP
37 #include "wx/tooltip.h"
45 #include "wx/textctrl.h"
49 #include "wx/statusbr.h"
51 #include "wx/settings.h"
53 #include "wx/fontutil.h"
56 #include "wx/thread.h"
62 #include "wx/gtk/private.h"
63 #include <gdk/gdkprivate.h>
64 #include <gdk/gdkkeysyms.h>
68 #include <gtk/gtkprivate.h>
70 #include "wx/gtk/win_gtk.h"
73 #include <pango/pangox.h>
77 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
79 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
89 extern GtkContainerClass
*pizza_parent_class
;
92 //-----------------------------------------------------------------------------
93 // documentation on internals
94 //-----------------------------------------------------------------------------
97 I have been asked several times about writing some documentation about
98 the GTK port of wxWindows, especially its internal structures. Obviously,
99 you cannot understand wxGTK without knowing a little about the GTK, but
100 some more information about what the wxWindow, which is the base class
101 for all other window classes, does seems required as well.
105 What does wxWindow do? It contains the common interface for the following
106 jobs of its descendants:
108 1) Define the rudimentary behaviour common to all window classes, such as
109 resizing, intercepting user input (so as to make it possible to use these
110 events for special purposes in a derived class), window names etc.
112 2) Provide the possibility to contain and manage children, if the derived
113 class is allowed to contain children, which holds true for those window
114 classes which do not display a native GTK widget. To name them, these
115 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
116 work classes are a special case and are handled a bit differently from
117 the rest. The same holds true for the wxNotebook class.
119 3) Provide the possibility to draw into a client area of a window. This,
120 too, only holds true for classes that do not display a native GTK widget
123 4) Provide the entire mechanism for scrolling widgets. This actual inter-
124 face for this is usually in wxScrolledWindow, but the GTK implementation
127 5) A multitude of helper or extra methods for special purposes, such as
128 Drag'n'Drop, managing validators etc.
130 6) Display a border (sunken, raised, simple or none).
132 Normally one might expect, that one wxWindows window would always correspond
133 to one GTK widget. Under GTK, there is no such allround widget that has all
134 the functionality. Moreover, the GTK defines a client area as a different
135 widget from the actual widget you are handling. Last but not least some
136 special classes (e.g. wxFrame) handle different categories of widgets and
137 still have the possibility to draw something in the client area.
138 It was therefore required to write a special purpose GTK widget, that would
139 represent a client area in the sense of wxWindows capable to do the jobs
140 2), 3) and 4). I have written this class and it resides in win_gtk.c of
143 All windows must have a widget, with which they interact with other under-
144 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
145 thw wxWindow class has a member variable called m_widget which holds a
146 pointer to this widget. When the window class represents a GTK native widget,
147 this is (in most cases) the only GTK widget the class manages. E.g. the
148 wxStatitText class handles only a GtkLabel widget a pointer to which you
149 can find in m_widget (defined in wxWindow)
151 When the class has a client area for drawing into and for containing children
152 it has to handle the client area widget (of the type GtkPizza, defined in
153 win_gtk.c), but there could be any number of widgets, handled by a class
154 The common rule for all windows is only, that the widget that interacts with
155 the rest of GTK must be referenced in m_widget and all other widgets must be
156 children of this widget on the GTK level. The top-most widget, which also
157 represents the client area, must be in the m_wxwindow field and must be of
160 As I said, the window classes that display a GTK native widget only have
161 one widget, so in the case of e.g. the wxButton class m_widget holds a
162 pointer to a GtkButton widget. But windows with client areas (for drawing
163 and children) have a m_widget field that is a pointer to a GtkScrolled-
164 Window and a m_wxwindow field that is pointer to a GtkPizza and this
165 one is (in the GTK sense) a child of the GtkScrolledWindow.
167 If the m_wxwindow field is set, then all input to this widget is inter-
168 cepted and sent to the wxWindows class. If not, all input to the widget
169 that gets pointed to by m_widget gets intercepted and sent to the class.
173 The design of scrolling in wxWindows is markedly different from that offered
174 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
175 clicking on a scrollbar belonging to scrolled window will inevitably move
176 the window. In wxWindows, the scrollbar will only emit an event, send this
177 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
178 which actually moves the window and its subchildren. Note that GtkPizza
179 memorizes how much it has been scrolled but that wxWindows forgets this
180 so that the two coordinates systems have to be kept in synch. This is done
181 in various places using the pizza->xoffset and pizza->yoffset values.
185 Singularily the most broken code in GTK is the code that is supposes to
186 inform subwindows (child windows) about new positions. Very often, duplicate
187 events are sent without changes in size or position, equally often no
188 events are sent at all (All this is due to a bug in the GtkContainer code
189 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
190 GTK's own system and it simply waits for size events for toplevel windows
191 and then iterates down the respective size events to all window. This has
192 the disadvantage, that windows might get size events before the GTK widget
193 actually has the reported size. This doesn't normally pose any problem, but
194 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
195 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
196 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
197 window that is used for OpenGl output really has that size (as reported by
202 If someone at some point of time feels the immense desire to have a look at,
203 change or attempt to optimse the Refresh() logic, this person will need an
204 intimate understanding of what a "draw" and what an "expose" events are and
205 what there are used for, in particular when used in connection with GTK's
206 own windowless widgets. Beware.
210 Cursors, too, have been a constant source of pleasure. The main difficulty
211 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
212 for the parent. To prevent this from doing too much harm, I use idle time
213 to set the cursor over and over again, starting from the toplevel windows
214 and ending with the youngest generation (speaking of parent and child windows).
215 Also don't forget that cursors (like much else) are connected to GdkWindows,
216 not GtkWidgets and that the "window" field of a GtkWidget might very well
217 point to the GdkWindow of the parent widget (-> "window less widget") and
218 that the two obviously have very different meanings.
222 //-----------------------------------------------------------------------------
224 //-----------------------------------------------------------------------------
226 extern wxList wxPendingDelete
;
227 extern bool g_blockEventsOnDrag
;
228 extern bool g_blockEventsOnScroll
;
229 extern wxCursor g_globalCursor
;
231 static GdkGC
*g_eraseGC
= NULL
;
233 // mouse capture state: the window which has it and if the mouse is currently
235 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
236 static bool g_captureWindowHasMouse
= FALSE
;
238 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
240 // the last window which had the focus - this is normally never NULL (except
241 // if we never had focus at all) as even when g_focusWindow is NULL it still
242 // keeps its previous value
243 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
245 // the frame that is currently active (i.e. its child has focus). It is
246 // used to generate wxActivateEvents
247 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
248 static bool g_activeFrameLostFocus
= FALSE
;
250 // If a window get the focus set but has not been realized
251 // yet, defer setting the focus to idle time.
252 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
254 // if we detect that the app has got/lost the focus, we set this variable to
255 // either TRUE or FALSE and an activate event will be sent during the next
256 // OnIdle() call and it is reset to -1: this value means that we shouldn't
257 // send any activate events at all
258 static int g_sendActivateEvent
= -1;
260 // hack: we need something to pass to gtk_menu_popup, so we store the time of
261 // the last click here
262 static guint32 gs_timeLastClick
= 0;
264 extern bool g_mainThreadLocked
;
266 //-----------------------------------------------------------------------------
268 //-----------------------------------------------------------------------------
271 #define DISABLE_STYLE_IF_BROKEN_THEME 0
277 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
279 # define DEBUG_MAIN_THREAD
282 #define DEBUG_MAIN_THREAD
285 // the trace mask used for the focus debugging messages
286 #define TRACE_FOCUS _T("focus")
288 //-----------------------------------------------------------------------------
289 // missing gdk functions
290 //-----------------------------------------------------------------------------
293 gdk_window_warp_pointer (GdkWindow
*window
,
298 GdkWindowPrivate
*priv
;
302 window
= GDK_ROOT_PARENT();
305 if (!GDK_WINDOW_DESTROYED(window
))
307 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
308 None
, /* not source window -> move from anywhere */
309 GDK_WINDOW_XID(window
), /* dest window */
310 0, 0, 0, 0, /* not source window -> move from anywhere */
314 priv
= (GdkWindowPrivate
*) window
;
316 if (!priv
->destroyed
)
318 XWarpPointer (priv
->xdisplay
,
319 None
, /* not source window -> move from anywhere */
320 priv
->xwindow
, /* dest window */
321 0, 0, 0, 0, /* not source window -> move from anywhere */
327 //-----------------------------------------------------------------------------
329 //-----------------------------------------------------------------------------
331 extern void wxapp_install_idle_handler();
332 extern bool g_isIdle
;
334 //-----------------------------------------------------------------------------
335 // local code (see below)
336 //-----------------------------------------------------------------------------
338 // returns the child of win which currently has focus or NULL if not found
340 // Note: can't be static, needed by textctrl.cpp.
341 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
343 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
345 return (wxWindow
*)NULL
;
347 if ( winFocus
== win
)
348 return (wxWindow
*)win
;
350 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
352 node
= node
->GetNext() )
354 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
359 return (wxWindow
*)NULL
;
362 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
364 // wxUniversal widgets draw the borders and scrollbars themselves
365 #ifndef __WXUNIVERSAL__
372 if (win
->m_hasScrolling
)
374 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
376 GtkRequisition vscroll_req
;
377 vscroll_req
.width
= 2;
378 vscroll_req
.height
= 2;
379 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
380 (scroll_window
->vscrollbar
, &vscroll_req
);
382 GtkRequisition hscroll_req
;
383 hscroll_req
.width
= 2;
384 hscroll_req
.height
= 2;
385 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
386 (scroll_window
->hscrollbar
, &hscroll_req
);
388 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
390 if (scroll_window
->vscrollbar_visible
)
392 dw
+= vscroll_req
.width
;
393 dw
+= scroll_class
->scrollbar_spacing
;
396 if (scroll_window
->hscrollbar_visible
)
398 dh
+= hscroll_req
.height
;
399 dh
+= scroll_class
->scrollbar_spacing
;
405 if (GTK_WIDGET_NO_WINDOW (widget
))
407 dx
+= widget
->allocation
.x
;
408 dy
+= widget
->allocation
.y
;
411 if (win
->HasFlag(wxRAISED_BORDER
))
413 gtk_draw_shadow( widget
->style
,
418 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
422 if (win
->HasFlag(wxSUNKEN_BORDER
))
424 gtk_draw_shadow( widget
->style
,
429 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
433 if (win
->HasFlag(wxSIMPLE_BORDER
))
436 gc
= gdk_gc_new( widget
->window
);
437 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
438 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
440 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
444 #endif // __WXUNIVERSAL__
447 //-----------------------------------------------------------------------------
448 // "expose_event" of m_widget
449 //-----------------------------------------------------------------------------
451 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
453 if (gdk_event
->count
> 0) return FALSE
;
455 draw_frame( widget
, win
);
459 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
465 //-----------------------------------------------------------------------------
466 // "draw" of m_widget
467 //-----------------------------------------------------------------------------
471 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
473 draw_frame( widget
, win
);
478 //-----------------------------------------------------------------------------
479 // "size_request" of m_widget
480 //-----------------------------------------------------------------------------
482 // make it extern because wxStatitText needs to disconnect this one
484 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
485 GtkRequisition
*requisition
,
489 win
->GetSize( &w
, &h
);
495 requisition
->height
= h
;
496 requisition
->width
= w
;
499 //-----------------------------------------------------------------------------
500 // "expose_event" of m_wxwindow
501 //-----------------------------------------------------------------------------
503 static int gtk_window_expose_callback( GtkWidget
*widget
,
504 GdkEventExpose
*gdk_event
,
510 wxapp_install_idle_handler();
513 // This callback gets called in drawing-idle time under
514 // GTK 2.0, so we don't need to defer anything to idle
517 GtkPizza
*pizza
= GTK_PIZZA( widget
);
518 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
523 wxPrintf( wxT("OnExpose from ") );
524 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
525 wxPrintf( win
->GetClassInfo()->GetClassName() );
526 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
527 (int)gdk_event
->area
.y
,
528 (int)gdk_event
->area
.width
,
529 (int)gdk_event
->area
.height
);
534 win
->m_wxwindow
->style
,
538 (GdkRectangle
*) NULL
,
540 (char *)"button", // const_cast
545 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
547 win
->GtkSendPaintEvents();
550 // Let parent window draw window less widgets
551 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
553 // This gets called immediately after an expose event
554 // under GTK 1.2 so we collect the calls and wait for
555 // the idle handler to pick things up.
557 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
559 gdk_event
->area
.width
,
560 gdk_event
->area
.height
);
561 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
563 gdk_event
->area
.width
,
564 gdk_event
->area
.height
);
566 // Actual redrawing takes place in idle time.
573 //-----------------------------------------------------------------------------
574 // "event" of m_wxwindow
575 //-----------------------------------------------------------------------------
577 // GTK thinks it is clever and filters out a certain amount of "unneeded"
578 // expose events. We need them, of course, so we override the main event
579 // procedure in GtkWidget by giving our own handler for all system events.
580 // There, we look for expose events ourselves whereas all other events are
583 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
584 GdkEventExpose
*event
,
587 if (event
->type
== GDK_EXPOSE
)
589 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
596 //-----------------------------------------------------------------------------
597 // "draw" of m_wxwindow
598 //-----------------------------------------------------------------------------
602 // This callback is a complete replacement of the gtk_pizza_draw() function,
603 // which is disabled.
605 static void gtk_window_draw_callback( GtkWidget
*widget
,
612 wxapp_install_idle_handler();
614 // if there are any children we must refresh everything
617 if ( !win
->HasFlag(wxFULL_REPAINT_ON_RESIZE
) &&
618 win
->GetChildren().IsEmpty() )
626 wxPrintf( wxT("OnDraw from ") );
627 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
628 wxPrintf( win
->GetClassInfo()->GetClassName() );
629 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
636 #ifndef __WXUNIVERSAL__
637 GtkPizza
*pizza
= GTK_PIZZA (widget
);
639 if (win
->GetThemeEnabled())
641 wxWindow
*parent
= win
->GetParent();
642 while (parent
&& !parent
->IsTopLevel())
643 parent
= parent
->GetParent();
647 gtk_paint_flat_box (parent
->m_widget
->style
,
658 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
659 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
661 // Update immediately, not in idle time.
664 #ifndef __WXUNIVERSAL__
665 // Redraw child widgets
666 GList
*children
= pizza
->children
;
669 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
670 children
= children
->next
;
672 GdkRectangle child_area
;
673 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
675 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
683 //-----------------------------------------------------------------------------
684 // "key_press_event" from any window
685 //-----------------------------------------------------------------------------
687 // set WXTRACE to this to see the key event codes on the console
688 #define TRACE_KEYS _T("keyevent")
690 // translates an X key symbol to WXK_XXX value
692 // if isChar is true it means that the value returned will be used for EVT_CHAR
693 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
694 // for example, while if it is false it means that the value is going to be
695 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
697 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
703 // Shift, Control and Alt don't generate the CHAR events at all
706 key_code
= isChar
? 0 : WXK_SHIFT
;
710 key_code
= isChar
? 0 : WXK_CONTROL
;
718 key_code
= isChar
? 0 : WXK_ALT
;
721 // neither do the toggle modifies
722 case GDK_Scroll_Lock
:
723 key_code
= isChar
? 0 : WXK_SCROLL
;
727 key_code
= isChar
? 0 : WXK_CAPITAL
;
731 key_code
= isChar
? 0 : WXK_NUMLOCK
;
735 // various other special keys
748 case GDK_ISO_Left_Tab
:
755 key_code
= WXK_RETURN
;
759 key_code
= WXK_CLEAR
;
763 key_code
= WXK_PAUSE
;
767 key_code
= WXK_SELECT
;
771 key_code
= WXK_PRINT
;
775 key_code
= WXK_EXECUTE
;
779 key_code
= WXK_ESCAPE
;
782 // cursor and other extended keyboard keys
784 key_code
= WXK_DELETE
;
800 key_code
= WXK_RIGHT
;
807 case GDK_Prior
: // == GDK_Page_Up
808 key_code
= WXK_PRIOR
;
811 case GDK_Next
: // == GDK_Page_Down
824 key_code
= WXK_INSERT
;
839 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
843 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
847 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
851 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
855 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
859 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
863 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
867 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
871 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
875 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
879 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
883 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
887 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
890 case GDK_KP_Prior
: // == GDK_KP_Page_Up
891 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
894 case GDK_KP_Next
: // == GDK_KP_Page_Down
895 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
899 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
903 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
907 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
911 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
915 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
918 case GDK_KP_Multiply
:
919 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
923 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
926 case GDK_KP_Separator
:
927 // FIXME: what is this?
928 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
931 case GDK_KP_Subtract
:
932 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
936 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
940 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
957 key_code
= WXK_F1
+ keysym
- GDK_F1
;
967 static inline bool wxIsAsciiKeysym(KeySym ks
)
973 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
975 GdkEventKey
*gdk_event
)
977 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
978 // but only event->keyval which is quite useless to us, so remember
979 // the last character from GDK_KEY_PRESS and reuse it as last resort
981 // NB: should be MT-safe as we're always called from the main thread only
986 } s_lastKeyPress
= { 0, 0 };
988 KeySym keysym
= gdk_event
->keyval
;
990 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
991 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
995 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
999 // do we have the translation or is it a plain ASCII character?
1000 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1002 // we should use keysym if it is ASCII as X does some translations
1003 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1004 // which we don't want here (but which we do use for OnChar())
1005 if ( !wxIsAsciiKeysym(keysym
) )
1007 keysym
= (KeySym
)gdk_event
->string
[0];
1010 // we want to always get the same key code when the same key is
1011 // pressed regardless of the state of the modifies, i.e. on a
1012 // standard US keyboard pressing '5' or '%' ('5' key with
1013 // Shift) should result in the same key code in OnKeyDown():
1014 // '5' (although OnChar() will get either '5' or '%').
1016 // to do it we first translate keysym to keycode (== scan code)
1017 // and then back but always using the lower register
1018 Display
*dpy
= (Display
*)wxGetDisplay();
1019 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1021 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1023 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1025 // use the normalized, i.e. lower register, keysym if we've
1027 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1029 // as explained above, we want to have lower register key codes
1030 // normally but for the letter keys we want to have the upper ones
1032 // NB: don't use XConvertCase() here, we want to do it for letters
1034 key_code
= toupper(key_code
);
1036 else // non ASCII key, what to do?
1038 // by default, ignore it
1041 // but if we have cached information from the last KEY_PRESS
1042 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1045 if ( keysym
== s_lastKeyPress
.keysym
)
1047 key_code
= s_lastKeyPress
.keycode
;
1052 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1054 // remember it to be reused for KEY_UP event later
1055 s_lastKeyPress
.keysym
= keysym
;
1056 s_lastKeyPress
.keycode
= key_code
;
1060 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1062 // sending unknown key events doesn't really make sense
1066 // now fill all the other fields
1069 GdkModifierType state
;
1070 if (gdk_event
->window
)
1071 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1073 event
.SetTimestamp( gdk_event
->time
);
1074 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1075 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1076 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1077 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1078 event
.m_keyCode
= key_code
;
1079 event
.m_scanCode
= gdk_event
->keyval
;
1080 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1081 event
.m_rawFlags
= 0;
1084 event
.SetEventObject( win
);
1090 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1091 GdkEventKey
*gdk_event
,
1097 wxapp_install_idle_handler();
1101 if (g_blockEventsOnDrag
)
1105 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1106 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1108 // unknown key pressed, ignore (the event would be useless anyhow)
1112 // Emit KEY_DOWN event
1113 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1118 wxWindowGTK
*ancestor
= win
;
1121 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1124 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1125 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1128 if (ancestor
->IsTopLevel())
1130 ancestor
= ancestor
->GetParent();
1133 #endif // wxUSE_ACCEL
1135 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1136 // will only be sent if it is not in an accelerator table.
1140 KeySym keysym
= gdk_event
->keyval
;
1142 // In GTK 2.0, we need to hand over the key event to an input method
1143 // and the IM will emit a "commit" event containing the actual utf8
1144 // character. In that case the EVT_CHAR events will be sent from
1145 // there. But only do it this way for non-KeySym keys.
1146 key_code
= wxTranslateKeySymToWXKey(gdk_event
->keyval
, FALSE
/* isChar */);
1147 if ( !key_code
&& win
->m_imContext
)
1149 gtk_im_context_filter_keypress ( (GtkIMContext
*) win
->m_imContext
, gdk_event
);
1155 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1156 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1159 if ( gdk_event
->length
== 1 )
1161 key_code
= (unsigned char)gdk_event
->string
[0];
1163 else if ( wxIsAsciiKeysym(keysym
) )
1166 key_code
= (unsigned char)keysym
;
1172 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1174 event
.m_keyCode
= key_code
;
1176 // Implement OnCharHook by checking ancesteror top level windows
1177 wxWindow
*parent
= win
;
1178 while (parent
&& !parent
->IsTopLevel())
1179 parent
= parent
->GetParent();
1182 event
.SetEventType( wxEVT_CHAR_HOOK
);
1183 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1188 event
.SetEventType(wxEVT_CHAR
);
1189 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1195 // win is a control: tab can be propagated up
1197 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1198 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1199 // have this style, yet choose not to process this particular TAB in which
1200 // case TAB must still work as a navigational character
1202 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1204 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1206 wxNavigationKeyEvent new_event
;
1207 new_event
.SetEventObject( win
->GetParent() );
1208 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1209 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1210 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1211 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1212 new_event
.SetCurrentFocus( win
);
1213 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1216 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1218 (gdk_event
->keyval
== GDK_Escape
) )
1220 // however only do it if we have a Cancel button in the dialog,
1221 // otherwise the user code may get confused by the events from a
1222 // non-existing button and, worse, a wxButton might get button event
1223 // from another button which is not really expected
1224 wxWindow
*winForCancel
= win
,
1226 while ( winForCancel
)
1228 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1231 // found a cancel button
1235 if ( winForCancel
->IsTopLevel() )
1237 // no need to look further
1241 // maybe our parent has a cancel button?
1242 winForCancel
= winForCancel
->GetParent();
1247 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1248 event
.SetEventObject(btnCancel
);
1249 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1255 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1263 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1269 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1272 event
.m_uniChar
= g_utf8_get_char( str
);
1274 // Backward compatible for ISO-8859
1275 if (event
.m_uniChar
< 256)
1276 event
.m_keyCode
= event
.m_uniChar
;
1278 gunichar uniChar
= g_utf8_get_char( str
);
1279 // We cannot handle Unicode in non-Unicode mode
1280 if (uniChar
> 255) return;
1282 event
.m_keyCode
= uniChar
;
1286 // TODO: We still need to set all the extra attributes of the
1287 // event, modifiers and such...
1290 // Implement OnCharHook by checking ancestor top level windows
1291 wxWindow
*parent
= window
;
1292 while (parent
&& !parent
->IsTopLevel())
1293 parent
= parent
->GetParent();
1296 event
.SetEventType( wxEVT_CHAR_HOOK
);
1297 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1302 event
.SetEventType(wxEVT_CHAR
);
1303 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1309 //-----------------------------------------------------------------------------
1310 // "key_release_event" from any window
1311 //-----------------------------------------------------------------------------
1313 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1314 GdkEventKey
*gdk_event
,
1320 wxapp_install_idle_handler();
1325 if (g_blockEventsOnDrag
)
1328 wxKeyEvent
event( wxEVT_KEY_UP
);
1329 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1331 // unknown key pressed, ignore (the event would be useless anyhow
1335 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1338 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1342 // ============================================================================
1344 // ============================================================================
1346 // ----------------------------------------------------------------------------
1347 // mouse event processing helpers
1348 // ----------------------------------------------------------------------------
1350 // init wxMouseEvent with the info from gdk_event
1352 // NB: this has to be a macro as gdk_event type is different for different
1353 // events we're used with
1354 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1355 /* wxMouseEvent& */ event, \
1356 /* GdkEventXXX * */ gdk_event) \
1358 event.SetTimestamp( gdk_event->time ); \
1359 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1360 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1361 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1362 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1363 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1364 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1365 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1366 if (event.GetEventType()==wxEVT_MOUSEWHEEL) \
1368 if (((GdkEventButton*)gdk_event)->button == 4) \
1369 event.m_wheelRotation = 120; \
1370 else if (((GdkEventButton*)gdk_event)->button == 5) \
1371 event.m_wheelRotation = -120; \
1374 wxPoint pt = win->GetClientAreaOrigin(); \
1375 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1376 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1378 event.SetEventObject( win ); \
1379 event.SetId( win->GetId() ); \
1380 event.SetTimestamp( gdk_event->time ); \
1383 static void AdjustEventButtonState(wxMouseEvent& event)
1385 // GDK reports the old state of the button for a button press event, but
1386 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1387 // for a LEFT_DOWN event, not FALSE, so we will invert
1388 // left/right/middleDown for the corresponding click events
1390 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1391 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1392 (event
.GetEventType() == wxEVT_LEFT_UP
))
1394 event
.m_leftDown
= !event
.m_leftDown
;
1398 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1399 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1400 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1402 event
.m_middleDown
= !event
.m_middleDown
;
1406 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1407 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1408 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1410 event
.m_rightDown
= !event
.m_rightDown
;
1415 // find the window to send the mouse event too
1417 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1422 if (win
->m_wxwindow
)
1424 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1425 xx
+= pizza
->xoffset
;
1426 yy
+= pizza
->yoffset
;
1429 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1432 wxWindowGTK
*child
= node
->GetData();
1434 node
= node
->GetNext();
1435 if (!child
->IsShown())
1438 if (child
->IsTransparentForMouse())
1440 // wxStaticBox is transparent in the box itself
1441 int xx1
= child
->m_x
;
1442 int yy1
= child
->m_y
;
1443 int xx2
= child
->m_x
+ child
->m_width
;
1444 int yy2
= child
->m_y
+ child
->m_height
;
1447 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1449 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1451 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1453 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1464 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1465 (child
->m_x
<= xx
) &&
1466 (child
->m_y
<= yy
) &&
1467 (child
->m_x
+child
->m_width
>= xx
) &&
1468 (child
->m_y
+child
->m_height
>= yy
))
1481 //-----------------------------------------------------------------------------
1482 // "button_press_event"
1483 //-----------------------------------------------------------------------------
1485 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1486 GdkEventButton
*gdk_event
,
1492 wxapp_install_idle_handler();
1495 wxPrintf( wxT("1) OnButtonPress from ") );
1496 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1497 wxPrintf( win->GetClassInfo()->GetClassName() );
1498 wxPrintf( wxT(".\n") );
1500 if (!win
->m_hasVMT
) return FALSE
;
1501 if (g_blockEventsOnDrag
) return TRUE
;
1502 if (g_blockEventsOnScroll
) return TRUE
;
1504 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1506 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1508 gtk_widget_grab_focus( win
->m_wxwindow
);
1510 wxPrintf( wxT("GrabFocus from ") );
1511 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1512 wxPrintf( win->GetClassInfo()->GetClassName() );
1513 wxPrintf( wxT(".\n") );
1517 // GDK sends surplus button down event
1518 // before a double click event. We
1519 // need to filter these out.
1520 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1522 GdkEvent
*peek_event
= gdk_event_peek();
1525 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1526 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1528 gdk_event_free( peek_event
);
1533 gdk_event_free( peek_event
);
1538 wxEventType event_type
= wxEVT_NULL
;
1540 if (gdk_event
->button
== 1)
1542 // note that GDK generates triple click events which are not supported
1543 // by wxWindows but still have to be passed to the app as otherwise
1544 // clicks would simply go missing
1545 switch (gdk_event
->type
)
1547 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1548 case GDK_BUTTON_PRESS
:
1549 event_type
= wxEVT_LEFT_DOWN
;
1552 case GDK_2BUTTON_PRESS
:
1553 event_type
= wxEVT_LEFT_DCLICK
;
1557 // just to silence gcc warnings
1561 else if (gdk_event
->button
== 2)
1563 switch (gdk_event
->type
)
1565 case GDK_BUTTON_PRESS
:
1566 event_type
= wxEVT_MIDDLE_DOWN
;
1569 case GDK_2BUTTON_PRESS
:
1570 event_type
= wxEVT_MIDDLE_DCLICK
;
1577 else if (gdk_event
->button
== 3)
1579 switch (gdk_event
->type
)
1581 case GDK_BUTTON_PRESS
:
1582 event_type
= wxEVT_RIGHT_DOWN
;
1585 case GDK_2BUTTON_PRESS
:
1586 event_type
= wxEVT_RIGHT_DCLICK
;
1593 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1595 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1597 event_type
= wxEVT_MOUSEWHEEL
;
1601 if ( event_type
== wxEVT_NULL
)
1603 // unknown mouse button or click type
1607 wxMouseEvent
event( event_type
);
1608 InitMouseEvent( win
, event
, gdk_event
);
1610 AdjustEventButtonState(event
);
1612 // wxListBox actually get mouse events from the item, so we need to give it
1613 // a chance to correct this
1614 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1616 // find the correct window to send the event too: it may be a different one
1617 // from the one which got it at GTK+ level because some control don't have
1618 // their own X window and thus cannot get any events.
1619 if ( !g_captureWindow
)
1620 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1622 gs_timeLastClick
= gdk_event
->time
;
1625 wxPrintf( wxT("2) OnButtonPress from ") );
1626 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1627 wxPrintf( win->GetClassInfo()->GetClassName() );
1628 wxPrintf( wxT(".\n") );
1632 if (event_type
== wxEVT_LEFT_DCLICK
)
1634 // GTK 1.2 crashes when intercepting double
1635 // click events from both wxSpinButton and
1637 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1639 // Just disable this event for now.
1645 if (win
->GetEventHandler()->ProcessEvent( event
))
1647 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1654 //-----------------------------------------------------------------------------
1655 // "button_release_event"
1656 //-----------------------------------------------------------------------------
1658 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1659 GdkEventButton
*gdk_event
,
1665 wxapp_install_idle_handler();
1667 if (!win
->m_hasVMT
) return FALSE
;
1668 if (g_blockEventsOnDrag
) return FALSE
;
1669 if (g_blockEventsOnScroll
) return FALSE
;
1671 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1673 wxEventType event_type
= wxEVT_NULL
;
1675 switch (gdk_event
->button
)
1678 event_type
= wxEVT_LEFT_UP
;
1682 event_type
= wxEVT_MIDDLE_UP
;
1686 event_type
= wxEVT_RIGHT_UP
;
1690 // unknwon button, don't process
1694 wxMouseEvent
event( event_type
);
1695 InitMouseEvent( win
, event
, gdk_event
);
1697 AdjustEventButtonState(event
);
1699 // same wxListBox hack as above
1700 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1702 if ( event_type
== wxEVT_RIGHT_UP
)
1704 // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
1707 // (a) it's a command event and so is propagated to the parent
1708 // (b) under MSW it can be generated from kbd too
1709 // (c) it uses screen coords (because of (a))
1710 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1712 win
->ClientToScreen(event
.GetPosition()));
1713 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1716 if ( !g_captureWindow
)
1717 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1719 if (win
->GetEventHandler()->ProcessEvent( event
))
1721 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1728 //-----------------------------------------------------------------------------
1729 // "motion_notify_event"
1730 //-----------------------------------------------------------------------------
1732 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1733 GdkEventMotion
*gdk_event
,
1739 wxapp_install_idle_handler();
1741 if (!win
->m_hasVMT
) return FALSE
;
1742 if (g_blockEventsOnDrag
) return FALSE
;
1743 if (g_blockEventsOnScroll
) return FALSE
;
1745 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1747 if (gdk_event
->is_hint
)
1751 GdkModifierType state
;
1752 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1758 printf( "OnMotion from " );
1759 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1760 printf( win->GetClassInfo()->GetClassName() );
1764 wxMouseEvent
event( wxEVT_MOTION
);
1765 InitMouseEvent(win
, event
, gdk_event
);
1767 if ( g_captureWindow
)
1769 // synthetize a mouse enter or leave event if needed
1770 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1771 // This seems to be necessary and actually been added to
1772 // GDK itself in version 2.0.X
1775 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1776 if ( hasMouse
!= g_captureWindowHasMouse
)
1778 // the mouse changed window
1779 g_captureWindowHasMouse
= hasMouse
;
1781 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1782 : wxEVT_LEAVE_WINDOW
);
1783 InitMouseEvent(win
, event
, gdk_event
);
1784 event
.SetEventObject(win
);
1785 win
->GetEventHandler()->ProcessEvent(event
);
1790 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1793 if (win
->GetEventHandler()->ProcessEvent( event
))
1795 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1803 //-----------------------------------------------------------------------------
1804 // "mouse_wheel_event"
1805 //-----------------------------------------------------------------------------
1807 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1808 GdkEventScroll
* gdk_event
,
1814 wxapp_install_idle_handler();
1816 wxEventType event_type
= wxEVT_NULL
;
1817 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1818 event_type
= wxEVT_MOUSEWHEEL
;
1819 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1820 event_type
= wxEVT_MOUSEWHEEL
;
1824 wxMouseEvent
event( event_type
);
1825 // Can't use InitMouse macro because scroll events don't have button
1826 event
.SetTimestamp( gdk_event
->time
);
1827 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1828 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1829 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1830 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1831 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1832 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1833 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1834 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1835 event
.m_wheelRotation
= 120;
1837 event
.m_wheelRotation
= -120;
1839 wxPoint pt
= win
->GetClientAreaOrigin();
1840 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1841 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1843 event
.SetEventObject( win
);
1844 event
.SetId( win
->GetId() );
1845 event
.SetTimestamp( gdk_event
->time
);
1847 if (win
->GetEventHandler()->ProcessEvent( event
))
1849 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1857 //-----------------------------------------------------------------------------
1859 //-----------------------------------------------------------------------------
1861 // send the wxChildFocusEvent and wxFocusEvent, common code of
1862 // gtk_window_focus_in_callback() and SetFocus()
1863 static bool DoSendFocusEvents(wxWindow
*win
)
1865 // Notify the parent keeping track of focus for the kbd navigation
1866 // purposes that we got it.
1867 wxChildFocusEvent
eventChildFocus(win
);
1868 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1870 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1871 eventFocus
.SetEventObject(win
);
1873 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1876 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1877 GdkEvent
*WXUNUSED(event
),
1883 wxapp_install_idle_handler();
1885 if (!win
->m_hasVMT
) return FALSE
;
1886 if (g_blockEventsOnDrag
) return FALSE
;
1888 switch ( g_sendActivateEvent
)
1891 // we've got focus from outside, synthetize wxActivateEvent
1892 g_sendActivateEvent
= 1;
1896 // another our window just lost focus, it was already ours before
1897 // - don't send any wxActivateEvent
1898 g_sendActivateEvent
= -1;
1903 g_focusWindow
= win
;
1905 wxLogTrace(TRACE_FOCUS
,
1906 _T("%s: focus in"), win
->GetName().c_str());
1910 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1914 // caret needs to be informed about focus change
1915 wxCaret
*caret
= win
->GetCaret();
1918 caret
->OnSetFocus();
1920 #endif // wxUSE_CARET
1922 g_activeFrameLostFocus
= FALSE
;
1924 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1925 if ( active
!= g_activeFrame
)
1927 if ( g_activeFrame
)
1929 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1930 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1931 event
.SetEventObject(g_activeFrame
);
1932 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1935 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1936 g_activeFrame
= active
;
1937 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1938 event
.SetEventObject(g_activeFrame
);
1939 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1941 // Don't send focus events in addition to activate
1942 // if (win == g_activeFrame)
1946 // does the window itself think that it has the focus?
1947 if ( !win
->m_hasFocus
)
1949 // not yet, notify it
1950 win
->m_hasFocus
= TRUE
;
1952 if ( DoSendFocusEvents(win
) )
1954 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1962 //-----------------------------------------------------------------------------
1963 // "focus_out_event"
1964 //-----------------------------------------------------------------------------
1966 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1971 wxapp_install_idle_handler();
1973 if (!win
->m_hasVMT
) return FALSE
;
1974 if (g_blockEventsOnDrag
) return FALSE
;
1976 wxLogTrace( TRACE_FOCUS
,
1977 _T("%s: focus out"), win
->GetName().c_str() );
1979 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1981 // VZ: commenting this out because it does happen (although not easy
1982 // to reproduce, I only see it when using wxMiniFrame and not
1983 // always) and makes using Mahogany quite annoying
1985 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1986 wxT("unfocusing window that hasn't gained focus properly") );
1989 g_activeFrameLostFocus
= TRUE
;
1992 // if the focus goes out of our app alltogether, OnIdle() will send
1993 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1994 // g_sendActivateEvent to -1
1995 g_sendActivateEvent
= 0;
1997 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2001 g_focusWindow
= (wxWindowGTK
*)NULL
;
2009 // caret needs to be informed about focus change
2010 wxCaret
*caret
= win
->GetCaret();
2013 caret
->OnKillFocus();
2015 #endif // wxUSE_CARET
2017 // don't send the window a kill focus event if it thinks that it doesn't
2018 // have focus already
2019 if ( win
->m_hasFocus
)
2021 win
->m_hasFocus
= FALSE
;
2023 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2024 event
.SetEventObject( win
);
2026 if (win
->GetEventHandler()->ProcessEvent( event
))
2028 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
2036 //-----------------------------------------------------------------------------
2037 // "enter_notify_event"
2038 //-----------------------------------------------------------------------------
2041 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2042 GdkEventCrossing
*gdk_event
,
2048 wxapp_install_idle_handler();
2050 if (!win
->m_hasVMT
) return FALSE
;
2051 if (g_blockEventsOnDrag
) return FALSE
;
2053 // Event was emitted after a grab
2054 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2056 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2060 GdkModifierType state
= (GdkModifierType
)0;
2062 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2064 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2065 InitMouseEvent(win
, event
, gdk_event
);
2066 wxPoint pt
= win
->GetClientAreaOrigin();
2067 event
.m_x
= x
+ pt
.x
;
2068 event
.m_y
= y
+ pt
.y
;
2070 if (win
->GetEventHandler()->ProcessEvent( event
))
2072 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2079 //-----------------------------------------------------------------------------
2080 // "leave_notify_event"
2081 //-----------------------------------------------------------------------------
2083 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2088 wxapp_install_idle_handler();
2090 if (!win
->m_hasVMT
) return FALSE
;
2091 if (g_blockEventsOnDrag
) return FALSE
;
2093 // Event was emitted after an ungrab
2094 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2096 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2098 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2099 event
.SetTimestamp( gdk_event
->time
);
2100 event
.SetEventObject( win
);
2104 GdkModifierType state
= (GdkModifierType
)0;
2106 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2108 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2109 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2110 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2111 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2112 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2113 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2114 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2116 wxPoint pt
= win
->GetClientAreaOrigin();
2117 event
.m_x
= x
+ pt
.x
;
2118 event
.m_y
= y
+ pt
.y
;
2120 if (win
->GetEventHandler()->ProcessEvent( event
))
2122 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2129 //-----------------------------------------------------------------------------
2130 // "value_changed" from m_vAdjust
2131 //-----------------------------------------------------------------------------
2133 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2140 wxapp_install_idle_handler();
2142 if (g_blockEventsOnDrag
) return;
2144 if (!win
->m_hasVMT
) return;
2146 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2147 if (fabs(diff
) < 0.2) return;
2149 win
->m_oldVerticalPos
= adjust
->value
;
2152 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2154 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2156 int value
= (int)(adjust
->value
+0.5);
2158 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2159 event
.SetEventObject( win
);
2160 win
->GetEventHandler()->ProcessEvent( event
);
2163 //-----------------------------------------------------------------------------
2164 // "value_changed" from m_hAdjust
2165 //-----------------------------------------------------------------------------
2167 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2174 wxapp_install_idle_handler();
2176 if (g_blockEventsOnDrag
) return;
2177 if (!win
->m_hasVMT
) return;
2179 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2180 if (fabs(diff
) < 0.2) return;
2183 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2185 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2187 win
->m_oldHorizontalPos
= adjust
->value
;
2189 int value
= (int)(adjust
->value
+0.5);
2191 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2192 event
.SetEventObject( win
);
2193 win
->GetEventHandler()->ProcessEvent( event
);
2196 //-----------------------------------------------------------------------------
2197 // "button_press_event" from scrollbar
2198 //-----------------------------------------------------------------------------
2200 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2201 GdkEventButton
*gdk_event
,
2207 wxapp_install_idle_handler();
2210 g_blockEventsOnScroll
= TRUE
;
2212 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2214 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2220 //-----------------------------------------------------------------------------
2221 // "button_release_event" from scrollbar
2222 //-----------------------------------------------------------------------------
2224 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2225 GdkEventButton
*WXUNUSED(gdk_event
),
2230 // don't test here as we can release the mouse while being over
2231 // a different window than the slider
2233 // if (gdk_event->window != widget->slider) return FALSE;
2235 g_blockEventsOnScroll
= FALSE
;
2237 if (win
->m_isScrolling
)
2239 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2243 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2244 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2246 value
= (int)(win
->m_hAdjust
->value
+0.5);
2249 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2251 value
= (int)(win
->m_vAdjust
->value
+0.5);
2255 wxScrollWinEvent
event( command
, value
, dir
);
2256 event
.SetEventObject( win
);
2257 win
->GetEventHandler()->ProcessEvent( event
);
2260 win
->m_isScrolling
= FALSE
;
2265 // ----------------------------------------------------------------------------
2266 // this wxWindowBase function is implemented here (in platform-specific file)
2267 // because it is static and so couldn't be made virtual
2268 // ----------------------------------------------------------------------------
2270 wxWindow
*wxWindowBase::FindFocus()
2272 // the cast is necessary when we compile in wxUniversal mode
2273 return (wxWindow
*)g_focusWindow
;
2277 //-----------------------------------------------------------------------------
2278 // "realize" from m_widget
2279 //-----------------------------------------------------------------------------
2281 /* We cannot set colours and fonts before the widget has
2282 been realized, so we do this directly after realization. */
2285 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2290 wxapp_install_idle_handler();
2292 if (win
->m_delayedBackgroundColour
&& !win
->GetThemeEnabled())
2293 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2295 if (win
->m_delayedForegroundColour
&& !win
->GetThemeEnabled())
2296 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2299 if (win
->m_imContext
)
2301 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2302 gtk_im_context_set_client_window( (GtkIMContext
*) win
->m_imContext
, pizza
->bin_window
);
2306 wxWindowCreateEvent
event( win
);
2307 event
.SetEventObject( win
);
2308 win
->GetEventHandler()->ProcessEvent( event
);
2313 //-----------------------------------------------------------------------------
2315 //-----------------------------------------------------------------------------
2318 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2319 GtkAllocation
*WXUNUSED(alloc
),
2323 wxapp_install_idle_handler();
2325 if (!win
->m_hasScrolling
) return;
2327 int client_width
= 0;
2328 int client_height
= 0;
2329 win
->GetClientSize( &client_width
, &client_height
);
2330 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2333 win
->m_oldClientWidth
= client_width
;
2334 win
->m_oldClientHeight
= client_height
;
2336 if (!win
->m_nativeSizeEvent
)
2338 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2339 event
.SetEventObject( win
);
2340 win
->GetEventHandler()->ProcessEvent( event
);
2346 #define WXUNUSED_UNLESS_XIM(param) param
2348 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2351 /* Resize XIM window */
2354 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2355 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2356 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2359 wxapp_install_idle_handler();
2365 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2369 gdk_window_get_size (widget
->window
, &width
, &height
);
2370 win
->m_icattr
->preedit_area
.width
= width
;
2371 win
->m_icattr
->preedit_area
.height
= height
;
2372 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2377 //-----------------------------------------------------------------------------
2378 // "realize" from m_wxwindow
2379 //-----------------------------------------------------------------------------
2381 /* Initialize XIM support */
2384 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2385 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2388 wxapp_install_idle_handler();
2391 if (win
->m_ic
) return FALSE
;
2392 if (!widget
) return FALSE
;
2393 if (!gdk_im_ready()) return FALSE
;
2395 win
->m_icattr
= gdk_ic_attr_new();
2396 if (!win
->m_icattr
) return FALSE
;
2400 GdkColormap
*colormap
;
2401 GdkICAttr
*attr
= win
->m_icattr
;
2402 unsigned attrmask
= GDK_IC_ALL_REQ
;
2404 GdkIMStyle supported_style
= (GdkIMStyle
)
2405 (GDK_IM_PREEDIT_NONE
|
2406 GDK_IM_PREEDIT_NOTHING
|
2407 GDK_IM_PREEDIT_POSITION
|
2408 GDK_IM_STATUS_NONE
|
2409 GDK_IM_STATUS_NOTHING
);
2411 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2412 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2414 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2415 attr
->client_window
= widget
->window
;
2417 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2418 gtk_widget_get_default_colormap ())
2420 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2421 attr
->preedit_colormap
= colormap
;
2424 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2425 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2426 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2427 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2429 switch (style
& GDK_IM_PREEDIT_MASK
)
2431 case GDK_IM_PREEDIT_POSITION
:
2432 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2434 g_warning ("over-the-spot style requires fontset");
2438 gdk_window_get_size (widget
->window
, &width
, &height
);
2440 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2441 attr
->spot_location
.x
= 0;
2442 attr
->spot_location
.y
= height
;
2443 attr
->preedit_area
.x
= 0;
2444 attr
->preedit_area
.y
= 0;
2445 attr
->preedit_area
.width
= width
;
2446 attr
->preedit_area
.height
= height
;
2447 attr
->preedit_fontset
= widget
->style
->font
;
2452 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2454 if (win
->m_ic
== NULL
)
2455 g_warning ("Can't create input context.");
2458 mask
= gdk_window_get_events (widget
->window
);
2459 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2460 gdk_window_set_events (widget
->window
, mask
);
2462 if (GTK_WIDGET_HAS_FOCUS(widget
))
2463 gdk_im_begin (win
->m_ic
, widget
->window
);
2470 //-----------------------------------------------------------------------------
2471 // InsertChild for wxWindowGTK.
2472 //-----------------------------------------------------------------------------
2474 /* Callback for wxWindowGTK. This very strange beast has to be used because
2475 * C++ has no virtual methods in a constructor. We have to emulate a
2476 * virtual function here as wxNotebook requires a different way to insert
2477 * a child in it. I had opted for creating a wxNotebookPage window class
2478 * which would have made this superfluous (such in the MDI window system),
2479 * but no-one was listening to me... */
2481 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2483 /* the window might have been scrolled already, do we
2484 have to adapt the position */
2485 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2486 child
->m_x
+= pizza
->xoffset
;
2487 child
->m_y
+= pizza
->yoffset
;
2489 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2490 GTK_WIDGET(child
->m_widget
),
2497 //-----------------------------------------------------------------------------
2499 //-----------------------------------------------------------------------------
2501 wxWindow
*wxGetActiveWindow()
2503 return wxWindow::FindFocus();
2506 //-----------------------------------------------------------------------------
2508 //-----------------------------------------------------------------------------
2510 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2512 #ifdef __WXUNIVERSAL__
2513 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2515 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2516 #endif // __WXUNIVERSAL__/__WXGTK__
2518 void wxWindowGTK::Init()
2521 m_widget
= (GtkWidget
*) NULL
;
2522 m_wxwindow
= (GtkWidget
*) NULL
;
2523 m_focusWidget
= (GtkWidget
*) NULL
;
2533 m_needParent
= TRUE
;
2534 m_isBeingDeleted
= FALSE
;
2537 m_nativeSizeEvent
= FALSE
;
2539 m_hasScrolling
= FALSE
;
2540 m_isScrolling
= FALSE
;
2542 m_hAdjust
= (GtkAdjustment
*) NULL
;
2543 m_vAdjust
= (GtkAdjustment
*) NULL
;
2544 m_oldHorizontalPos
=
2545 m_oldVerticalPos
= 0.0;
2547 m_oldClientHeight
= 0;
2550 m_widgetStyle
= (GtkStyle
*) NULL
;
2552 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2554 m_acceptsFocus
= FALSE
;
2557 m_clipPaintRegion
= FALSE
;
2559 m_cursor
= *wxSTANDARD_CURSOR
;
2561 m_delayedForegroundColour
= FALSE
;
2562 m_delayedBackgroundColour
= FALSE
;
2566 m_x11Context
= NULL
;
2569 m_ic
= (GdkIC
*) NULL
;
2570 m_icattr
= (GdkICAttr
*) NULL
;
2575 wxWindowGTK::wxWindowGTK()
2580 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2585 const wxString
&name
)
2589 Create( parent
, id
, pos
, size
, style
, name
);
2592 bool wxWindowGTK::Create( wxWindow
*parent
,
2597 const wxString
&name
)
2599 if (!PreCreation( parent
, pos
, size
) ||
2600 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2602 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2606 m_insertCallback
= wxInsertChildInWindow
;
2608 // always needed for background clearing
2609 m_delayedBackgroundColour
= TRUE
;
2611 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2612 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2614 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2616 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2617 scroll_class
->scrollbar_spacing
= 0;
2619 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2621 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2622 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2624 m_wxwindow
= gtk_pizza_new();
2626 #ifndef __WXUNIVERSAL__
2627 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2629 if (HasFlag(wxRAISED_BORDER
))
2631 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2633 else if (HasFlag(wxSUNKEN_BORDER
))
2635 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2637 else if (HasFlag(wxSIMPLE_BORDER
))
2639 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2643 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2645 #endif // __WXUNIVERSAL__
2647 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2649 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2650 m_acceptsFocus
= TRUE
;
2652 // I _really_ don't want scrollbars in the beginning
2653 m_vAdjust
->lower
= 0.0;
2654 m_vAdjust
->upper
= 1.0;
2655 m_vAdjust
->value
= 0.0;
2656 m_vAdjust
->step_increment
= 1.0;
2657 m_vAdjust
->page_increment
= 1.0;
2658 m_vAdjust
->page_size
= 5.0;
2659 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2660 m_hAdjust
->lower
= 0.0;
2661 m_hAdjust
->upper
= 1.0;
2662 m_hAdjust
->value
= 0.0;
2663 m_hAdjust
->step_increment
= 1.0;
2664 m_hAdjust
->page_increment
= 1.0;
2665 m_hAdjust
->page_size
= 5.0;
2666 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2668 // these handlers block mouse events to any window during scrolling such as
2669 // motion events and prevent GTK and wxWindows from fighting over where the
2672 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2673 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2675 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2676 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2678 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2679 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2681 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2682 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2684 // these handlers get notified when screen updates are required either when
2685 // scrolling or when the window size (and therefore scrollbar configuration)
2688 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2689 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2690 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2691 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2694 // Create input method handler
2695 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2697 // Cannot handle drawing preedited text yet
2698 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2700 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2701 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2704 gtk_widget_show( m_wxwindow
);
2707 m_parent
->DoAddChild( this );
2709 m_focusWidget
= m_wxwindow
;
2718 wxWindowGTK::~wxWindowGTK()
2722 if (g_focusWindow
== this)
2723 g_focusWindow
= NULL
;
2725 if (g_activeFrame
== this)
2726 g_activeFrame
= NULL
;
2728 if ( g_delayedFocus
== this )
2729 g_delayedFocus
= NULL
;
2731 m_isBeingDeleted
= TRUE
;
2741 gdk_ic_destroy (m_ic
);
2743 gdk_ic_attr_destroy (m_icattr
);
2748 #if DISABLE_STYLE_IF_BROKEN_THEME
2749 // don't delete if it's a pixmap theme style
2750 if (!m_widgetStyle
->engine_data
)
2751 gtk_style_unref( m_widgetStyle
);
2753 m_widgetStyle
= (GtkStyle
*) NULL
;
2758 gtk_widget_destroy( m_wxwindow
);
2759 m_wxwindow
= (GtkWidget
*) NULL
;
2764 gtk_widget_destroy( m_widget
);
2765 m_widget
= (GtkWidget
*) NULL
;
2769 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2771 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2773 // This turns -1 into 30 so that a minimal window is
2774 // visible even although -1,-1 has been given as the
2775 // size of the window. the same trick is used in other
2776 // ports and should make debugging easier.
2777 m_width
= WidthDefault(size
.x
) ;
2778 m_height
= HeightDefault(size
.y
);
2783 // some reasonable defaults
2788 m_x
= (gdk_screen_width () - m_width
) / 2;
2789 if (m_x
< 10) m_x
= 10;
2793 m_y
= (gdk_screen_height () - m_height
) / 2;
2794 if (m_y
< 10) m_y
= 10;
2801 void wxWindowGTK::PostCreation()
2803 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2809 // these get reported to wxWindows -> wxPaintEvent
2811 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2813 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2814 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2817 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2818 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2820 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2822 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2823 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2826 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2830 // Create input method handler
2831 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2833 // Cannot handle drawing preedited text yet
2834 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2836 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2837 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2841 // these are called when the "sunken" or "raised" borders are drawn
2842 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2843 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2846 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2847 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2853 if (m_focusWidget
== NULL
)
2854 m_focusWidget
= m_widget
;
2856 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2857 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2859 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2860 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2862 // connect to the various key and mouse handlers
2864 GtkWidget
*connect_widget
= GetConnectWidget();
2866 ConnectWidget( connect_widget
);
2868 /* We cannot set colours, fonts and cursors before the widget has
2869 been realized, so we do this directly after realization */
2870 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2871 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2875 // Catch native resize events
2876 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2877 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2879 // Initialize XIM support
2880 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2881 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2883 // And resize XIM window
2884 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2885 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2888 if ( !GTK_IS_COMBO(m_widget
))
2890 // This is needed if we want to add our windows into native
2891 // GTK control, such as the toolbar. With this callback, the
2892 // toolbar gets to know the correct size (the one set by the
2893 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2894 // when moving to GTK 2.0.
2895 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2896 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2903 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2905 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2906 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2908 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2909 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2911 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2912 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2914 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2915 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2917 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2918 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2921 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2922 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2925 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2926 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2928 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2929 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2932 bool wxWindowGTK::Destroy()
2934 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2938 return wxWindowBase::Destroy();
2941 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2943 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2946 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2948 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2949 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2952 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2955 if (m_resizing
) return; /* I don't like recursions */
2958 int currentX
, currentY
;
2959 GetPosition(¤tX
, ¤tY
);
2960 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2962 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2964 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2966 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2968 /* don't set the size for children of wxNotebook, just take the values. */
2976 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2977 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2979 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2980 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2984 m_x
= x
+ pizza
->xoffset
;
2985 m_y
= y
+ pizza
->yoffset
;
2987 if (width
!= -1) m_width
= width
;
2988 if (height
!= -1) m_height
= height
;
2990 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2992 if (width
== -1) m_width
= 80;
2995 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2997 if (height
== -1) m_height
= 26;
3000 int minWidth
= GetMinWidth(),
3001 minHeight
= GetMinHeight(),
3002 maxWidth
= GetMaxWidth(),
3003 maxHeight
= GetMaxHeight();
3005 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3006 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3007 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3008 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3011 int bottom_border
= 0;
3014 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3016 /* the default button has a border around it */
3022 DoMoveWindow( m_x
-border
,
3025 m_height
+border
+bottom_border
);
3030 /* Sometimes the client area changes size without the
3031 whole windows's size changing, but if the whole
3032 windows's size doesn't change, no wxSizeEvent will
3033 normally be sent. Here we add an extra test if
3034 the client test has been changed and this will
3036 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3040 wxPrintf( "OnSize sent from " );
3041 if (GetClassInfo() && GetClassInfo()->GetClassName())
3042 wxPrintf( GetClassInfo()->GetClassName() );
3043 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3046 if (!m_nativeSizeEvent
)
3048 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3049 event
.SetEventObject( this );
3050 GetEventHandler()->ProcessEvent( event
);
3056 void wxWindowGTK::OnInternalIdle()
3058 // Update invalidated regions.
3061 // Synthetize activate events.
3062 if ( g_sendActivateEvent
!= -1 )
3064 bool activate
= g_sendActivateEvent
!= 0;
3067 g_sendActivateEvent
= -1;
3069 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
3072 if ( g_activeFrameLostFocus
)
3074 if ( g_activeFrame
)
3076 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3077 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3078 event
.SetEventObject(g_activeFrame
);
3079 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3080 g_activeFrame
= NULL
;
3082 g_activeFrameLostFocus
= FALSE
;
3085 wxCursor cursor
= m_cursor
;
3086 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3090 /* I now set the cursor anew in every OnInternalIdle call
3091 as setting the cursor in a parent window also effects the
3092 windows above so that checking for the current cursor is
3097 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3099 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3101 if (!g_globalCursor
.Ok())
3102 cursor
= *wxSTANDARD_CURSOR
;
3104 window
= m_widget
->window
;
3105 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3106 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3112 GdkWindow
*window
= m_widget
->window
;
3113 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3114 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3119 if (wxUpdateUIEvent::CanUpdate(this))
3120 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3123 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3125 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3127 if (width
) (*width
) = m_width
;
3128 if (height
) (*height
) = m_height
;
3131 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3133 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3137 SetSize( width
, height
);
3144 #ifndef __WXUNIVERSAL__
3145 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3147 /* when using GTK 1.2 we set the shadow border size to 2 */
3151 if (HasFlag(wxSIMPLE_BORDER
))
3153 /* when using GTK 1.2 we set the simple border size to 1 */
3157 #endif // __WXUNIVERSAL__
3161 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3163 GtkRequisition vscroll_req
;
3164 vscroll_req
.width
= 2;
3165 vscroll_req
.height
= 2;
3166 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3167 (scroll_window
->vscrollbar
, &vscroll_req
);
3169 GtkRequisition hscroll_req
;
3170 hscroll_req
.width
= 2;
3171 hscroll_req
.height
= 2;
3172 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3173 (scroll_window
->hscrollbar
, &hscroll_req
);
3175 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3177 if (scroll_window
->vscrollbar_visible
)
3179 dw
+= vscroll_req
.width
;
3180 dw
+= scroll_class
->scrollbar_spacing
;
3183 if (scroll_window
->hscrollbar_visible
)
3185 dh
+= hscroll_req
.height
;
3186 dh
+= scroll_class
->scrollbar_spacing
;
3190 SetSize( width
+dw
, height
+dh
);
3194 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3196 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3200 if (width
) (*width
) = m_width
;
3201 if (height
) (*height
) = m_height
;
3208 #ifndef __WXUNIVERSAL__
3209 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3211 /* when using GTK 1.2 we set the shadow border size to 2 */
3215 if (HasFlag(wxSIMPLE_BORDER
))
3217 /* when using GTK 1.2 we set the simple border size to 1 */
3221 #endif // __WXUNIVERSAL__
3225 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3227 GtkRequisition vscroll_req
;
3228 vscroll_req
.width
= 2;
3229 vscroll_req
.height
= 2;
3230 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3231 (scroll_window
->vscrollbar
, &vscroll_req
);
3233 GtkRequisition hscroll_req
;
3234 hscroll_req
.width
= 2;
3235 hscroll_req
.height
= 2;
3236 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3237 (scroll_window
->hscrollbar
, &hscroll_req
);
3239 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3241 if (scroll_window
->vscrollbar_visible
)
3243 dw
+= vscroll_req
.width
;
3244 dw
+= scroll_class
->scrollbar_spacing
;
3247 if (scroll_window
->hscrollbar_visible
)
3249 dh
+= hscroll_req
.height
;
3250 dh
+= scroll_class
->scrollbar_spacing
;
3254 if (width
) (*width
) = m_width
- dw
;
3255 if (height
) (*height
) = m_height
- dh
;
3259 printf( "GetClientSize, name %s ", GetName().c_str() );
3260 if (width) printf( " width = %d", (*width) );
3261 if (height) printf( " height = %d", (*height) );
3266 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3268 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3272 if (m_parent
&& m_parent
->m_wxwindow
)
3274 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3275 dx
= pizza
->xoffset
;
3276 dy
= pizza
->yoffset
;
3279 if (x
) (*x
) = m_x
- dx
;
3280 if (y
) (*y
) = m_y
- dy
;
3283 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3285 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3287 if (!m_widget
->window
) return;
3289 GdkWindow
*source
= (GdkWindow
*) NULL
;
3291 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3293 source
= m_widget
->window
;
3297 gdk_window_get_origin( source
, &org_x
, &org_y
);
3301 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3303 org_x
+= m_widget
->allocation
.x
;
3304 org_y
+= m_widget
->allocation
.y
;
3312 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3314 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3316 if (!m_widget
->window
) return;
3318 GdkWindow
*source
= (GdkWindow
*) NULL
;
3320 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3322 source
= m_widget
->window
;
3326 gdk_window_get_origin( source
, &org_x
, &org_y
);
3330 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3332 org_x
+= m_widget
->allocation
.x
;
3333 org_y
+= m_widget
->allocation
.y
;
3341 bool wxWindowGTK::Show( bool show
)
3343 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3345 if (!wxWindowBase::Show(show
))
3352 gtk_widget_show( m_widget
);
3354 gtk_widget_hide( m_widget
);
3356 wxShowEvent
eventShow(GetId(), show
);
3357 eventShow
.m_eventObject
= this;
3359 GetEventHandler()->ProcessEvent(eventShow
);
3364 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3366 win
->OnParentEnable(enable
);
3368 // Recurse, so that children have the opportunity to Do The Right Thing
3369 // and reset colours that have been messed up by a parent's (really ancestor's)
3371 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3373 node
= node
->GetNext() )
3375 wxWindow
*child
= node
->GetData();
3376 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3377 wxWindowNotifyEnable(child
, enable
);
3381 bool wxWindowGTK::Enable( bool enable
)
3383 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3385 if (!wxWindowBase::Enable(enable
))
3391 gtk_widget_set_sensitive( m_widget
, enable
);
3393 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3395 wxWindowNotifyEnable(this, enable
);
3400 int wxWindowGTK::GetCharHeight() const
3402 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3404 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3407 PangoContext
*context
= NULL
;
3409 context
= gtk_widget_get_pango_context( m_widget
);
3414 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3415 PangoLayout
*layout
= pango_layout_new(context
);
3416 pango_layout_set_font_description(layout
, desc
);
3417 pango_layout_set_text(layout
, "H", 1);
3418 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3420 PangoRectangle rect
;
3421 pango_layout_line_get_extents(line
, NULL
, &rect
);
3423 g_object_unref( G_OBJECT( layout
) );
3425 return (int) (rect
.height
/ PANGO_SCALE
);
3427 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3429 return font
->ascent
+ font
->descent
;
3433 int wxWindowGTK::GetCharWidth() const
3435 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3437 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3440 PangoContext
*context
= NULL
;
3442 context
= gtk_widget_get_pango_context( m_widget
);
3447 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3448 PangoLayout
*layout
= pango_layout_new(context
);
3449 pango_layout_set_font_description(layout
, desc
);
3450 pango_layout_set_text(layout
, "g", 1);
3451 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3453 PangoRectangle rect
;
3454 pango_layout_line_get_extents(line
, NULL
, &rect
);
3456 g_object_unref( G_OBJECT( layout
) );
3458 return (int) (rect
.width
/ PANGO_SCALE
);
3460 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3462 return gdk_string_width( font
, "g" );
3466 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3470 int *externalLeading
,
3471 const wxFont
*theFont
) const
3473 wxFont fontToUse
= m_font
;
3474 if (theFont
) fontToUse
= *theFont
;
3476 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3478 if (string
.IsEmpty())
3486 PangoContext
*context
= NULL
;
3488 context
= gtk_widget_get_pango_context( m_widget
);
3497 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3498 PangoLayout
*layout
= pango_layout_new(context
);
3499 pango_layout_set_font_description(layout
, desc
);
3502 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3503 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3505 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3506 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3507 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3510 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3512 PangoRectangle rect
;
3513 pango_layout_line_get_extents(line
, NULL
, &rect
);
3515 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3516 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3519 // Do something about metrics here
3522 if (externalLeading
) (*externalLeading
) = 0; // ??
3524 g_object_unref( G_OBJECT( layout
) );
3526 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3527 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3528 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3529 if (descent
) (*descent
) = font
->descent
;
3530 if (externalLeading
) (*externalLeading
) = 0; // ??
3534 void wxWindowGTK::SetFocus()
3536 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3540 // don't do anything if we already have focus
3546 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3548 gtk_widget_grab_focus (m_wxwindow
);
3553 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3555 if (!GTK_WIDGET_REALIZED(m_widget
))
3557 // we can't set the focus to the widget now so we remember that
3558 // it should be focused and will do it later, during the idle
3559 // time, as soon as we can
3560 wxLogTrace(TRACE_FOCUS
,
3561 _T("Delaying setting focus to %s(%s)"),
3562 GetClassInfo()->GetClassName(), GetLabel().c_str());
3564 g_delayedFocus
= this;
3568 wxLogTrace(TRACE_FOCUS
,
3569 _T("Setting focus to %s(%s)"),
3570 GetClassInfo()->GetClassName(), GetLabel().c_str());
3572 gtk_widget_grab_focus (m_widget
);
3575 else if (GTK_IS_CONTAINER(m_widget
))
3577 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3581 wxLogTrace(TRACE_FOCUS
,
3582 _T("Can't set focus to %s(%s)"),
3583 GetClassInfo()->GetClassName(), GetLabel().c_str());
3588 bool wxWindowGTK::AcceptsFocus() const
3590 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3593 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3595 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3597 wxWindowGTK
*oldParent
= m_parent
,
3598 *newParent
= (wxWindowGTK
*)newParentBase
;
3600 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3602 if ( !wxWindowBase::Reparent(newParent
) )
3605 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3607 /* prevent GTK from deleting the widget arbitrarily */
3608 gtk_widget_ref( m_widget
);
3612 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3615 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3619 /* insert GTK representation */
3620 (*(newParent
->m_insertCallback
))(newParent
, this);
3623 /* reverse: prevent GTK from deleting the widget arbitrarily */
3624 gtk_widget_unref( m_widget
);
3629 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3631 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3633 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3635 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3640 /* insert GTK representation */
3641 (*m_insertCallback
)(this, child
);
3644 void wxWindowGTK::Raise()
3646 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3648 if (!m_widget
->window
) return;
3650 gdk_window_raise( m_widget
->window
);
3653 void wxWindowGTK::Lower()
3655 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3657 if (!m_widget
->window
) return;
3659 gdk_window_lower( m_widget
->window
);
3662 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3664 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3666 if (cursor
== m_cursor
)
3670 wxapp_install_idle_handler();
3672 if (cursor
== wxNullCursor
)
3673 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3675 return wxWindowBase::SetCursor( cursor
);
3678 void wxWindowGTK::WarpPointer( int x
, int y
)
3680 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3682 // We provide this function ourselves as it is
3683 // missing in GDK (top of this file).
3685 GdkWindow
*window
= (GdkWindow
*) NULL
;
3687 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3689 window
= GetConnectWidget()->window
;
3692 gdk_window_warp_pointer( window
, x
, y
);
3696 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3698 if (!m_widget
) return;
3699 if (!m_widget
->window
) return;
3703 wxapp_install_idle_handler();
3705 wxRect
myRect(0,0,0,0);
3706 if (m_wxwindow
&& rect
)
3708 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3709 m_wxwindow
->allocation
.height
));
3710 myRect
.Intersect(*rect
);
3711 if (!myRect
.width
|| !myRect
.height
)
3712 // nothing to do, rectangle is empty
3717 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3721 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3722 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3726 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3727 m_clearRegion
.Clear();
3728 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3736 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3737 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3741 GdkRectangle gdk_rect
;
3742 gdk_rect
.x
= rect
->x
;
3743 gdk_rect
.y
= rect
->y
;
3744 gdk_rect
.width
= rect
->width
;
3745 gdk_rect
.height
= rect
->height
;
3746 gtk_widget_draw( m_widget
, &gdk_rect
);
3753 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3754 m_updateRegion
.Clear();
3755 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3759 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3767 GdkRectangle gdk_rect
;
3768 gdk_rect
.x
= rect
->x
;
3769 gdk_rect
.y
= rect
->y
;
3770 gdk_rect
.width
= rect
->width
;
3771 gdk_rect
.height
= rect
->height
;
3772 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3776 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3782 void wxWindowGTK::Update()
3787 void wxWindowGTK::GtkUpdate()
3790 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3791 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3793 if (!m_updateRegion
.IsEmpty())
3794 GtkSendPaintEvents();
3798 void wxWindowGTK::GtkSendPaintEvents()
3803 m_clearRegion
.Clear();
3805 m_updateRegion
.Clear();
3809 // Clip to paint region in wxClientDC
3810 m_clipPaintRegion
= TRUE
;
3813 // widget to draw on
3814 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3816 // later for GTK 2.0, too.
3817 if (GetThemeEnabled())
3819 // find ancestor from which to steal background
3820 wxWindow
*parent
= GetParent();
3821 while (parent
&& !parent
->IsTopLevel())
3822 parent
= parent
->GetParent();
3824 parent
= (wxWindow
*)this;
3826 wxRegionIterator
upd( m_updateRegion
);
3830 rect
.x
= upd
.GetX();
3831 rect
.y
= upd
.GetY();
3832 rect
.width
= upd
.GetWidth();
3833 rect
.height
= upd
.GetHeight();
3835 gtk_paint_flat_box( parent
->m_widget
->style
,
3852 wxWindowDC
dc( (wxWindow
*)this );
3853 dc
.SetClippingRegion( m_updateRegion
);
3855 wxEraseEvent
erase_event( GetId(), &dc
);
3856 erase_event
.SetEventObject( this );
3858 GetEventHandler()->ProcessEvent(erase_event
);
3861 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3863 wxWindowDC
dc( (wxWindow
*)this );
3864 if (m_clearRegion
.IsEmpty())
3865 dc
.SetClippingRegion( m_updateRegion
);
3867 dc
.SetClippingRegion( m_clearRegion
);
3869 wxEraseEvent
erase_event( GetId(), &dc
);
3870 erase_event
.SetEventObject( this );
3872 if (!GetEventHandler()->ProcessEvent(erase_event
))
3876 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3877 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3879 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3881 wxRegionIterator
upd( m_clearRegion
);
3884 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3885 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3889 m_clearRegion
.Clear();
3893 wxNcPaintEvent
nc_paint_event( GetId() );
3894 nc_paint_event
.SetEventObject( this );
3895 GetEventHandler()->ProcessEvent( nc_paint_event
);
3897 wxPaintEvent
paint_event( GetId() );
3898 paint_event
.SetEventObject( this );
3899 GetEventHandler()->ProcessEvent( paint_event
);
3901 m_clipPaintRegion
= FALSE
;
3903 #ifndef __WXUNIVERSAL__
3905 // The following code will result in all window-less widgets
3906 // being redrawn because the wxWindows class is allowed to
3907 // paint over the window-less widgets.
3909 GList
*children
= pizza
->children
;
3912 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3913 children
= children
->next
;
3915 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3916 GTK_WIDGET_DRAWABLE (child
->widget
))
3918 // Get intersection of widget area and update region
3919 wxRegion
region( m_updateRegion
);
3921 GdkEventExpose gdk_event
;
3922 gdk_event
.type
= GDK_EXPOSE
;
3923 gdk_event
.window
= pizza
->bin_window
;
3924 gdk_event
.count
= 0;
3926 wxRegionIterator
upd( m_updateRegion
);
3930 rect
.x
= upd
.GetX();
3931 rect
.y
= upd
.GetY();
3932 rect
.width
= upd
.GetWidth();
3933 rect
.height
= upd
.GetHeight();
3935 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3937 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3947 m_updateRegion
.Clear();
3950 void wxWindowGTK::ClearBackground()
3952 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3955 if (m_wxwindow
&& m_wxwindow
->window
)
3957 m_clearRegion
.Clear();
3958 wxSize
size( GetClientSize() );
3959 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3961 // Better do this in idle?
3968 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3970 wxWindowBase::DoSetToolTip(tip
);
3973 m_tooltip
->Apply( (wxWindow
*)this );
3976 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3978 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3980 #endif // wxUSE_TOOLTIPS
3982 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3984 GdkWindow
*window
= (GdkWindow
*) NULL
;
3986 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3988 window
= GetConnectWidget()->window
;
3992 // We need the pixel value e.g. for background clearing.
3993 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3997 // wxMSW doesn't clear the window here, either.
3998 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
4004 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4006 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4008 if (!wxWindowBase::SetBackgroundColour(colour
))
4011 GdkWindow
*window
= (GdkWindow
*) NULL
;
4013 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4015 window
= GetConnectWidget()->window
;
4019 // indicate that a new style has been set
4020 // but it couldn't get applied as the
4021 // widget hasn't been realized yet.
4022 m_delayedBackgroundColour
= TRUE
;
4027 GtkSetBackgroundColour( colour
);
4033 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
4035 GdkWindow
*window
= (GdkWindow
*) NULL
;
4037 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4039 window
= GetConnectWidget()->window
;
4046 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4048 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4050 if (!wxWindowBase::SetForegroundColour(colour
))
4052 // don't leave if the GTK widget has just
4054 if (!m_delayedForegroundColour
) return FALSE
;
4057 GdkWindow
*window
= (GdkWindow
*) NULL
;
4059 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4061 window
= GetConnectWidget()->window
;
4065 // indicate that a new style has been set
4066 // but it couldn't get applied as the
4067 // widget hasn't been realized yet.
4068 m_delayedForegroundColour
= TRUE
;
4072 GtkSetForegroundColour( colour
);
4079 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4081 return gtk_widget_get_pango_context( m_widget
);
4084 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4087 m_x11Context
= pango_x_get_context( gdk_display
);
4089 return m_x11Context
;
4093 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4097 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4099 // FIXME: no more klass in 2.0
4101 remake
->klass
= m_widgetStyle
->klass
;
4104 gtk_style_unref( m_widgetStyle
);
4105 m_widgetStyle
= remake
;
4109 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4112 def
= gtk_widget_get_default_style();
4114 m_widgetStyle
= gtk_style_copy( def
);
4116 // FIXME: no more klass in 2.0
4118 m_widgetStyle
->klass
= def
->klass
;
4122 return m_widgetStyle
;
4125 void wxWindowGTK::SetWidgetStyle()
4127 #if DISABLE_STYLE_IF_BROKEN_THEME
4128 if (m_widget
->style
->engine_data
)
4130 static bool s_warningPrinted
= FALSE
;
4131 if (!s_warningPrinted
)
4133 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
4134 s_warningPrinted
= TRUE
;
4136 m_widgetStyle
= m_widget
->style
;
4141 GtkStyle
*style
= GetWidgetStyle();
4143 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
4146 pango_font_description_free( style
->font_desc
);
4147 style
->font_desc
= pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4149 gdk_font_unref( style
->font
);
4150 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4154 if (m_foregroundColour
.Ok())
4156 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4157 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4159 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4160 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4161 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4165 // Try to restore the gtk default style. This is still a little
4166 // oversimplified for what is probably really needed here for controls
4167 // other than buttons, but is better than not being able to (re)set a
4168 // control's foreground colour to *wxBLACK -- RL
4169 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4172 def
= gtk_widget_get_default_style();
4174 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4175 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4176 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4180 if (m_backgroundColour
.Ok())
4182 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4183 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4185 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4186 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4187 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4188 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4189 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4190 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4191 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4192 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4196 // Try to restore the gtk default style. This is still a little
4197 // oversimplified for what is probably really needed here for controls
4198 // other than buttons, but is better than not being able to (re)set a
4199 // control's background colour to default grey and means resetting a
4200 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4202 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4205 def
= gtk_widget_get_default_style();
4207 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4208 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4209 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4210 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4211 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4212 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4213 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4214 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4219 void wxWindowGTK::ApplyWidgetStyle()
4223 //-----------------------------------------------------------------------------
4224 // Pop-up menu stuff
4225 //-----------------------------------------------------------------------------
4227 #if wxUSE_MENUS_NATIVE
4230 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4232 *is_waiting
= FALSE
;
4235 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4237 menu
->SetInvokingWindow( win
);
4238 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4241 wxMenuItem
*menuitem
= node
->GetData();
4242 if (menuitem
->IsSubMenu())
4244 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4247 node
= node
->GetNext();
4251 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
4252 // wxPopupMenuPositionCallback()
4254 // should be safe even in the MT case as the user can hardly popup 2 menus
4255 // simultaneously, can he?
4256 static gint gs_pop_x
= 0;
4257 static gint gs_pop_y
= 0;
4259 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4262 gboolean
* WXUNUSED(whatever
),
4264 gpointer
WXUNUSED(user_data
) )
4266 // ensure that the menu appears entirely on screen
4268 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4270 wxSize sizeScreen
= wxGetDisplaySize();
4272 gint xmax
= sizeScreen
.x
- req
.width
,
4273 ymax
= sizeScreen
.y
- req
.height
;
4275 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
4276 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
4279 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4281 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4283 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
4285 SetInvokingWindow( menu
, this );
4291 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
4293 bool is_waiting
= TRUE
;
4295 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4297 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4298 (gpointer
)&is_waiting
);
4301 GTK_MENU(menu
->m_menu
),
4302 (GtkWidget
*) NULL
, // parent menu shell
4303 (GtkWidget
*) NULL
, // parent menu item
4304 wxPopupMenuPositionCallback
, // function to position it
4305 NULL
, // client data
4306 0, // button used to activate it
4308 gtk_get_current_event_time()
4310 gs_timeLastClick
// the time of activation
4316 gtk_main_iteration();
4322 #endif // wxUSE_MENUS_NATIVE
4324 #if wxUSE_DRAG_AND_DROP
4326 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4328 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4330 GtkWidget
*dnd_widget
= GetConnectWidget();
4332 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4334 if (m_dropTarget
) delete m_dropTarget
;
4335 m_dropTarget
= dropTarget
;
4337 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4340 #endif // wxUSE_DRAG_AND_DROP
4342 GtkWidget
* wxWindowGTK::GetConnectWidget()
4344 GtkWidget
*connect_widget
= m_widget
;
4345 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4347 return connect_widget
;
4350 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4353 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4355 return (window
== m_widget
->window
);
4358 bool wxWindowGTK::SetFont( const wxFont
&font
)
4360 if (!wxWindowBase::SetFont(font
) || !m_widget
)
4365 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4366 if ( sysbg
== m_backgroundColour
)
4368 m_backgroundColour
= wxNullColour
;
4370 m_backgroundColour
= sysbg
;
4380 void wxWindowGTK::DoCaptureMouse()
4382 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4384 GdkWindow
*window
= (GdkWindow
*) NULL
;
4386 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4388 window
= GetConnectWidget()->window
;
4390 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4392 wxCursor
* cursor
= & m_cursor
;
4394 cursor
= wxSTANDARD_CURSOR
;
4396 gdk_pointer_grab( window
, FALSE
,
4398 (GDK_BUTTON_PRESS_MASK
|
4399 GDK_BUTTON_RELEASE_MASK
|
4400 GDK_POINTER_MOTION_HINT_MASK
|
4401 GDK_POINTER_MOTION_MASK
),
4403 cursor
->GetCursor(),
4404 (guint32
)GDK_CURRENT_TIME
);
4405 g_captureWindow
= this;
4406 g_captureWindowHasMouse
= TRUE
;
4409 void wxWindowGTK::DoReleaseMouse()
4411 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4413 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4415 g_captureWindow
= (wxWindowGTK
*) NULL
;
4417 GdkWindow
*window
= (GdkWindow
*) NULL
;
4419 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4421 window
= GetConnectWidget()->window
;
4426 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4430 wxWindow
*wxWindowBase::GetCapture()
4432 return (wxWindow
*)g_captureWindow
;
4435 bool wxWindowGTK::IsRetained() const
4440 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4441 int range
, bool refresh
)
4443 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4445 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4447 m_hasScrolling
= TRUE
;
4449 if (orient
== wxHORIZONTAL
)
4451 float fpos
= (float)pos
;
4452 float frange
= (float)range
;
4453 float fthumb
= (float)thumbVisible
;
4454 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4455 if (fpos
< 0.0) fpos
= 0.0;
4457 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4458 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4460 SetScrollPos( orient
, pos
, refresh
);
4464 m_oldHorizontalPos
= fpos
;
4466 m_hAdjust
->lower
= 0.0;
4467 m_hAdjust
->upper
= frange
;
4468 m_hAdjust
->value
= fpos
;
4469 m_hAdjust
->step_increment
= 1.0;
4470 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4471 m_hAdjust
->page_size
= fthumb
;
4475 float fpos
= (float)pos
;
4476 float frange
= (float)range
;
4477 float fthumb
= (float)thumbVisible
;
4478 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4479 if (fpos
< 0.0) fpos
= 0.0;
4481 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4482 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4484 SetScrollPos( orient
, pos
, refresh
);
4488 m_oldVerticalPos
= fpos
;
4490 m_vAdjust
->lower
= 0.0;
4491 m_vAdjust
->upper
= frange
;
4492 m_vAdjust
->value
= fpos
;
4493 m_vAdjust
->step_increment
= 1.0;
4494 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4495 m_vAdjust
->page_size
= fthumb
;
4498 if (orient
== wxHORIZONTAL
)
4499 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4501 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4504 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4506 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4508 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4510 if (orient
== wxHORIZONTAL
)
4512 float fpos
= (float)pos
;
4513 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4514 if (fpos
< 0.0) fpos
= 0.0;
4515 m_oldHorizontalPos
= fpos
;
4517 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4518 m_hAdjust
->value
= fpos
;
4522 float fpos
= (float)pos
;
4523 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4524 if (fpos
< 0.0) fpos
= 0.0;
4525 m_oldVerticalPos
= fpos
;
4527 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4528 m_vAdjust
->value
= fpos
;
4531 if (m_wxwindow
->window
)
4533 if (orient
== wxHORIZONTAL
)
4535 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4536 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4538 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4540 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4541 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4545 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4546 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4548 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4550 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4551 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4556 int wxWindowGTK::GetScrollThumb( int orient
) const
4558 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4560 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4562 if (orient
== wxHORIZONTAL
)
4563 return (int)(m_hAdjust
->page_size
+0.5);
4565 return (int)(m_vAdjust
->page_size
+0.5);
4568 int wxWindowGTK::GetScrollPos( int orient
) const
4570 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4572 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4574 if (orient
== wxHORIZONTAL
)
4575 return (int)(m_hAdjust
->value
+0.5);
4577 return (int)(m_vAdjust
->value
+0.5);
4580 int wxWindowGTK::GetScrollRange( int orient
) const
4582 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4584 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4586 if (orient
== wxHORIZONTAL
)
4587 return (int)(m_hAdjust
->upper
+0.5);
4589 return (int)(m_vAdjust
->upper
+0.5);
4592 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4594 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4596 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4598 // No scrolling requested.
4599 if ((dx
== 0) && (dy
== 0)) return;
4602 if (!m_updateRegion
.IsEmpty())
4604 m_updateRegion
.Offset( dx
, dy
);
4608 GetClientSize( &cw
, &ch
);
4609 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4612 if (!m_clearRegion
.IsEmpty())
4614 m_clearRegion
.Offset( dx
, dy
);
4618 GetClientSize( &cw
, &ch
);
4619 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4623 m_clipPaintRegion
= TRUE
;
4625 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4627 m_clipPaintRegion
= FALSE
;
4631 // Find the wxWindow at the current mouse position, also returning the mouse
4633 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4635 pt
= wxGetMousePosition();
4636 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4640 // Get the current mouse position.
4641 wxPoint
wxGetMousePosition()
4643 /* This crashes when used within wxHelpContext,
4644 so we have to use the X-specific implementation below.
4646 GdkModifierType *mask;
4647 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4649 return wxPoint(x, y);
4653 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4655 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4656 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4657 Window rootReturn
, childReturn
;
4658 int rootX
, rootY
, winX
, winY
;
4659 unsigned int maskReturn
;
4661 XQueryPointer (display
,
4665 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4666 return wxPoint(rootX
, rootY
);
4670 // ----------------------------------------------------------------------------
4672 // ----------------------------------------------------------------------------
4674 class wxWinModule
: public wxModule
4681 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4684 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4686 bool wxWinModule::OnInit()
4688 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4689 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4694 void wxWinModule::OnExit()
4697 gdk_gc_unref( g_eraseGC
);