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 switch (gdk_event
->type
)
1544 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1545 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1546 case GDK_3BUTTON_PRESS
: return FALSE
;
1550 else if (gdk_event
->button
== 2)
1552 switch (gdk_event
->type
)
1554 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1555 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1559 else if (gdk_event
->button
== 3)
1561 switch (gdk_event
->type
)
1563 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1564 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1568 else if (gdk_event
->button
== 4)
1570 switch (gdk_event
->type
)
1572 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1576 else if (gdk_event
->button
== 5)
1578 switch (gdk_event
->type
)
1580 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1585 if ( event_type
== wxEVT_NULL
)
1587 // unknown mouse button or click type
1591 wxMouseEvent
event( event_type
);
1592 InitMouseEvent( win
, event
, gdk_event
);
1594 AdjustEventButtonState(event
);
1596 // wxListBox actually get mouse events from the item, so we need to give it
1597 // a chance to correct this
1598 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1600 // find the correct window to send the event too: it may be a different one
1601 // from the one which got it at GTK+ level because some control don't have
1602 // their own X window and thus cannot get any events.
1603 if ( !g_captureWindow
)
1604 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1606 gs_timeLastClick
= gdk_event
->time
;
1609 wxPrintf( wxT("2) OnButtonPress from ") );
1610 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1611 wxPrintf( win->GetClassInfo()->GetClassName() );
1612 wxPrintf( wxT(".\n") );
1616 if (event_type
== wxEVT_LEFT_DCLICK
)
1618 // GTK 1.2 crashes when intercepting double
1619 // click events from both wxSpinButton and
1621 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1623 // Just disable this event for now.
1629 if (win
->GetEventHandler()->ProcessEvent( event
))
1631 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1638 //-----------------------------------------------------------------------------
1639 // "button_release_event"
1640 //-----------------------------------------------------------------------------
1642 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1643 GdkEventButton
*gdk_event
,
1649 wxapp_install_idle_handler();
1651 if (!win
->m_hasVMT
) return FALSE
;
1652 if (g_blockEventsOnDrag
) return FALSE
;
1653 if (g_blockEventsOnScroll
) return FALSE
;
1655 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1657 wxEventType event_type
= wxEVT_NULL
;
1659 switch (gdk_event
->button
)
1662 event_type
= wxEVT_LEFT_UP
;
1666 event_type
= wxEVT_MIDDLE_UP
;
1670 event_type
= wxEVT_RIGHT_UP
;
1674 // unknwon button, don't process
1678 wxMouseEvent
event( event_type
);
1679 InitMouseEvent( win
, event
, gdk_event
);
1681 AdjustEventButtonState(event
);
1683 // same wxListBox hack as above
1684 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1686 if ( event_type
== wxEVT_RIGHT_UP
)
1688 // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
1691 // (a) it's a command event and so is propagated to the parent
1692 // (b) under MSW it can be generated from kbd too
1693 // (c) it uses screen coords (because of (a))
1694 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1696 win
->ClientToScreen(event
.GetPosition()));
1697 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1700 if ( !g_captureWindow
)
1701 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1703 if (win
->GetEventHandler()->ProcessEvent( event
))
1705 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1712 //-----------------------------------------------------------------------------
1713 // "motion_notify_event"
1714 //-----------------------------------------------------------------------------
1716 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1717 GdkEventMotion
*gdk_event
,
1723 wxapp_install_idle_handler();
1725 if (!win
->m_hasVMT
) return FALSE
;
1726 if (g_blockEventsOnDrag
) return FALSE
;
1727 if (g_blockEventsOnScroll
) return FALSE
;
1729 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1731 if (gdk_event
->is_hint
)
1735 GdkModifierType state
;
1736 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1742 printf( "OnMotion from " );
1743 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1744 printf( win->GetClassInfo()->GetClassName() );
1748 wxMouseEvent
event( wxEVT_MOTION
);
1749 InitMouseEvent(win
, event
, gdk_event
);
1751 if ( g_captureWindow
)
1753 // synthetize a mouse enter or leave event if needed
1754 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1755 // This seems to be necessary and actually been added to
1756 // GDK itself in version 2.0.X
1759 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1760 if ( hasMouse
!= g_captureWindowHasMouse
)
1762 // the mouse changed window
1763 g_captureWindowHasMouse
= hasMouse
;
1765 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1766 : wxEVT_LEAVE_WINDOW
);
1767 InitMouseEvent(win
, event
, gdk_event
);
1768 event
.SetEventObject(win
);
1769 win
->GetEventHandler()->ProcessEvent(event
);
1774 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1777 if (win
->GetEventHandler()->ProcessEvent( event
))
1779 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1787 //-----------------------------------------------------------------------------
1788 // "mouse_wheel_event"
1789 //-----------------------------------------------------------------------------
1791 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1792 GdkEventScroll
* gdk_event
,
1798 wxapp_install_idle_handler();
1800 wxEventType event_type
= wxEVT_NULL
;
1801 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1802 event_type
= wxEVT_MOUSEWHEEL
;
1803 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1804 event_type
= wxEVT_MOUSEWHEEL
;
1808 wxMouseEvent
event( event_type
);
1809 // Can't use InitMouse macro because scroll events don't have button
1810 event
.SetTimestamp( gdk_event
->time
);
1811 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1812 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1813 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1814 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1815 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1816 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1817 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1818 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1819 event
.m_wheelRotation
= 120;
1821 event
.m_wheelRotation
= -120;
1823 wxPoint pt
= win
->GetClientAreaOrigin();
1824 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1825 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1827 event
.SetEventObject( win
);
1828 event
.SetId( win
->GetId() );
1829 event
.SetTimestamp( gdk_event
->time
);
1831 if (win
->GetEventHandler()->ProcessEvent( event
))
1833 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1841 //-----------------------------------------------------------------------------
1843 //-----------------------------------------------------------------------------
1845 // send the wxChildFocusEvent and wxFocusEvent, common code of
1846 // gtk_window_focus_in_callback() and SetFocus()
1847 static bool DoSendFocusEvents(wxWindow
*win
)
1849 // Notify the parent keeping track of focus for the kbd navigation
1850 // purposes that we got it.
1851 wxChildFocusEvent
eventChildFocus(win
);
1852 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1854 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1855 eventFocus
.SetEventObject(win
);
1857 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1860 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1861 GdkEvent
*WXUNUSED(event
),
1867 wxapp_install_idle_handler();
1869 if (!win
->m_hasVMT
) return FALSE
;
1870 if (g_blockEventsOnDrag
) return FALSE
;
1872 switch ( g_sendActivateEvent
)
1875 // we've got focus from outside, synthetize wxActivateEvent
1876 g_sendActivateEvent
= 1;
1880 // another our window just lost focus, it was already ours before
1881 // - don't send any wxActivateEvent
1882 g_sendActivateEvent
= -1;
1887 g_focusWindow
= win
;
1889 wxLogTrace(TRACE_FOCUS
,
1890 _T("%s: focus in"), win
->GetName().c_str());
1894 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1898 // caret needs to be informed about focus change
1899 wxCaret
*caret
= win
->GetCaret();
1902 caret
->OnSetFocus();
1904 #endif // wxUSE_CARET
1906 g_activeFrameLostFocus
= FALSE
;
1908 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1909 if ( active
!= g_activeFrame
)
1911 if ( g_activeFrame
)
1913 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1914 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1915 event
.SetEventObject(g_activeFrame
);
1916 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1919 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1920 g_activeFrame
= active
;
1921 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1922 event
.SetEventObject(g_activeFrame
);
1923 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1925 // Don't send focus events in addition to activate
1926 // if (win == g_activeFrame)
1930 // does the window itself think that it has the focus?
1931 if ( !win
->m_hasFocus
)
1933 // not yet, notify it
1934 win
->m_hasFocus
= TRUE
;
1936 if ( DoSendFocusEvents(win
) )
1938 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1946 //-----------------------------------------------------------------------------
1947 // "focus_out_event"
1948 //-----------------------------------------------------------------------------
1950 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1955 wxapp_install_idle_handler();
1957 if (!win
->m_hasVMT
) return FALSE
;
1958 if (g_blockEventsOnDrag
) return FALSE
;
1960 wxLogTrace( TRACE_FOCUS
,
1961 _T("%s: focus out"), win
->GetName().c_str() );
1963 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1965 // VZ: commenting this out because it does happen (although not easy
1966 // to reproduce, I only see it when using wxMiniFrame and not
1967 // always) and makes using Mahogany quite annoying
1969 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1970 wxT("unfocusing window that hasn't gained focus properly") );
1973 g_activeFrameLostFocus
= TRUE
;
1976 // if the focus goes out of our app alltogether, OnIdle() will send
1977 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1978 // g_sendActivateEvent to -1
1979 g_sendActivateEvent
= 0;
1981 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1985 g_focusWindow
= (wxWindowGTK
*)NULL
;
1993 // caret needs to be informed about focus change
1994 wxCaret
*caret
= win
->GetCaret();
1997 caret
->OnKillFocus();
1999 #endif // wxUSE_CARET
2001 // don't send the window a kill focus event if it thinks that it doesn't
2002 // have focus already
2003 if ( win
->m_hasFocus
)
2005 win
->m_hasFocus
= FALSE
;
2007 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2008 event
.SetEventObject( win
);
2010 if (win
->GetEventHandler()->ProcessEvent( event
))
2012 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
2020 //-----------------------------------------------------------------------------
2021 // "enter_notify_event"
2022 //-----------------------------------------------------------------------------
2025 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2026 GdkEventCrossing
*gdk_event
,
2032 wxapp_install_idle_handler();
2034 if (!win
->m_hasVMT
) return FALSE
;
2035 if (g_blockEventsOnDrag
) return FALSE
;
2037 // Event was emitted after a grab
2038 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2040 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2044 GdkModifierType state
= (GdkModifierType
)0;
2046 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2048 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2049 InitMouseEvent(win
, event
, gdk_event
);
2050 wxPoint pt
= win
->GetClientAreaOrigin();
2051 event
.m_x
= x
+ pt
.x
;
2052 event
.m_y
= y
+ pt
.y
;
2054 if (win
->GetEventHandler()->ProcessEvent( event
))
2056 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2063 //-----------------------------------------------------------------------------
2064 // "leave_notify_event"
2065 //-----------------------------------------------------------------------------
2067 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2072 wxapp_install_idle_handler();
2074 if (!win
->m_hasVMT
) return FALSE
;
2075 if (g_blockEventsOnDrag
) return FALSE
;
2077 // Event was emitted after an ungrab
2078 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2080 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2082 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2083 event
.SetTimestamp( gdk_event
->time
);
2084 event
.SetEventObject( win
);
2088 GdkModifierType state
= (GdkModifierType
)0;
2090 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2092 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2093 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2094 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2095 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2096 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2097 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2098 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2100 wxPoint pt
= win
->GetClientAreaOrigin();
2101 event
.m_x
= x
+ pt
.x
;
2102 event
.m_y
= y
+ pt
.y
;
2104 if (win
->GetEventHandler()->ProcessEvent( event
))
2106 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2113 //-----------------------------------------------------------------------------
2114 // "value_changed" from m_vAdjust
2115 //-----------------------------------------------------------------------------
2117 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2124 wxapp_install_idle_handler();
2126 if (g_blockEventsOnDrag
) return;
2128 if (!win
->m_hasVMT
) return;
2130 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2131 if (fabs(diff
) < 0.2) return;
2133 win
->m_oldVerticalPos
= adjust
->value
;
2136 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2138 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2140 int value
= (int)(adjust
->value
+0.5);
2142 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2143 event
.SetEventObject( win
);
2144 win
->GetEventHandler()->ProcessEvent( event
);
2147 //-----------------------------------------------------------------------------
2148 // "value_changed" from m_hAdjust
2149 //-----------------------------------------------------------------------------
2151 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2158 wxapp_install_idle_handler();
2160 if (g_blockEventsOnDrag
) return;
2161 if (!win
->m_hasVMT
) return;
2163 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2164 if (fabs(diff
) < 0.2) return;
2167 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2169 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2171 win
->m_oldHorizontalPos
= adjust
->value
;
2173 int value
= (int)(adjust
->value
+0.5);
2175 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2176 event
.SetEventObject( win
);
2177 win
->GetEventHandler()->ProcessEvent( event
);
2180 //-----------------------------------------------------------------------------
2181 // "button_press_event" from scrollbar
2182 //-----------------------------------------------------------------------------
2184 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2185 GdkEventButton
*gdk_event
,
2191 wxapp_install_idle_handler();
2194 g_blockEventsOnScroll
= TRUE
;
2196 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2198 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2204 //-----------------------------------------------------------------------------
2205 // "button_release_event" from scrollbar
2206 //-----------------------------------------------------------------------------
2208 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2209 GdkEventButton
*WXUNUSED(gdk_event
),
2214 // don't test here as we can release the mouse while being over
2215 // a different window than the slider
2217 // if (gdk_event->window != widget->slider) return FALSE;
2219 g_blockEventsOnScroll
= FALSE
;
2221 if (win
->m_isScrolling
)
2223 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2227 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2228 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2230 value
= (int)(win
->m_hAdjust
->value
+0.5);
2233 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2235 value
= (int)(win
->m_vAdjust
->value
+0.5);
2239 wxScrollWinEvent
event( command
, value
, dir
);
2240 event
.SetEventObject( win
);
2241 win
->GetEventHandler()->ProcessEvent( event
);
2244 win
->m_isScrolling
= FALSE
;
2249 // ----------------------------------------------------------------------------
2250 // this wxWindowBase function is implemented here (in platform-specific file)
2251 // because it is static and so couldn't be made virtual
2252 // ----------------------------------------------------------------------------
2254 wxWindow
*wxWindowBase::FindFocus()
2256 // the cast is necessary when we compile in wxUniversal mode
2257 return (wxWindow
*)g_focusWindow
;
2261 //-----------------------------------------------------------------------------
2262 // "realize" from m_widget
2263 //-----------------------------------------------------------------------------
2265 /* We cannot set colours and fonts before the widget has
2266 been realized, so we do this directly after realization. */
2269 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2274 wxapp_install_idle_handler();
2276 if (win
->m_delayedBackgroundColour
&& !win
->GetThemeEnabled())
2277 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2279 if (win
->m_delayedForegroundColour
&& !win
->GetThemeEnabled())
2280 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2283 if (win
->m_imContext
)
2285 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2286 gtk_im_context_set_client_window( (GtkIMContext
*) win
->m_imContext
, pizza
->bin_window
);
2290 wxWindowCreateEvent
event( win
);
2291 event
.SetEventObject( win
);
2292 win
->GetEventHandler()->ProcessEvent( event
);
2297 //-----------------------------------------------------------------------------
2299 //-----------------------------------------------------------------------------
2302 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2303 GtkAllocation
*WXUNUSED(alloc
),
2307 wxapp_install_idle_handler();
2309 if (!win
->m_hasScrolling
) return;
2311 int client_width
= 0;
2312 int client_height
= 0;
2313 win
->GetClientSize( &client_width
, &client_height
);
2314 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2317 win
->m_oldClientWidth
= client_width
;
2318 win
->m_oldClientHeight
= client_height
;
2320 if (!win
->m_nativeSizeEvent
)
2322 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2323 event
.SetEventObject( win
);
2324 win
->GetEventHandler()->ProcessEvent( event
);
2330 #define WXUNUSED_UNLESS_XIM(param) param
2332 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2335 /* Resize XIM window */
2338 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2339 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2340 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2343 wxapp_install_idle_handler();
2349 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2353 gdk_window_get_size (widget
->window
, &width
, &height
);
2354 win
->m_icattr
->preedit_area
.width
= width
;
2355 win
->m_icattr
->preedit_area
.height
= height
;
2356 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2361 //-----------------------------------------------------------------------------
2362 // "realize" from m_wxwindow
2363 //-----------------------------------------------------------------------------
2365 /* Initialize XIM support */
2368 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2369 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2372 wxapp_install_idle_handler();
2375 if (win
->m_ic
) return FALSE
;
2376 if (!widget
) return FALSE
;
2377 if (!gdk_im_ready()) return FALSE
;
2379 win
->m_icattr
= gdk_ic_attr_new();
2380 if (!win
->m_icattr
) return FALSE
;
2384 GdkColormap
*colormap
;
2385 GdkICAttr
*attr
= win
->m_icattr
;
2386 unsigned attrmask
= GDK_IC_ALL_REQ
;
2388 GdkIMStyle supported_style
= (GdkIMStyle
)
2389 (GDK_IM_PREEDIT_NONE
|
2390 GDK_IM_PREEDIT_NOTHING
|
2391 GDK_IM_PREEDIT_POSITION
|
2392 GDK_IM_STATUS_NONE
|
2393 GDK_IM_STATUS_NOTHING
);
2395 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2396 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2398 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2399 attr
->client_window
= widget
->window
;
2401 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2402 gtk_widget_get_default_colormap ())
2404 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2405 attr
->preedit_colormap
= colormap
;
2408 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2409 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2410 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2411 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2413 switch (style
& GDK_IM_PREEDIT_MASK
)
2415 case GDK_IM_PREEDIT_POSITION
:
2416 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2418 g_warning ("over-the-spot style requires fontset");
2422 gdk_window_get_size (widget
->window
, &width
, &height
);
2424 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2425 attr
->spot_location
.x
= 0;
2426 attr
->spot_location
.y
= height
;
2427 attr
->preedit_area
.x
= 0;
2428 attr
->preedit_area
.y
= 0;
2429 attr
->preedit_area
.width
= width
;
2430 attr
->preedit_area
.height
= height
;
2431 attr
->preedit_fontset
= widget
->style
->font
;
2436 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2438 if (win
->m_ic
== NULL
)
2439 g_warning ("Can't create input context.");
2442 mask
= gdk_window_get_events (widget
->window
);
2443 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2444 gdk_window_set_events (widget
->window
, mask
);
2446 if (GTK_WIDGET_HAS_FOCUS(widget
))
2447 gdk_im_begin (win
->m_ic
, widget
->window
);
2454 //-----------------------------------------------------------------------------
2455 // InsertChild for wxWindowGTK.
2456 //-----------------------------------------------------------------------------
2458 /* Callback for wxWindowGTK. This very strange beast has to be used because
2459 * C++ has no virtual methods in a constructor. We have to emulate a
2460 * virtual function here as wxNotebook requires a different way to insert
2461 * a child in it. I had opted for creating a wxNotebookPage window class
2462 * which would have made this superfluous (such in the MDI window system),
2463 * but no-one was listening to me... */
2465 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2467 /* the window might have been scrolled already, do we
2468 have to adapt the position */
2469 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2470 child
->m_x
+= pizza
->xoffset
;
2471 child
->m_y
+= pizza
->yoffset
;
2473 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2474 GTK_WIDGET(child
->m_widget
),
2481 //-----------------------------------------------------------------------------
2483 //-----------------------------------------------------------------------------
2485 wxWindow
*wxGetActiveWindow()
2487 return wxWindow::FindFocus();
2490 //-----------------------------------------------------------------------------
2492 //-----------------------------------------------------------------------------
2494 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2496 #ifdef __WXUNIVERSAL__
2497 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2499 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2500 #endif // __WXUNIVERSAL__/__WXGTK__
2502 void wxWindowGTK::Init()
2505 m_widget
= (GtkWidget
*) NULL
;
2506 m_wxwindow
= (GtkWidget
*) NULL
;
2507 m_focusWidget
= (GtkWidget
*) NULL
;
2517 m_needParent
= TRUE
;
2518 m_isBeingDeleted
= FALSE
;
2521 m_nativeSizeEvent
= FALSE
;
2523 m_hasScrolling
= FALSE
;
2524 m_isScrolling
= FALSE
;
2526 m_hAdjust
= (GtkAdjustment
*) NULL
;
2527 m_vAdjust
= (GtkAdjustment
*) NULL
;
2528 m_oldHorizontalPos
=
2529 m_oldVerticalPos
= 0.0;
2531 m_oldClientHeight
= 0;
2534 m_widgetStyle
= (GtkStyle
*) NULL
;
2536 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2538 m_acceptsFocus
= FALSE
;
2541 m_clipPaintRegion
= FALSE
;
2543 m_cursor
= *wxSTANDARD_CURSOR
;
2545 m_delayedForegroundColour
= FALSE
;
2546 m_delayedBackgroundColour
= FALSE
;
2550 m_x11Context
= NULL
;
2553 m_ic
= (GdkIC
*) NULL
;
2554 m_icattr
= (GdkICAttr
*) NULL
;
2559 wxWindowGTK::wxWindowGTK()
2564 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2569 const wxString
&name
)
2573 Create( parent
, id
, pos
, size
, style
, name
);
2576 bool wxWindowGTK::Create( wxWindow
*parent
,
2581 const wxString
&name
)
2583 if (!PreCreation( parent
, pos
, size
) ||
2584 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2586 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2590 m_insertCallback
= wxInsertChildInWindow
;
2592 // always needed for background clearing
2593 m_delayedBackgroundColour
= TRUE
;
2595 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2596 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2598 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2600 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2601 scroll_class
->scrollbar_spacing
= 0;
2603 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2605 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2606 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2608 m_wxwindow
= gtk_pizza_new();
2610 #ifndef __WXUNIVERSAL__
2611 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2613 if (HasFlag(wxRAISED_BORDER
))
2615 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2617 else if (HasFlag(wxSUNKEN_BORDER
))
2619 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2621 else if (HasFlag(wxSIMPLE_BORDER
))
2623 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2627 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2629 #endif // __WXUNIVERSAL__
2631 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2633 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2634 m_acceptsFocus
= TRUE
;
2636 // I _really_ don't want scrollbars in the beginning
2637 m_vAdjust
->lower
= 0.0;
2638 m_vAdjust
->upper
= 1.0;
2639 m_vAdjust
->value
= 0.0;
2640 m_vAdjust
->step_increment
= 1.0;
2641 m_vAdjust
->page_increment
= 1.0;
2642 m_vAdjust
->page_size
= 5.0;
2643 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2644 m_hAdjust
->lower
= 0.0;
2645 m_hAdjust
->upper
= 1.0;
2646 m_hAdjust
->value
= 0.0;
2647 m_hAdjust
->step_increment
= 1.0;
2648 m_hAdjust
->page_increment
= 1.0;
2649 m_hAdjust
->page_size
= 5.0;
2650 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2652 // these handlers block mouse events to any window during scrolling such as
2653 // motion events and prevent GTK and wxWindows from fighting over where the
2656 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2657 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2659 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2660 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2662 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2663 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2665 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2666 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2668 // these handlers get notified when screen updates are required either when
2669 // scrolling or when the window size (and therefore scrollbar configuration)
2672 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2673 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2674 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2675 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2678 // Create input method handler
2679 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2681 // Cannot handle drawing preedited text yet
2682 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2684 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2685 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2688 gtk_widget_show( m_wxwindow
);
2691 m_parent
->DoAddChild( this );
2693 m_focusWidget
= m_wxwindow
;
2702 wxWindowGTK::~wxWindowGTK()
2706 if (g_focusWindow
== this)
2707 g_focusWindow
= NULL
;
2709 if (g_activeFrame
== this)
2710 g_activeFrame
= NULL
;
2712 if ( g_delayedFocus
== this )
2713 g_delayedFocus
= NULL
;
2715 m_isBeingDeleted
= TRUE
;
2725 gdk_ic_destroy (m_ic
);
2727 gdk_ic_attr_destroy (m_icattr
);
2732 #if DISABLE_STYLE_IF_BROKEN_THEME
2733 // don't delete if it's a pixmap theme style
2734 if (!m_widgetStyle
->engine_data
)
2735 gtk_style_unref( m_widgetStyle
);
2737 m_widgetStyle
= (GtkStyle
*) NULL
;
2742 gtk_widget_destroy( m_wxwindow
);
2743 m_wxwindow
= (GtkWidget
*) NULL
;
2748 gtk_widget_destroy( m_widget
);
2749 m_widget
= (GtkWidget
*) NULL
;
2753 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2755 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2757 // This turns -1 into 30 so that a minimal window is
2758 // visible even although -1,-1 has been given as the
2759 // size of the window. the same trick is used in other
2760 // ports and should make debugging easier.
2761 m_width
= WidthDefault(size
.x
) ;
2762 m_height
= HeightDefault(size
.y
);
2767 // some reasonable defaults
2772 m_x
= (gdk_screen_width () - m_width
) / 2;
2773 if (m_x
< 10) m_x
= 10;
2777 m_y
= (gdk_screen_height () - m_height
) / 2;
2778 if (m_y
< 10) m_y
= 10;
2785 void wxWindowGTK::PostCreation()
2787 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2793 // these get reported to wxWindows -> wxPaintEvent
2795 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2797 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2798 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2801 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2802 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2804 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2806 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2807 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2810 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2814 // Create input method handler
2815 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2817 // Cannot handle drawing preedited text yet
2818 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2820 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2821 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2825 // these are called when the "sunken" or "raised" borders are drawn
2826 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2827 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2830 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2831 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2837 if (m_focusWidget
== NULL
)
2838 m_focusWidget
= m_widget
;
2840 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2841 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2843 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2844 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2846 // connect to the various key and mouse handlers
2848 GtkWidget
*connect_widget
= GetConnectWidget();
2850 ConnectWidget( connect_widget
);
2852 /* We cannot set colours, fonts and cursors before the widget has
2853 been realized, so we do this directly after realization */
2854 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2855 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2859 // Catch native resize events
2860 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2861 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2863 // Initialize XIM support
2864 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2865 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2867 // And resize XIM window
2868 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2869 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2872 if ( !GTK_IS_COMBO(m_widget
))
2874 // This is needed if we want to add our windows into native
2875 // GTK control, such as the toolbar. With this callback, the
2876 // toolbar gets to know the correct size (the one set by the
2877 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2878 // when moving to GTK 2.0.
2879 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2880 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2887 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2889 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2890 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2892 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2893 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2895 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2896 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2898 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2899 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2901 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2902 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2905 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2906 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2909 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2910 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2912 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2913 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2916 bool wxWindowGTK::Destroy()
2918 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2922 return wxWindowBase::Destroy();
2925 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2927 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2930 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2932 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2933 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2936 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2939 if (m_resizing
) return; /* I don't like recursions */
2942 int currentX
, currentY
;
2943 GetPosition(¤tX
, ¤tY
);
2944 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2946 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2948 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2950 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2952 /* don't set the size for children of wxNotebook, just take the values. */
2960 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2961 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2963 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2964 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2968 m_x
= x
+ pizza
->xoffset
;
2969 m_y
= y
+ pizza
->yoffset
;
2971 if (width
!= -1) m_width
= width
;
2972 if (height
!= -1) m_height
= height
;
2974 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2976 if (width
== -1) m_width
= 80;
2979 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2981 if (height
== -1) m_height
= 26;
2984 int minWidth
= GetMinWidth(),
2985 minHeight
= GetMinHeight(),
2986 maxWidth
= GetMaxWidth(),
2987 maxHeight
= GetMaxHeight();
2989 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2990 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2991 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2992 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2995 int bottom_border
= 0;
2998 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3000 /* the default button has a border around it */
3006 DoMoveWindow( m_x
-border
,
3009 m_height
+border
+bottom_border
);
3014 /* Sometimes the client area changes size without the
3015 whole windows's size changing, but if the whole
3016 windows's size doesn't change, no wxSizeEvent will
3017 normally be sent. Here we add an extra test if
3018 the client test has been changed and this will
3020 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3024 wxPrintf( "OnSize sent from " );
3025 if (GetClassInfo() && GetClassInfo()->GetClassName())
3026 wxPrintf( GetClassInfo()->GetClassName() );
3027 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3030 if (!m_nativeSizeEvent
)
3032 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3033 event
.SetEventObject( this );
3034 GetEventHandler()->ProcessEvent( event
);
3040 void wxWindowGTK::OnInternalIdle()
3042 // Update invalidated regions.
3045 // Synthetize activate events.
3046 if ( g_sendActivateEvent
!= -1 )
3048 bool activate
= g_sendActivateEvent
!= 0;
3051 g_sendActivateEvent
= -1;
3053 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
3056 if ( g_activeFrameLostFocus
)
3058 if ( g_activeFrame
)
3060 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3061 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3062 event
.SetEventObject(g_activeFrame
);
3063 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3064 g_activeFrame
= NULL
;
3066 g_activeFrameLostFocus
= FALSE
;
3069 wxCursor cursor
= m_cursor
;
3070 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3074 /* I now set the cursor anew in every OnInternalIdle call
3075 as setting the cursor in a parent window also effects the
3076 windows above so that checking for the current cursor is
3081 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3083 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3085 if (!g_globalCursor
.Ok())
3086 cursor
= *wxSTANDARD_CURSOR
;
3088 window
= m_widget
->window
;
3089 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3090 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3096 GdkWindow
*window
= m_widget
->window
;
3097 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3098 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3103 if (wxUpdateUIEvent::CanUpdate(this))
3104 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3107 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3109 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3111 if (width
) (*width
) = m_width
;
3112 if (height
) (*height
) = m_height
;
3115 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3117 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3121 SetSize( width
, height
);
3128 #ifndef __WXUNIVERSAL__
3129 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3131 /* when using GTK 1.2 we set the shadow border size to 2 */
3135 if (HasFlag(wxSIMPLE_BORDER
))
3137 /* when using GTK 1.2 we set the simple border size to 1 */
3141 #endif // __WXUNIVERSAL__
3145 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3147 GtkRequisition vscroll_req
;
3148 vscroll_req
.width
= 2;
3149 vscroll_req
.height
= 2;
3150 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3151 (scroll_window
->vscrollbar
, &vscroll_req
);
3153 GtkRequisition hscroll_req
;
3154 hscroll_req
.width
= 2;
3155 hscroll_req
.height
= 2;
3156 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3157 (scroll_window
->hscrollbar
, &hscroll_req
);
3159 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3161 if (scroll_window
->vscrollbar_visible
)
3163 dw
+= vscroll_req
.width
;
3164 dw
+= scroll_class
->scrollbar_spacing
;
3167 if (scroll_window
->hscrollbar_visible
)
3169 dh
+= hscroll_req
.height
;
3170 dh
+= scroll_class
->scrollbar_spacing
;
3174 SetSize( width
+dw
, height
+dh
);
3178 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3180 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3184 if (width
) (*width
) = m_width
;
3185 if (height
) (*height
) = m_height
;
3192 #ifndef __WXUNIVERSAL__
3193 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3195 /* when using GTK 1.2 we set the shadow border size to 2 */
3199 if (HasFlag(wxSIMPLE_BORDER
))
3201 /* when using GTK 1.2 we set the simple border size to 1 */
3205 #endif // __WXUNIVERSAL__
3209 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3211 GtkRequisition vscroll_req
;
3212 vscroll_req
.width
= 2;
3213 vscroll_req
.height
= 2;
3214 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3215 (scroll_window
->vscrollbar
, &vscroll_req
);
3217 GtkRequisition hscroll_req
;
3218 hscroll_req
.width
= 2;
3219 hscroll_req
.height
= 2;
3220 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3221 (scroll_window
->hscrollbar
, &hscroll_req
);
3223 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3225 if (scroll_window
->vscrollbar_visible
)
3227 dw
+= vscroll_req
.width
;
3228 dw
+= scroll_class
->scrollbar_spacing
;
3231 if (scroll_window
->hscrollbar_visible
)
3233 dh
+= hscroll_req
.height
;
3234 dh
+= scroll_class
->scrollbar_spacing
;
3238 if (width
) (*width
) = m_width
- dw
;
3239 if (height
) (*height
) = m_height
- dh
;
3243 printf( "GetClientSize, name %s ", GetName().c_str() );
3244 if (width) printf( " width = %d", (*width) );
3245 if (height) printf( " height = %d", (*height) );
3250 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3252 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3256 if (m_parent
&& m_parent
->m_wxwindow
)
3258 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3259 dx
= pizza
->xoffset
;
3260 dy
= pizza
->yoffset
;
3263 if (x
) (*x
) = m_x
- dx
;
3264 if (y
) (*y
) = m_y
- dy
;
3267 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3269 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3271 if (!m_widget
->window
) return;
3273 GdkWindow
*source
= (GdkWindow
*) NULL
;
3275 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3277 source
= m_widget
->window
;
3281 gdk_window_get_origin( source
, &org_x
, &org_y
);
3285 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3287 org_x
+= m_widget
->allocation
.x
;
3288 org_y
+= m_widget
->allocation
.y
;
3296 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3298 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3300 if (!m_widget
->window
) return;
3302 GdkWindow
*source
= (GdkWindow
*) NULL
;
3304 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3306 source
= m_widget
->window
;
3310 gdk_window_get_origin( source
, &org_x
, &org_y
);
3314 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3316 org_x
+= m_widget
->allocation
.x
;
3317 org_y
+= m_widget
->allocation
.y
;
3325 bool wxWindowGTK::Show( bool show
)
3327 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3329 if (!wxWindowBase::Show(show
))
3336 gtk_widget_show( m_widget
);
3338 gtk_widget_hide( m_widget
);
3340 wxShowEvent
eventShow(GetId(), show
);
3341 eventShow
.m_eventObject
= this;
3343 GetEventHandler()->ProcessEvent(eventShow
);
3348 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3350 win
->OnParentEnable(enable
);
3352 // Recurse, so that children have the opportunity to Do The Right Thing
3353 // and reset colours that have been messed up by a parent's (really ancestor's)
3355 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3357 node
= node
->GetNext() )
3359 wxWindow
*child
= node
->GetData();
3360 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3361 wxWindowNotifyEnable(child
, enable
);
3365 bool wxWindowGTK::Enable( bool enable
)
3367 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3369 if (!wxWindowBase::Enable(enable
))
3375 gtk_widget_set_sensitive( m_widget
, enable
);
3377 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3379 wxWindowNotifyEnable(this, enable
);
3384 int wxWindowGTK::GetCharHeight() const
3386 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3388 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3391 PangoContext
*context
= NULL
;
3393 context
= gtk_widget_get_pango_context( m_widget
);
3398 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3399 PangoLayout
*layout
= pango_layout_new(context
);
3400 pango_layout_set_font_description(layout
, desc
);
3401 pango_layout_set_text(layout
, "H", 1);
3402 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3404 PangoRectangle rect
;
3405 pango_layout_line_get_extents(line
, NULL
, &rect
);
3407 g_object_unref( G_OBJECT( layout
) );
3409 return (int) (rect
.height
/ PANGO_SCALE
);
3411 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3413 return font
->ascent
+ font
->descent
;
3417 int wxWindowGTK::GetCharWidth() const
3419 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3421 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3424 PangoContext
*context
= NULL
;
3426 context
= gtk_widget_get_pango_context( m_widget
);
3431 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3432 PangoLayout
*layout
= pango_layout_new(context
);
3433 pango_layout_set_font_description(layout
, desc
);
3434 pango_layout_set_text(layout
, "g", 1);
3435 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3437 PangoRectangle rect
;
3438 pango_layout_line_get_extents(line
, NULL
, &rect
);
3440 g_object_unref( G_OBJECT( layout
) );
3442 return (int) (rect
.width
/ PANGO_SCALE
);
3444 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3446 return gdk_string_width( font
, "g" );
3450 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3454 int *externalLeading
,
3455 const wxFont
*theFont
) const
3457 wxFont fontToUse
= m_font
;
3458 if (theFont
) fontToUse
= *theFont
;
3460 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3462 if (string
.IsEmpty())
3470 PangoContext
*context
= NULL
;
3472 context
= gtk_widget_get_pango_context( m_widget
);
3481 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3482 PangoLayout
*layout
= pango_layout_new(context
);
3483 pango_layout_set_font_description(layout
, desc
);
3486 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3487 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3489 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3490 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3491 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3494 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3496 PangoRectangle rect
;
3497 pango_layout_line_get_extents(line
, NULL
, &rect
);
3499 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3500 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3503 // Do something about metrics here
3506 if (externalLeading
) (*externalLeading
) = 0; // ??
3508 g_object_unref( G_OBJECT( layout
) );
3510 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3511 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3512 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3513 if (descent
) (*descent
) = font
->descent
;
3514 if (externalLeading
) (*externalLeading
) = 0; // ??
3518 void wxWindowGTK::SetFocus()
3520 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3524 // don't do anything if we already have focus
3530 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3532 gtk_widget_grab_focus (m_wxwindow
);
3537 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3539 if (!GTK_WIDGET_REALIZED(m_widget
))
3541 // we can't set the focus to the widget now so we remember that
3542 // it should be focused and will do it later, during the idle
3543 // time, as soon as we can
3544 wxLogTrace(TRACE_FOCUS
,
3545 _T("Delaying setting focus to %s(%s)"),
3546 GetClassInfo()->GetClassName(), GetLabel().c_str());
3548 g_delayedFocus
= this;
3552 wxLogTrace(TRACE_FOCUS
,
3553 _T("Setting focus to %s(%s)"),
3554 GetClassInfo()->GetClassName(), GetLabel().c_str());
3556 gtk_widget_grab_focus (m_widget
);
3559 else if (GTK_IS_CONTAINER(m_widget
))
3561 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3565 wxLogTrace(TRACE_FOCUS
,
3566 _T("Can't set focus to %s(%s)"),
3567 GetClassInfo()->GetClassName(), GetLabel().c_str());
3572 bool wxWindowGTK::AcceptsFocus() const
3574 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3577 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3579 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3581 wxWindowGTK
*oldParent
= m_parent
,
3582 *newParent
= (wxWindowGTK
*)newParentBase
;
3584 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3586 if ( !wxWindowBase::Reparent(newParent
) )
3589 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3591 /* prevent GTK from deleting the widget arbitrarily */
3592 gtk_widget_ref( m_widget
);
3596 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3599 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3603 /* insert GTK representation */
3604 (*(newParent
->m_insertCallback
))(newParent
, this);
3607 /* reverse: prevent GTK from deleting the widget arbitrarily */
3608 gtk_widget_unref( m_widget
);
3613 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3615 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3617 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3619 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3624 /* insert GTK representation */
3625 (*m_insertCallback
)(this, child
);
3628 void wxWindowGTK::Raise()
3630 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3632 if (!m_widget
->window
) return;
3634 gdk_window_raise( m_widget
->window
);
3637 void wxWindowGTK::Lower()
3639 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3641 if (!m_widget
->window
) return;
3643 gdk_window_lower( m_widget
->window
);
3646 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3648 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3650 if (cursor
== m_cursor
)
3654 wxapp_install_idle_handler();
3656 if (cursor
== wxNullCursor
)
3657 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3659 return wxWindowBase::SetCursor( cursor
);
3662 void wxWindowGTK::WarpPointer( int x
, int y
)
3664 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3666 // We provide this function ourselves as it is
3667 // missing in GDK (top of this file).
3669 GdkWindow
*window
= (GdkWindow
*) NULL
;
3671 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3673 window
= GetConnectWidget()->window
;
3676 gdk_window_warp_pointer( window
, x
, y
);
3680 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3682 if (!m_widget
) return;
3683 if (!m_widget
->window
) return;
3687 wxapp_install_idle_handler();
3689 wxRect
myRect(0,0,0,0);
3690 if (m_wxwindow
&& rect
)
3692 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3693 m_wxwindow
->allocation
.height
));
3694 myRect
.Intersect(*rect
);
3695 if (!myRect
.width
|| !myRect
.height
)
3696 // nothing to do, rectangle is empty
3701 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3705 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3706 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3710 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3711 m_clearRegion
.Clear();
3712 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3720 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3721 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3725 GdkRectangle gdk_rect
;
3726 gdk_rect
.x
= rect
->x
;
3727 gdk_rect
.y
= rect
->y
;
3728 gdk_rect
.width
= rect
->width
;
3729 gdk_rect
.height
= rect
->height
;
3730 gtk_widget_draw( m_widget
, &gdk_rect
);
3737 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3738 m_updateRegion
.Clear();
3739 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3743 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3751 GdkRectangle gdk_rect
;
3752 gdk_rect
.x
= rect
->x
;
3753 gdk_rect
.y
= rect
->y
;
3754 gdk_rect
.width
= rect
->width
;
3755 gdk_rect
.height
= rect
->height
;
3756 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3760 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3766 void wxWindowGTK::Update()
3771 void wxWindowGTK::GtkUpdate()
3774 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3775 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3777 if (!m_updateRegion
.IsEmpty())
3778 GtkSendPaintEvents();
3782 void wxWindowGTK::GtkSendPaintEvents()
3787 m_clearRegion
.Clear();
3789 m_updateRegion
.Clear();
3793 // Clip to paint region in wxClientDC
3794 m_clipPaintRegion
= TRUE
;
3797 // widget to draw on
3798 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3800 // later for GTK 2.0, too.
3801 if (GetThemeEnabled())
3803 // find ancestor from which to steal background
3804 wxWindow
*parent
= GetParent();
3805 while (parent
&& !parent
->IsTopLevel())
3806 parent
= parent
->GetParent();
3808 parent
= (wxWindow
*)this;
3810 wxRegionIterator
upd( m_updateRegion
);
3814 rect
.x
= upd
.GetX();
3815 rect
.y
= upd
.GetY();
3816 rect
.width
= upd
.GetWidth();
3817 rect
.height
= upd
.GetHeight();
3819 gtk_paint_flat_box( parent
->m_widget
->style
,
3836 wxWindowDC
dc( (wxWindow
*)this );
3837 dc
.SetClippingRegion( m_updateRegion
);
3839 wxEraseEvent
erase_event( GetId(), &dc
);
3840 erase_event
.SetEventObject( this );
3842 GetEventHandler()->ProcessEvent(erase_event
);
3845 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3847 wxWindowDC
dc( (wxWindow
*)this );
3848 if (m_clearRegion
.IsEmpty())
3849 dc
.SetClippingRegion( m_updateRegion
);
3851 dc
.SetClippingRegion( m_clearRegion
);
3853 wxEraseEvent
erase_event( GetId(), &dc
);
3854 erase_event
.SetEventObject( this );
3856 if (!GetEventHandler()->ProcessEvent(erase_event
))
3860 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3861 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3863 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3865 wxRegionIterator
upd( m_clearRegion
);
3868 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3869 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3873 m_clearRegion
.Clear();
3877 wxNcPaintEvent
nc_paint_event( GetId() );
3878 nc_paint_event
.SetEventObject( this );
3879 GetEventHandler()->ProcessEvent( nc_paint_event
);
3881 wxPaintEvent
paint_event( GetId() );
3882 paint_event
.SetEventObject( this );
3883 GetEventHandler()->ProcessEvent( paint_event
);
3885 m_clipPaintRegion
= FALSE
;
3887 #ifndef __WXUNIVERSAL__
3889 // The following code will result in all window-less widgets
3890 // being redrawn because the wxWindows class is allowed to
3891 // paint over the window-less widgets.
3893 GList
*children
= pizza
->children
;
3896 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3897 children
= children
->next
;
3899 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3900 GTK_WIDGET_DRAWABLE (child
->widget
))
3902 // Get intersection of widget area and update region
3903 wxRegion
region( m_updateRegion
);
3905 GdkEventExpose gdk_event
;
3906 gdk_event
.type
= GDK_EXPOSE
;
3907 gdk_event
.window
= pizza
->bin_window
;
3908 gdk_event
.count
= 0;
3910 wxRegionIterator
upd( m_updateRegion
);
3914 rect
.x
= upd
.GetX();
3915 rect
.y
= upd
.GetY();
3916 rect
.width
= upd
.GetWidth();
3917 rect
.height
= upd
.GetHeight();
3919 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3921 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3931 m_updateRegion
.Clear();
3934 void wxWindowGTK::ClearBackground()
3936 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3939 if (m_wxwindow
&& m_wxwindow
->window
)
3941 m_clearRegion
.Clear();
3942 wxSize
size( GetClientSize() );
3943 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3945 // Better do this in idle?
3952 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3954 wxWindowBase::DoSetToolTip(tip
);
3957 m_tooltip
->Apply( (wxWindow
*)this );
3960 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3962 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3964 #endif // wxUSE_TOOLTIPS
3966 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3968 GdkWindow
*window
= (GdkWindow
*) NULL
;
3970 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3972 window
= GetConnectWidget()->window
;
3976 // We need the pixel value e.g. for background clearing.
3977 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3981 // wxMSW doesn't clear the window here, either.
3982 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3988 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3990 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3992 if (!wxWindowBase::SetBackgroundColour(colour
))
3995 GdkWindow
*window
= (GdkWindow
*) NULL
;
3997 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3999 window
= GetConnectWidget()->window
;
4003 // indicate that a new style has been set
4004 // but it couldn't get applied as the
4005 // widget hasn't been realized yet.
4006 m_delayedBackgroundColour
= TRUE
;
4011 GtkSetBackgroundColour( colour
);
4017 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
4019 GdkWindow
*window
= (GdkWindow
*) NULL
;
4021 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4023 window
= GetConnectWidget()->window
;
4030 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4032 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4034 if (!wxWindowBase::SetForegroundColour(colour
))
4036 // don't leave if the GTK widget has just
4038 if (!m_delayedForegroundColour
) return FALSE
;
4041 GdkWindow
*window
= (GdkWindow
*) NULL
;
4043 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4045 window
= GetConnectWidget()->window
;
4049 // indicate that a new style has been set
4050 // but it couldn't get applied as the
4051 // widget hasn't been realized yet.
4052 m_delayedForegroundColour
= TRUE
;
4056 GtkSetForegroundColour( colour
);
4063 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4065 return gtk_widget_get_pango_context( m_widget
);
4068 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4071 m_x11Context
= pango_x_get_context( gdk_display
);
4073 return m_x11Context
;
4077 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4081 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4083 // FIXME: no more klass in 2.0
4085 remake
->klass
= m_widgetStyle
->klass
;
4088 gtk_style_unref( m_widgetStyle
);
4089 m_widgetStyle
= remake
;
4093 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4096 def
= gtk_widget_get_default_style();
4098 m_widgetStyle
= gtk_style_copy( def
);
4100 // FIXME: no more klass in 2.0
4102 m_widgetStyle
->klass
= def
->klass
;
4106 return m_widgetStyle
;
4109 void wxWindowGTK::SetWidgetStyle()
4111 #if DISABLE_STYLE_IF_BROKEN_THEME
4112 if (m_widget
->style
->engine_data
)
4114 static bool s_warningPrinted
= FALSE
;
4115 if (!s_warningPrinted
)
4117 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
4118 s_warningPrinted
= TRUE
;
4120 m_widgetStyle
= m_widget
->style
;
4125 GtkStyle
*style
= GetWidgetStyle();
4127 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
4130 pango_font_description_free( style
->font_desc
);
4131 style
->font_desc
= pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4133 gdk_font_unref( style
->font
);
4134 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4138 if (m_foregroundColour
.Ok())
4140 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4141 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4143 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4144 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4145 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4149 // Try to restore the gtk default style. This is still a little
4150 // oversimplified for what is probably really needed here for controls
4151 // other than buttons, but is better than not being able to (re)set a
4152 // control's foreground colour to *wxBLACK -- RL
4153 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4156 def
= gtk_widget_get_default_style();
4158 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4159 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4160 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4164 if (m_backgroundColour
.Ok())
4166 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4167 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4169 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4170 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4171 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4172 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4173 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4174 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4175 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4176 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4180 // Try to restore the gtk default style. This is still a little
4181 // oversimplified for what is probably really needed here for controls
4182 // other than buttons, but is better than not being able to (re)set a
4183 // control's background colour to default grey and means resetting a
4184 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4186 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4189 def
= gtk_widget_get_default_style();
4191 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4192 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4193 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4194 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4195 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4196 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4197 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4198 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4203 void wxWindowGTK::ApplyWidgetStyle()
4207 //-----------------------------------------------------------------------------
4208 // Pop-up menu stuff
4209 //-----------------------------------------------------------------------------
4211 #if wxUSE_MENUS_NATIVE
4214 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4216 *is_waiting
= FALSE
;
4219 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4221 menu
->SetInvokingWindow( win
);
4222 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4225 wxMenuItem
*menuitem
= node
->GetData();
4226 if (menuitem
->IsSubMenu())
4228 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4231 node
= node
->GetNext();
4235 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
4236 // wxPopupMenuPositionCallback()
4238 // should be safe even in the MT case as the user can hardly popup 2 menus
4239 // simultaneously, can he?
4240 static gint gs_pop_x
= 0;
4241 static gint gs_pop_y
= 0;
4243 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4246 gboolean
* WXUNUSED(whatever
),
4248 gpointer
WXUNUSED(user_data
) )
4250 // ensure that the menu appears entirely on screen
4252 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4254 wxSize sizeScreen
= wxGetDisplaySize();
4256 gint xmax
= sizeScreen
.x
- req
.width
,
4257 ymax
= sizeScreen
.y
- req
.height
;
4259 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
4260 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
4263 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4265 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4267 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
4269 SetInvokingWindow( menu
, this );
4275 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
4277 bool is_waiting
= TRUE
;
4279 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4281 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4282 (gpointer
)&is_waiting
);
4285 GTK_MENU(menu
->m_menu
),
4286 (GtkWidget
*) NULL
, // parent menu shell
4287 (GtkWidget
*) NULL
, // parent menu item
4288 wxPopupMenuPositionCallback
, // function to position it
4289 NULL
, // client data
4290 0, // button used to activate it
4292 gtk_get_current_event_time()
4294 gs_timeLastClick
// the time of activation
4300 gtk_main_iteration();
4306 #endif // wxUSE_MENUS_NATIVE
4308 #if wxUSE_DRAG_AND_DROP
4310 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4312 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4314 GtkWidget
*dnd_widget
= GetConnectWidget();
4316 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4318 if (m_dropTarget
) delete m_dropTarget
;
4319 m_dropTarget
= dropTarget
;
4321 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4324 #endif // wxUSE_DRAG_AND_DROP
4326 GtkWidget
* wxWindowGTK::GetConnectWidget()
4328 GtkWidget
*connect_widget
= m_widget
;
4329 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4331 return connect_widget
;
4334 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4337 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4339 return (window
== m_widget
->window
);
4342 bool wxWindowGTK::SetFont( const wxFont
&font
)
4344 if (!wxWindowBase::SetFont(font
) || !m_widget
)
4349 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4350 if ( sysbg
== m_backgroundColour
)
4352 m_backgroundColour
= wxNullColour
;
4354 m_backgroundColour
= sysbg
;
4364 void wxWindowGTK::DoCaptureMouse()
4366 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4368 GdkWindow
*window
= (GdkWindow
*) NULL
;
4370 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4372 window
= GetConnectWidget()->window
;
4374 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4376 wxCursor
* cursor
= & m_cursor
;
4378 cursor
= wxSTANDARD_CURSOR
;
4380 gdk_pointer_grab( window
, FALSE
,
4382 (GDK_BUTTON_PRESS_MASK
|
4383 GDK_BUTTON_RELEASE_MASK
|
4384 GDK_POINTER_MOTION_HINT_MASK
|
4385 GDK_POINTER_MOTION_MASK
),
4387 cursor
->GetCursor(),
4388 (guint32
)GDK_CURRENT_TIME
);
4389 g_captureWindow
= this;
4390 g_captureWindowHasMouse
= TRUE
;
4393 void wxWindowGTK::DoReleaseMouse()
4395 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4397 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4399 g_captureWindow
= (wxWindowGTK
*) NULL
;
4401 GdkWindow
*window
= (GdkWindow
*) NULL
;
4403 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4405 window
= GetConnectWidget()->window
;
4410 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4414 wxWindow
*wxWindowBase::GetCapture()
4416 return (wxWindow
*)g_captureWindow
;
4419 bool wxWindowGTK::IsRetained() const
4424 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4425 int range
, bool refresh
)
4427 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4429 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4431 m_hasScrolling
= TRUE
;
4433 if (orient
== wxHORIZONTAL
)
4435 float fpos
= (float)pos
;
4436 float frange
= (float)range
;
4437 float fthumb
= (float)thumbVisible
;
4438 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4439 if (fpos
< 0.0) fpos
= 0.0;
4441 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4442 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4444 SetScrollPos( orient
, pos
, refresh
);
4448 m_oldHorizontalPos
= fpos
;
4450 m_hAdjust
->lower
= 0.0;
4451 m_hAdjust
->upper
= frange
;
4452 m_hAdjust
->value
= fpos
;
4453 m_hAdjust
->step_increment
= 1.0;
4454 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4455 m_hAdjust
->page_size
= fthumb
;
4459 float fpos
= (float)pos
;
4460 float frange
= (float)range
;
4461 float fthumb
= (float)thumbVisible
;
4462 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4463 if (fpos
< 0.0) fpos
= 0.0;
4465 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4466 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4468 SetScrollPos( orient
, pos
, refresh
);
4472 m_oldVerticalPos
= fpos
;
4474 m_vAdjust
->lower
= 0.0;
4475 m_vAdjust
->upper
= frange
;
4476 m_vAdjust
->value
= fpos
;
4477 m_vAdjust
->step_increment
= 1.0;
4478 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4479 m_vAdjust
->page_size
= fthumb
;
4482 if (orient
== wxHORIZONTAL
)
4483 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4485 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4488 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4490 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4492 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4494 if (orient
== wxHORIZONTAL
)
4496 float fpos
= (float)pos
;
4497 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4498 if (fpos
< 0.0) fpos
= 0.0;
4499 m_oldHorizontalPos
= fpos
;
4501 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4502 m_hAdjust
->value
= fpos
;
4506 float fpos
= (float)pos
;
4507 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4508 if (fpos
< 0.0) fpos
= 0.0;
4509 m_oldVerticalPos
= fpos
;
4511 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4512 m_vAdjust
->value
= fpos
;
4515 if (m_wxwindow
->window
)
4517 if (orient
== wxHORIZONTAL
)
4519 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4520 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4522 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4524 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4525 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4529 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4530 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4532 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4534 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4535 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4540 int wxWindowGTK::GetScrollThumb( int orient
) const
4542 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4544 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4546 if (orient
== wxHORIZONTAL
)
4547 return (int)(m_hAdjust
->page_size
+0.5);
4549 return (int)(m_vAdjust
->page_size
+0.5);
4552 int wxWindowGTK::GetScrollPos( int orient
) const
4554 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4556 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4558 if (orient
== wxHORIZONTAL
)
4559 return (int)(m_hAdjust
->value
+0.5);
4561 return (int)(m_vAdjust
->value
+0.5);
4564 int wxWindowGTK::GetScrollRange( int orient
) const
4566 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4568 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4570 if (orient
== wxHORIZONTAL
)
4571 return (int)(m_hAdjust
->upper
+0.5);
4573 return (int)(m_vAdjust
->upper
+0.5);
4576 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4578 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4580 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4582 // No scrolling requested.
4583 if ((dx
== 0) && (dy
== 0)) return;
4586 if (!m_updateRegion
.IsEmpty())
4588 m_updateRegion
.Offset( dx
, dy
);
4592 GetClientSize( &cw
, &ch
);
4593 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4596 if (!m_clearRegion
.IsEmpty())
4598 m_clearRegion
.Offset( dx
, dy
);
4602 GetClientSize( &cw
, &ch
);
4603 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4607 m_clipPaintRegion
= TRUE
;
4609 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4611 m_clipPaintRegion
= FALSE
;
4615 // Find the wxWindow at the current mouse position, also returning the mouse
4617 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4619 pt
= wxGetMousePosition();
4620 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4624 // Get the current mouse position.
4625 wxPoint
wxGetMousePosition()
4627 /* This crashes when used within wxHelpContext,
4628 so we have to use the X-specific implementation below.
4630 GdkModifierType *mask;
4631 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4633 return wxPoint(x, y);
4637 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4639 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4640 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4641 Window rootReturn
, childReturn
;
4642 int rootX
, rootY
, winX
, winY
;
4643 unsigned int maskReturn
;
4645 XQueryPointer (display
,
4649 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4650 return wxPoint(rootX
, rootY
);
4654 // ----------------------------------------------------------------------------
4656 // ----------------------------------------------------------------------------
4658 class wxWinModule
: public wxModule
4665 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4668 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4670 bool wxWinModule::OnInit()
4672 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4673 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4678 void wxWinModule::OnExit()
4681 gdk_gc_unref( g_eraseGC
);