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" );
1786 //-----------------------------------------------------------------------------
1788 //-----------------------------------------------------------------------------
1790 // send the wxChildFocusEvent and wxFocusEvent, common code of
1791 // gtk_window_focus_in_callback() and SetFocus()
1792 static bool DoSendFocusEvents(wxWindow
*win
)
1794 // Notify the parent keeping track of focus for the kbd navigation
1795 // purposes that we got it.
1796 wxChildFocusEvent
eventChildFocus(win
);
1797 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1799 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1800 eventFocus
.SetEventObject(win
);
1802 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1805 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1806 GdkEvent
*WXUNUSED(event
),
1812 wxapp_install_idle_handler();
1814 if (!win
->m_hasVMT
) return FALSE
;
1815 if (g_blockEventsOnDrag
) return FALSE
;
1817 switch ( g_sendActivateEvent
)
1820 // we've got focus from outside, synthetize wxActivateEvent
1821 g_sendActivateEvent
= 1;
1825 // another our window just lost focus, it was already ours before
1826 // - don't send any wxActivateEvent
1827 g_sendActivateEvent
= -1;
1832 g_focusWindow
= win
;
1834 wxLogTrace(TRACE_FOCUS
,
1835 _T("%s: focus in"), win
->GetName().c_str());
1839 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1843 // caret needs to be informed about focus change
1844 wxCaret
*caret
= win
->GetCaret();
1847 caret
->OnSetFocus();
1849 #endif // wxUSE_CARET
1851 g_activeFrameLostFocus
= FALSE
;
1853 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1854 if ( active
!= g_activeFrame
)
1856 if ( g_activeFrame
)
1858 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1859 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1860 event
.SetEventObject(g_activeFrame
);
1861 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1864 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1865 g_activeFrame
= active
;
1866 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1867 event
.SetEventObject(g_activeFrame
);
1868 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1870 // Don't send focus events in addition to activate
1871 // if (win == g_activeFrame)
1875 // does the window itself think that it has the focus?
1876 if ( !win
->m_hasFocus
)
1878 // not yet, notify it
1879 win
->m_hasFocus
= TRUE
;
1881 if ( DoSendFocusEvents(win
) )
1883 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1891 //-----------------------------------------------------------------------------
1892 // "focus_out_event"
1893 //-----------------------------------------------------------------------------
1895 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1900 wxapp_install_idle_handler();
1902 if (!win
->m_hasVMT
) return FALSE
;
1903 if (g_blockEventsOnDrag
) return FALSE
;
1905 wxLogTrace( TRACE_FOCUS
,
1906 _T("%s: focus out"), win
->GetName().c_str() );
1908 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1910 // VZ: commenting this out because it does happen (although not easy
1911 // to reproduce, I only see it when using wxMiniFrame and not
1912 // always) and makes using Mahogany quite annoying
1914 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1915 wxT("unfocusing window that hasn't gained focus properly") );
1918 g_activeFrameLostFocus
= TRUE
;
1921 // if the focus goes out of our app alltogether, OnIdle() will send
1922 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1923 // g_sendActivateEvent to -1
1924 g_sendActivateEvent
= 0;
1926 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1930 g_focusWindow
= (wxWindowGTK
*)NULL
;
1938 // caret needs to be informed about focus change
1939 wxCaret
*caret
= win
->GetCaret();
1942 caret
->OnKillFocus();
1944 #endif // wxUSE_CARET
1946 // don't send the window a kill focus event if it thinks that it doesn't
1947 // have focus already
1948 if ( win
->m_hasFocus
)
1950 win
->m_hasFocus
= FALSE
;
1952 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1953 event
.SetEventObject( win
);
1955 if (win
->GetEventHandler()->ProcessEvent( event
))
1957 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1965 //-----------------------------------------------------------------------------
1966 // "enter_notify_event"
1967 //-----------------------------------------------------------------------------
1970 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1971 GdkEventCrossing
*gdk_event
,
1977 wxapp_install_idle_handler();
1979 if (!win
->m_hasVMT
) return FALSE
;
1980 if (g_blockEventsOnDrag
) return FALSE
;
1982 // Event was emitted after a grab
1983 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1985 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1989 GdkModifierType state
= (GdkModifierType
)0;
1991 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1993 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1994 InitMouseEvent(win
, event
, gdk_event
);
1995 wxPoint pt
= win
->GetClientAreaOrigin();
1996 event
.m_x
= x
+ pt
.x
;
1997 event
.m_y
= y
+ pt
.y
;
1999 if (win
->GetEventHandler()->ProcessEvent( event
))
2001 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2008 //-----------------------------------------------------------------------------
2009 // "leave_notify_event"
2010 //-----------------------------------------------------------------------------
2012 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2017 wxapp_install_idle_handler();
2019 if (!win
->m_hasVMT
) return FALSE
;
2020 if (g_blockEventsOnDrag
) return FALSE
;
2022 // Event was emitted after an ungrab
2023 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2025 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2027 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2028 event
.SetTimestamp( gdk_event
->time
);
2029 event
.SetEventObject( win
);
2033 GdkModifierType state
= (GdkModifierType
)0;
2035 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2037 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2038 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2039 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2040 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2041 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2042 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2043 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2045 wxPoint pt
= win
->GetClientAreaOrigin();
2046 event
.m_x
= x
+ pt
.x
;
2047 event
.m_y
= y
+ pt
.y
;
2049 if (win
->GetEventHandler()->ProcessEvent( event
))
2051 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2058 //-----------------------------------------------------------------------------
2059 // "value_changed" from m_vAdjust
2060 //-----------------------------------------------------------------------------
2062 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2069 wxapp_install_idle_handler();
2071 if (g_blockEventsOnDrag
) return;
2073 if (!win
->m_hasVMT
) return;
2075 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2076 if (fabs(diff
) < 0.2) return;
2078 win
->m_oldVerticalPos
= adjust
->value
;
2081 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2083 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2085 int value
= (int)(adjust
->value
+0.5);
2087 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2088 event
.SetEventObject( win
);
2089 win
->GetEventHandler()->ProcessEvent( event
);
2092 //-----------------------------------------------------------------------------
2093 // "value_changed" from m_hAdjust
2094 //-----------------------------------------------------------------------------
2096 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2103 wxapp_install_idle_handler();
2105 if (g_blockEventsOnDrag
) return;
2106 if (!win
->m_hasVMT
) return;
2108 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2109 if (fabs(diff
) < 0.2) return;
2112 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2114 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2116 win
->m_oldHorizontalPos
= adjust
->value
;
2118 int value
= (int)(adjust
->value
+0.5);
2120 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2121 event
.SetEventObject( win
);
2122 win
->GetEventHandler()->ProcessEvent( event
);
2125 //-----------------------------------------------------------------------------
2126 // "button_press_event" from scrollbar
2127 //-----------------------------------------------------------------------------
2129 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2130 GdkEventButton
*gdk_event
,
2136 wxapp_install_idle_handler();
2139 g_blockEventsOnScroll
= TRUE
;
2141 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2143 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2149 //-----------------------------------------------------------------------------
2150 // "button_release_event" from scrollbar
2151 //-----------------------------------------------------------------------------
2153 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2154 GdkEventButton
*WXUNUSED(gdk_event
),
2159 // don't test here as we can release the mouse while being over
2160 // a different window than the slider
2162 // if (gdk_event->window != widget->slider) return FALSE;
2164 g_blockEventsOnScroll
= FALSE
;
2166 if (win
->m_isScrolling
)
2168 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2172 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2173 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2175 value
= (int)(win
->m_hAdjust
->value
+0.5);
2178 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2180 value
= (int)(win
->m_vAdjust
->value
+0.5);
2184 wxScrollWinEvent
event( command
, value
, dir
);
2185 event
.SetEventObject( win
);
2186 win
->GetEventHandler()->ProcessEvent( event
);
2189 win
->m_isScrolling
= FALSE
;
2194 // ----------------------------------------------------------------------------
2195 // this wxWindowBase function is implemented here (in platform-specific file)
2196 // because it is static and so couldn't be made virtual
2197 // ----------------------------------------------------------------------------
2199 wxWindow
*wxWindowBase::FindFocus()
2201 // the cast is necessary when we compile in wxUniversal mode
2202 return (wxWindow
*)g_focusWindow
;
2206 //-----------------------------------------------------------------------------
2207 // "realize" from m_widget
2208 //-----------------------------------------------------------------------------
2210 /* We cannot set colours and fonts before the widget has
2211 been realized, so we do this directly after realization. */
2214 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2219 wxapp_install_idle_handler();
2221 if (win
->m_delayedBackgroundColour
&& !win
->GetThemeEnabled())
2222 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2224 if (win
->m_delayedForegroundColour
&& !win
->GetThemeEnabled())
2225 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2228 if (win
->m_imContext
)
2230 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2231 gtk_im_context_set_client_window( (GtkIMContext
*) win
->m_imContext
, pizza
->bin_window
);
2235 wxWindowCreateEvent
event( win
);
2236 event
.SetEventObject( win
);
2237 win
->GetEventHandler()->ProcessEvent( event
);
2242 //-----------------------------------------------------------------------------
2244 //-----------------------------------------------------------------------------
2247 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2248 GtkAllocation
*WXUNUSED(alloc
),
2252 wxapp_install_idle_handler();
2254 if (!win
->m_hasScrolling
) return;
2256 int client_width
= 0;
2257 int client_height
= 0;
2258 win
->GetClientSize( &client_width
, &client_height
);
2259 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2262 win
->m_oldClientWidth
= client_width
;
2263 win
->m_oldClientHeight
= client_height
;
2265 if (!win
->m_nativeSizeEvent
)
2267 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2268 event
.SetEventObject( win
);
2269 win
->GetEventHandler()->ProcessEvent( event
);
2275 #define WXUNUSED_UNLESS_XIM(param) param
2277 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2280 /* Resize XIM window */
2283 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2284 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2285 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2288 wxapp_install_idle_handler();
2294 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2298 gdk_window_get_size (widget
->window
, &width
, &height
);
2299 win
->m_icattr
->preedit_area
.width
= width
;
2300 win
->m_icattr
->preedit_area
.height
= height
;
2301 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2306 //-----------------------------------------------------------------------------
2307 // "realize" from m_wxwindow
2308 //-----------------------------------------------------------------------------
2310 /* Initialize XIM support */
2313 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2314 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2317 wxapp_install_idle_handler();
2320 if (win
->m_ic
) return FALSE
;
2321 if (!widget
) return FALSE
;
2322 if (!gdk_im_ready()) return FALSE
;
2324 win
->m_icattr
= gdk_ic_attr_new();
2325 if (!win
->m_icattr
) return FALSE
;
2329 GdkColormap
*colormap
;
2330 GdkICAttr
*attr
= win
->m_icattr
;
2331 unsigned attrmask
= GDK_IC_ALL_REQ
;
2333 GdkIMStyle supported_style
= (GdkIMStyle
)
2334 (GDK_IM_PREEDIT_NONE
|
2335 GDK_IM_PREEDIT_NOTHING
|
2336 GDK_IM_PREEDIT_POSITION
|
2337 GDK_IM_STATUS_NONE
|
2338 GDK_IM_STATUS_NOTHING
);
2340 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2341 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2343 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2344 attr
->client_window
= widget
->window
;
2346 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2347 gtk_widget_get_default_colormap ())
2349 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2350 attr
->preedit_colormap
= colormap
;
2353 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2354 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2355 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2356 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2358 switch (style
& GDK_IM_PREEDIT_MASK
)
2360 case GDK_IM_PREEDIT_POSITION
:
2361 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2363 g_warning ("over-the-spot style requires fontset");
2367 gdk_window_get_size (widget
->window
, &width
, &height
);
2369 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2370 attr
->spot_location
.x
= 0;
2371 attr
->spot_location
.y
= height
;
2372 attr
->preedit_area
.x
= 0;
2373 attr
->preedit_area
.y
= 0;
2374 attr
->preedit_area
.width
= width
;
2375 attr
->preedit_area
.height
= height
;
2376 attr
->preedit_fontset
= widget
->style
->font
;
2381 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2383 if (win
->m_ic
== NULL
)
2384 g_warning ("Can't create input context.");
2387 mask
= gdk_window_get_events (widget
->window
);
2388 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2389 gdk_window_set_events (widget
->window
, mask
);
2391 if (GTK_WIDGET_HAS_FOCUS(widget
))
2392 gdk_im_begin (win
->m_ic
, widget
->window
);
2399 //-----------------------------------------------------------------------------
2400 // InsertChild for wxWindowGTK.
2401 //-----------------------------------------------------------------------------
2403 /* Callback for wxWindowGTK. This very strange beast has to be used because
2404 * C++ has no virtual methods in a constructor. We have to emulate a
2405 * virtual function here as wxNotebook requires a different way to insert
2406 * a child in it. I had opted for creating a wxNotebookPage window class
2407 * which would have made this superfluous (such in the MDI window system),
2408 * but no-one was listening to me... */
2410 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2412 /* the window might have been scrolled already, do we
2413 have to adapt the position */
2414 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2415 child
->m_x
+= pizza
->xoffset
;
2416 child
->m_y
+= pizza
->yoffset
;
2418 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2419 GTK_WIDGET(child
->m_widget
),
2426 //-----------------------------------------------------------------------------
2428 //-----------------------------------------------------------------------------
2430 wxWindow
*wxGetActiveWindow()
2432 return wxWindow::FindFocus();
2435 //-----------------------------------------------------------------------------
2437 //-----------------------------------------------------------------------------
2439 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2441 #ifdef __WXUNIVERSAL__
2442 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2444 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2445 #endif // __WXUNIVERSAL__/__WXGTK__
2447 void wxWindowGTK::Init()
2450 m_widget
= (GtkWidget
*) NULL
;
2451 m_wxwindow
= (GtkWidget
*) NULL
;
2452 m_focusWidget
= (GtkWidget
*) NULL
;
2462 m_needParent
= TRUE
;
2463 m_isBeingDeleted
= FALSE
;
2466 m_nativeSizeEvent
= FALSE
;
2468 m_hasScrolling
= FALSE
;
2469 m_isScrolling
= FALSE
;
2471 m_hAdjust
= (GtkAdjustment
*) NULL
;
2472 m_vAdjust
= (GtkAdjustment
*) NULL
;
2473 m_oldHorizontalPos
=
2474 m_oldVerticalPos
= 0.0;
2476 m_oldClientHeight
= 0;
2479 m_widgetStyle
= (GtkStyle
*) NULL
;
2481 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2483 m_acceptsFocus
= FALSE
;
2486 m_clipPaintRegion
= FALSE
;
2488 m_cursor
= *wxSTANDARD_CURSOR
;
2490 m_delayedForegroundColour
= FALSE
;
2491 m_delayedBackgroundColour
= FALSE
;
2495 m_x11Context
= NULL
;
2498 m_ic
= (GdkIC
*) NULL
;
2499 m_icattr
= (GdkICAttr
*) NULL
;
2504 wxWindowGTK::wxWindowGTK()
2509 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2514 const wxString
&name
)
2518 Create( parent
, id
, pos
, size
, style
, name
);
2521 bool wxWindowGTK::Create( wxWindow
*parent
,
2526 const wxString
&name
)
2528 if (!PreCreation( parent
, pos
, size
) ||
2529 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2531 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2535 m_insertCallback
= wxInsertChildInWindow
;
2537 // always needed for background clearing
2538 m_delayedBackgroundColour
= TRUE
;
2540 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2541 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2543 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2545 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2546 scroll_class
->scrollbar_spacing
= 0;
2548 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2550 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2551 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2553 m_wxwindow
= gtk_pizza_new();
2555 #ifndef __WXUNIVERSAL__
2556 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2558 if (HasFlag(wxRAISED_BORDER
))
2560 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2562 else if (HasFlag(wxSUNKEN_BORDER
))
2564 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2566 else if (HasFlag(wxSIMPLE_BORDER
))
2568 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2572 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2574 #endif // __WXUNIVERSAL__
2576 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2578 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2579 m_acceptsFocus
= TRUE
;
2581 // I _really_ don't want scrollbars in the beginning
2582 m_vAdjust
->lower
= 0.0;
2583 m_vAdjust
->upper
= 1.0;
2584 m_vAdjust
->value
= 0.0;
2585 m_vAdjust
->step_increment
= 1.0;
2586 m_vAdjust
->page_increment
= 1.0;
2587 m_vAdjust
->page_size
= 5.0;
2588 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2589 m_hAdjust
->lower
= 0.0;
2590 m_hAdjust
->upper
= 1.0;
2591 m_hAdjust
->value
= 0.0;
2592 m_hAdjust
->step_increment
= 1.0;
2593 m_hAdjust
->page_increment
= 1.0;
2594 m_hAdjust
->page_size
= 5.0;
2595 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2597 // these handlers block mouse events to any window during scrolling such as
2598 // motion events and prevent GTK and wxWindows from fighting over where the
2601 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2602 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2604 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2605 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2607 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2608 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2610 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2611 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2613 // these handlers get notified when screen updates are required either when
2614 // scrolling or when the window size (and therefore scrollbar configuration)
2617 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2618 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2619 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2620 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2623 // Create input method handler
2624 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2626 // Cannot handle drawing preedited text yet
2627 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2629 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2630 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2633 gtk_widget_show( m_wxwindow
);
2636 m_parent
->DoAddChild( this );
2638 m_focusWidget
= m_wxwindow
;
2647 wxWindowGTK::~wxWindowGTK()
2651 if (g_focusWindow
== this)
2652 g_focusWindow
= NULL
;
2654 if (g_activeFrame
== this)
2655 g_activeFrame
= NULL
;
2657 if ( g_delayedFocus
== this )
2658 g_delayedFocus
= NULL
;
2660 m_isBeingDeleted
= TRUE
;
2670 gdk_ic_destroy (m_ic
);
2672 gdk_ic_attr_destroy (m_icattr
);
2677 #if DISABLE_STYLE_IF_BROKEN_THEME
2678 // don't delete if it's a pixmap theme style
2679 if (!m_widgetStyle
->engine_data
)
2680 gtk_style_unref( m_widgetStyle
);
2682 m_widgetStyle
= (GtkStyle
*) NULL
;
2687 gtk_widget_destroy( m_wxwindow
);
2688 m_wxwindow
= (GtkWidget
*) NULL
;
2693 gtk_widget_destroy( m_widget
);
2694 m_widget
= (GtkWidget
*) NULL
;
2698 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2700 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2702 // This turns -1 into 30 so that a minimal window is
2703 // visible even although -1,-1 has been given as the
2704 // size of the window. the same trick is used in other
2705 // ports and should make debugging easier.
2706 m_width
= WidthDefault(size
.x
) ;
2707 m_height
= HeightDefault(size
.y
);
2712 // some reasonable defaults
2717 m_x
= (gdk_screen_width () - m_width
) / 2;
2718 if (m_x
< 10) m_x
= 10;
2722 m_y
= (gdk_screen_height () - m_height
) / 2;
2723 if (m_y
< 10) m_y
= 10;
2730 void wxWindowGTK::PostCreation()
2732 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2738 // these get reported to wxWindows -> wxPaintEvent
2740 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2742 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2743 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2746 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2747 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2749 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2751 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2752 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2755 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2759 // Create input method handler
2760 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2762 // Cannot handle drawing preedited text yet
2763 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2765 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2766 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2770 // these are called when the "sunken" or "raised" borders are drawn
2771 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2772 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2775 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2776 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2782 if (m_focusWidget
== NULL
)
2783 m_focusWidget
= m_widget
;
2785 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2786 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2788 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2789 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2791 // connect to the various key and mouse handlers
2793 GtkWidget
*connect_widget
= GetConnectWidget();
2795 ConnectWidget( connect_widget
);
2797 /* We cannot set colours, fonts and cursors before the widget has
2798 been realized, so we do this directly after realization */
2799 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2800 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2804 // Catch native resize events
2805 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2806 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2808 // Initialize XIM support
2809 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2810 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2812 // And resize XIM window
2813 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2814 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2817 if ( !GTK_IS_COMBO(m_widget
))
2819 // This is needed if we want to add our windows into native
2820 // GTK control, such as the toolbar. With this callback, the
2821 // toolbar gets to know the correct size (the one set by the
2822 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2823 // when moving to GTK 2.0.
2824 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2825 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2832 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2834 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2835 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2837 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2838 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2840 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2841 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2843 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2844 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2846 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2847 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2849 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2850 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2852 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2853 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2856 bool wxWindowGTK::Destroy()
2858 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2862 return wxWindowBase::Destroy();
2865 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2867 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2870 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2872 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2873 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2876 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2879 if (m_resizing
) return; /* I don't like recursions */
2882 int currentX
, currentY
;
2883 GetPosition(¤tX
, ¤tY
);
2884 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2886 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2888 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2890 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2892 /* don't set the size for children of wxNotebook, just take the values. */
2900 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2901 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2903 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2904 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2908 m_x
= x
+ pizza
->xoffset
;
2909 m_y
= y
+ pizza
->yoffset
;
2911 if (width
!= -1) m_width
= width
;
2912 if (height
!= -1) m_height
= height
;
2914 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2916 if (width
== -1) m_width
= 80;
2919 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2921 if (height
== -1) m_height
= 26;
2924 int minWidth
= GetMinWidth(),
2925 minHeight
= GetMinHeight(),
2926 maxWidth
= GetMaxWidth(),
2927 maxHeight
= GetMaxHeight();
2929 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2930 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2931 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2932 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2935 int bottom_border
= 0;
2938 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2940 /* the default button has a border around it */
2946 DoMoveWindow( m_x
-border
,
2949 m_height
+border
+bottom_border
);
2954 /* Sometimes the client area changes size without the
2955 whole windows's size changing, but if the whole
2956 windows's size doesn't change, no wxSizeEvent will
2957 normally be sent. Here we add an extra test if
2958 the client test has been changed and this will
2960 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2964 wxPrintf( "OnSize sent from " );
2965 if (GetClassInfo() && GetClassInfo()->GetClassName())
2966 wxPrintf( GetClassInfo()->GetClassName() );
2967 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2970 if (!m_nativeSizeEvent
)
2972 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2973 event
.SetEventObject( this );
2974 GetEventHandler()->ProcessEvent( event
);
2980 void wxWindowGTK::OnInternalIdle()
2982 // Update invalidated regions.
2985 // Synthetize activate events.
2986 if ( g_sendActivateEvent
!= -1 )
2988 bool activate
= g_sendActivateEvent
!= 0;
2991 g_sendActivateEvent
= -1;
2993 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2996 if ( g_activeFrameLostFocus
)
2998 if ( g_activeFrame
)
3000 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3001 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3002 event
.SetEventObject(g_activeFrame
);
3003 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3004 g_activeFrame
= NULL
;
3006 g_activeFrameLostFocus
= FALSE
;
3009 wxCursor cursor
= m_cursor
;
3010 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3014 /* I now set the cursor anew in every OnInternalIdle call
3015 as setting the cursor in a parent window also effects the
3016 windows above so that checking for the current cursor is
3021 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3023 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3025 if (!g_globalCursor
.Ok())
3026 cursor
= *wxSTANDARD_CURSOR
;
3028 window
= m_widget
->window
;
3029 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3030 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3036 GdkWindow
*window
= m_widget
->window
;
3037 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3038 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3043 if (wxUpdateUIEvent::CanUpdate(this))
3044 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3047 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3049 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3051 if (width
) (*width
) = m_width
;
3052 if (height
) (*height
) = m_height
;
3055 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3057 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3061 SetSize( width
, height
);
3068 #ifndef __WXUNIVERSAL__
3069 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3071 /* when using GTK 1.2 we set the shadow border size to 2 */
3075 if (HasFlag(wxSIMPLE_BORDER
))
3077 /* when using GTK 1.2 we set the simple border size to 1 */
3081 #endif // __WXUNIVERSAL__
3085 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3087 GtkRequisition vscroll_req
;
3088 vscroll_req
.width
= 2;
3089 vscroll_req
.height
= 2;
3090 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3091 (scroll_window
->vscrollbar
, &vscroll_req
);
3093 GtkRequisition hscroll_req
;
3094 hscroll_req
.width
= 2;
3095 hscroll_req
.height
= 2;
3096 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3097 (scroll_window
->hscrollbar
, &hscroll_req
);
3099 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3101 if (scroll_window
->vscrollbar_visible
)
3103 dw
+= vscroll_req
.width
;
3104 dw
+= scroll_class
->scrollbar_spacing
;
3107 if (scroll_window
->hscrollbar_visible
)
3109 dh
+= hscroll_req
.height
;
3110 dh
+= scroll_class
->scrollbar_spacing
;
3114 SetSize( width
+dw
, height
+dh
);
3118 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3120 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3124 if (width
) (*width
) = m_width
;
3125 if (height
) (*height
) = m_height
;
3132 #ifndef __WXUNIVERSAL__
3133 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3135 /* when using GTK 1.2 we set the shadow border size to 2 */
3139 if (HasFlag(wxSIMPLE_BORDER
))
3141 /* when using GTK 1.2 we set the simple border size to 1 */
3145 #endif // __WXUNIVERSAL__
3149 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3151 GtkRequisition vscroll_req
;
3152 vscroll_req
.width
= 2;
3153 vscroll_req
.height
= 2;
3154 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3155 (scroll_window
->vscrollbar
, &vscroll_req
);
3157 GtkRequisition hscroll_req
;
3158 hscroll_req
.width
= 2;
3159 hscroll_req
.height
= 2;
3160 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3161 (scroll_window
->hscrollbar
, &hscroll_req
);
3163 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3165 if (scroll_window
->vscrollbar_visible
)
3167 dw
+= vscroll_req
.width
;
3168 dw
+= scroll_class
->scrollbar_spacing
;
3171 if (scroll_window
->hscrollbar_visible
)
3173 dh
+= hscroll_req
.height
;
3174 dh
+= scroll_class
->scrollbar_spacing
;
3178 if (width
) (*width
) = m_width
- dw
;
3179 if (height
) (*height
) = m_height
- dh
;
3183 printf( "GetClientSize, name %s ", GetName().c_str() );
3184 if (width) printf( " width = %d", (*width) );
3185 if (height) printf( " height = %d", (*height) );
3190 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3192 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3196 if (m_parent
&& m_parent
->m_wxwindow
)
3198 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3199 dx
= pizza
->xoffset
;
3200 dy
= pizza
->yoffset
;
3203 if (x
) (*x
) = m_x
- dx
;
3204 if (y
) (*y
) = m_y
- dy
;
3207 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3209 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3211 if (!m_widget
->window
) return;
3213 GdkWindow
*source
= (GdkWindow
*) NULL
;
3215 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3217 source
= m_widget
->window
;
3221 gdk_window_get_origin( source
, &org_x
, &org_y
);
3225 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3227 org_x
+= m_widget
->allocation
.x
;
3228 org_y
+= m_widget
->allocation
.y
;
3236 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3238 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3240 if (!m_widget
->window
) return;
3242 GdkWindow
*source
= (GdkWindow
*) NULL
;
3244 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3246 source
= m_widget
->window
;
3250 gdk_window_get_origin( source
, &org_x
, &org_y
);
3254 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3256 org_x
+= m_widget
->allocation
.x
;
3257 org_y
+= m_widget
->allocation
.y
;
3265 bool wxWindowGTK::Show( bool show
)
3267 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3269 if (!wxWindowBase::Show(show
))
3276 gtk_widget_show( m_widget
);
3278 gtk_widget_hide( m_widget
);
3280 wxShowEvent
eventShow(GetId(), show
);
3281 eventShow
.m_eventObject
= this;
3283 GetEventHandler()->ProcessEvent(eventShow
);
3288 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3290 win
->OnParentEnable(enable
);
3292 // Recurse, so that children have the opportunity to Do The Right Thing
3293 // and reset colours that have been messed up by a parent's (really ancestor's)
3295 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3297 node
= node
->GetNext() )
3299 wxWindow
*child
= node
->GetData();
3300 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3301 wxWindowNotifyEnable(child
, enable
);
3305 bool wxWindowGTK::Enable( bool enable
)
3307 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3309 if (!wxWindowBase::Enable(enable
))
3315 gtk_widget_set_sensitive( m_widget
, enable
);
3317 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3319 wxWindowNotifyEnable(this, enable
);
3324 int wxWindowGTK::GetCharHeight() const
3326 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3328 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3331 PangoContext
*context
= NULL
;
3333 context
= gtk_widget_get_pango_context( m_widget
);
3338 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3339 PangoLayout
*layout
= pango_layout_new(context
);
3340 pango_layout_set_font_description(layout
, desc
);
3341 pango_layout_set_text(layout
, "H", 1);
3342 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3344 PangoRectangle rect
;
3345 pango_layout_line_get_extents(line
, NULL
, &rect
);
3347 g_object_unref( G_OBJECT( layout
) );
3349 return (int) (rect
.height
/ PANGO_SCALE
);
3351 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3353 return font
->ascent
+ font
->descent
;
3357 int wxWindowGTK::GetCharWidth() const
3359 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3361 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3364 PangoContext
*context
= NULL
;
3366 context
= gtk_widget_get_pango_context( m_widget
);
3371 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3372 PangoLayout
*layout
= pango_layout_new(context
);
3373 pango_layout_set_font_description(layout
, desc
);
3374 pango_layout_set_text(layout
, "H", 1);
3375 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3377 PangoRectangle rect
;
3378 pango_layout_line_get_extents(line
, NULL
, &rect
);
3380 g_object_unref( G_OBJECT( layout
) );
3382 return (int) (rect
.width
/ PANGO_SCALE
);
3384 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3386 return gdk_string_width( font
, "H" );
3390 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3394 int *externalLeading
,
3395 const wxFont
*theFont
) const
3397 wxFont fontToUse
= m_font
;
3398 if (theFont
) fontToUse
= *theFont
;
3400 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3402 if (string
.IsEmpty())
3410 PangoContext
*context
= NULL
;
3412 context
= gtk_widget_get_pango_context( m_widget
);
3421 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3422 PangoLayout
*layout
= pango_layout_new(context
);
3423 pango_layout_set_font_description(layout
, desc
);
3426 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3427 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3429 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3430 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3431 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3434 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3436 PangoRectangle rect
;
3437 pango_layout_line_get_extents(line
, NULL
, &rect
);
3439 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3440 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3443 // Do something about metrics here
3446 if (externalLeading
) (*externalLeading
) = 0; // ??
3448 g_object_unref( G_OBJECT( layout
) );
3450 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3451 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3452 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3453 if (descent
) (*descent
) = font
->descent
;
3454 if (externalLeading
) (*externalLeading
) = 0; // ??
3458 void wxWindowGTK::SetFocus()
3460 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3464 // don't do anything if we already have focus
3470 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3472 gtk_widget_grab_focus (m_wxwindow
);
3477 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3479 if (!GTK_WIDGET_REALIZED(m_widget
))
3481 // we can't set the focus to the widget now so we remember that
3482 // it should be focused and will do it later, during the idle
3483 // time, as soon as we can
3484 wxLogTrace(TRACE_FOCUS
,
3485 _T("Delaying setting focus to %s(%s)"),
3486 GetClassInfo()->GetClassName(), GetLabel().c_str());
3488 g_delayedFocus
= this;
3492 wxLogTrace(TRACE_FOCUS
,
3493 _T("Setting focus to %s(%s)"),
3494 GetClassInfo()->GetClassName(), GetLabel().c_str());
3496 gtk_widget_grab_focus (m_widget
);
3499 else if (GTK_IS_CONTAINER(m_widget
))
3501 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3505 wxLogTrace(TRACE_FOCUS
,
3506 _T("Can't set focus to %s(%s)"),
3507 GetClassInfo()->GetClassName(), GetLabel().c_str());
3512 bool wxWindowGTK::AcceptsFocus() const
3514 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3517 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3519 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3521 wxWindowGTK
*oldParent
= m_parent
,
3522 *newParent
= (wxWindowGTK
*)newParentBase
;
3524 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3526 if ( !wxWindowBase::Reparent(newParent
) )
3529 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3531 /* prevent GTK from deleting the widget arbitrarily */
3532 gtk_widget_ref( m_widget
);
3536 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3539 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3543 /* insert GTK representation */
3544 (*(newParent
->m_insertCallback
))(newParent
, this);
3547 /* reverse: prevent GTK from deleting the widget arbitrarily */
3548 gtk_widget_unref( m_widget
);
3553 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3555 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3557 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3559 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3564 /* insert GTK representation */
3565 (*m_insertCallback
)(this, child
);
3568 void wxWindowGTK::Raise()
3570 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3572 if (!m_widget
->window
) return;
3574 gdk_window_raise( m_widget
->window
);
3577 void wxWindowGTK::Lower()
3579 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3581 if (!m_widget
->window
) return;
3583 gdk_window_lower( m_widget
->window
);
3586 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3588 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3590 if (cursor
== m_cursor
)
3594 wxapp_install_idle_handler();
3596 if (cursor
== wxNullCursor
)
3597 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3599 return wxWindowBase::SetCursor( cursor
);
3602 void wxWindowGTK::WarpPointer( int x
, int y
)
3604 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3606 // We provide this function ourselves as it is
3607 // missing in GDK (top of this file).
3609 GdkWindow
*window
= (GdkWindow
*) NULL
;
3611 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3613 window
= GetConnectWidget()->window
;
3616 gdk_window_warp_pointer( window
, x
, y
);
3620 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3622 if (!m_widget
) return;
3623 if (!m_widget
->window
) return;
3627 wxapp_install_idle_handler();
3629 wxRect
myRect(0,0,0,0);
3630 if (m_wxwindow
&& rect
)
3632 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3633 m_wxwindow
->allocation
.height
));
3634 myRect
.Intersect(*rect
);
3635 if (!myRect
.width
|| !myRect
.height
)
3636 // nothing to do, rectangle is empty
3641 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3645 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3646 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3650 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3651 m_clearRegion
.Clear();
3652 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3660 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3661 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3665 GdkRectangle gdk_rect
;
3666 gdk_rect
.x
= rect
->x
;
3667 gdk_rect
.y
= rect
->y
;
3668 gdk_rect
.width
= rect
->width
;
3669 gdk_rect
.height
= rect
->height
;
3670 gtk_widget_draw( m_widget
, &gdk_rect
);
3677 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3678 m_updateRegion
.Clear();
3679 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3683 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3691 GdkRectangle gdk_rect
;
3692 gdk_rect
.x
= rect
->x
;
3693 gdk_rect
.y
= rect
->y
;
3694 gdk_rect
.width
= rect
->width
;
3695 gdk_rect
.height
= rect
->height
;
3696 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3700 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3706 void wxWindowGTK::Update()
3711 void wxWindowGTK::GtkUpdate()
3714 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3715 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3717 if (!m_updateRegion
.IsEmpty())
3718 GtkSendPaintEvents();
3722 void wxWindowGTK::GtkSendPaintEvents()
3727 m_clearRegion
.Clear();
3729 m_updateRegion
.Clear();
3733 // Clip to paint region in wxClientDC
3734 m_clipPaintRegion
= TRUE
;
3737 // widget to draw on
3738 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3740 // later for GTK 2.0, too.
3741 if (GetThemeEnabled())
3743 // find ancestor from which to steal background
3744 wxWindow
*parent
= GetParent();
3745 while (parent
&& !parent
->IsTopLevel())
3746 parent
= parent
->GetParent();
3748 parent
= (wxWindow
*)this;
3750 wxRegionIterator
upd( m_updateRegion
);
3754 rect
.x
= upd
.GetX();
3755 rect
.y
= upd
.GetY();
3756 rect
.width
= upd
.GetWidth();
3757 rect
.height
= upd
.GetHeight();
3759 gtk_paint_flat_box( parent
->m_widget
->style
,
3776 wxWindowDC
dc( (wxWindow
*)this );
3777 dc
.SetClippingRegion( m_updateRegion
);
3779 wxEraseEvent
erase_event( GetId(), &dc
);
3780 erase_event
.SetEventObject( this );
3782 GetEventHandler()->ProcessEvent(erase_event
);
3785 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3787 wxWindowDC
dc( (wxWindow
*)this );
3788 if (m_clearRegion
.IsEmpty())
3789 dc
.SetClippingRegion( m_updateRegion
);
3791 dc
.SetClippingRegion( m_clearRegion
);
3793 wxEraseEvent
erase_event( GetId(), &dc
);
3794 erase_event
.SetEventObject( this );
3796 if (!GetEventHandler()->ProcessEvent(erase_event
))
3800 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3801 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3803 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3805 wxRegionIterator
upd( m_clearRegion
);
3808 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3809 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3813 m_clearRegion
.Clear();
3817 wxNcPaintEvent
nc_paint_event( GetId() );
3818 nc_paint_event
.SetEventObject( this );
3819 GetEventHandler()->ProcessEvent( nc_paint_event
);
3821 wxPaintEvent
paint_event( GetId() );
3822 paint_event
.SetEventObject( this );
3823 GetEventHandler()->ProcessEvent( paint_event
);
3825 m_clipPaintRegion
= FALSE
;
3827 #ifndef __WXUNIVERSAL__
3829 // The following code will result in all window-less widgets
3830 // being redrawn because the wxWindows class is allowed to
3831 // paint over the window-less widgets.
3833 GList
*children
= pizza
->children
;
3836 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3837 children
= children
->next
;
3839 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3840 GTK_WIDGET_DRAWABLE (child
->widget
))
3842 // Get intersection of widget area and update region
3843 wxRegion
region( m_updateRegion
);
3845 GdkEventExpose gdk_event
;
3846 gdk_event
.type
= GDK_EXPOSE
;
3847 gdk_event
.window
= pizza
->bin_window
;
3848 gdk_event
.count
= 0;
3850 wxRegionIterator
upd( m_updateRegion
);
3854 rect
.x
= upd
.GetX();
3855 rect
.y
= upd
.GetY();
3856 rect
.width
= upd
.GetWidth();
3857 rect
.height
= upd
.GetHeight();
3859 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3861 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3871 m_updateRegion
.Clear();
3874 void wxWindowGTK::ClearBackground()
3876 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3879 if (m_wxwindow
&& m_wxwindow
->window
)
3881 m_clearRegion
.Clear();
3882 wxSize
size( GetClientSize() );
3883 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3885 // Better do this in idle?
3892 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3894 wxWindowBase::DoSetToolTip(tip
);
3897 m_tooltip
->Apply( (wxWindow
*)this );
3900 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3902 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3904 #endif // wxUSE_TOOLTIPS
3906 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3908 GdkWindow
*window
= (GdkWindow
*) NULL
;
3910 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3912 window
= GetConnectWidget()->window
;
3916 // We need the pixel value e.g. for background clearing.
3917 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3921 // wxMSW doesn't clear the window here, either.
3922 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3928 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3930 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3932 if (!wxWindowBase::SetBackgroundColour(colour
))
3935 GdkWindow
*window
= (GdkWindow
*) NULL
;
3937 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3939 window
= GetConnectWidget()->window
;
3943 // indicate that a new style has been set
3944 // but it couldn't get applied as the
3945 // widget hasn't been realized yet.
3946 m_delayedBackgroundColour
= TRUE
;
3951 GtkSetBackgroundColour( colour
);
3957 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3959 GdkWindow
*window
= (GdkWindow
*) NULL
;
3961 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3963 window
= GetConnectWidget()->window
;
3970 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3972 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3974 if (!wxWindowBase::SetForegroundColour(colour
))
3976 // don't leave if the GTK widget has just
3978 if (!m_delayedForegroundColour
) return FALSE
;
3981 GdkWindow
*window
= (GdkWindow
*) NULL
;
3983 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3985 window
= GetConnectWidget()->window
;
3989 // indicate that a new style has been set
3990 // but it couldn't get applied as the
3991 // widget hasn't been realized yet.
3992 m_delayedForegroundColour
= TRUE
;
3996 GtkSetForegroundColour( colour
);
4003 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4005 return gtk_widget_get_pango_context( m_widget
);
4008 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4011 m_x11Context
= pango_x_get_context( gdk_display
);
4013 return m_x11Context
;
4017 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4021 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4023 // FIXME: no more klass in 2.0
4025 remake
->klass
= m_widgetStyle
->klass
;
4028 gtk_style_unref( m_widgetStyle
);
4029 m_widgetStyle
= remake
;
4033 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4036 def
= gtk_widget_get_default_style();
4038 m_widgetStyle
= gtk_style_copy( def
);
4040 // FIXME: no more klass in 2.0
4042 m_widgetStyle
->klass
= def
->klass
;
4046 return m_widgetStyle
;
4049 void wxWindowGTK::SetWidgetStyle()
4051 #if DISABLE_STYLE_IF_BROKEN_THEME
4052 if (m_widget
->style
->engine_data
)
4054 static bool s_warningPrinted
= FALSE
;
4055 if (!s_warningPrinted
)
4057 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
4058 s_warningPrinted
= TRUE
;
4060 m_widgetStyle
= m_widget
->style
;
4065 GtkStyle
*style
= GetWidgetStyle();
4067 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
4070 pango_font_description_free( style
->font_desc
);
4071 style
->font_desc
= pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4073 gdk_font_unref( style
->font
);
4074 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4078 if (m_foregroundColour
.Ok())
4080 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4081 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4083 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4084 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4085 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4089 // Try to restore the gtk default style. This is still a little
4090 // oversimplified for what is probably really needed here for controls
4091 // other than buttons, but is better than not being able to (re)set a
4092 // control's foreground colour to *wxBLACK -- RL
4093 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4096 def
= gtk_widget_get_default_style();
4098 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4099 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4100 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4104 if (m_backgroundColour
.Ok())
4106 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4107 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4109 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4110 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4111 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4112 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4113 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4114 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4115 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4116 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4120 // Try to restore the gtk default style. This is still a little
4121 // oversimplified for what is probably really needed here for controls
4122 // other than buttons, but is better than not being able to (re)set a
4123 // control's background colour to default grey and means resetting a
4124 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4126 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4129 def
= gtk_widget_get_default_style();
4131 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4132 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4133 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4134 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4135 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4136 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4137 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4138 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4143 void wxWindowGTK::ApplyWidgetStyle()
4147 //-----------------------------------------------------------------------------
4148 // Pop-up menu stuff
4149 //-----------------------------------------------------------------------------
4151 #if wxUSE_MENUS_NATIVE
4154 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4156 *is_waiting
= FALSE
;
4159 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4161 menu
->SetInvokingWindow( win
);
4162 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4165 wxMenuItem
*menuitem
= node
->GetData();
4166 if (menuitem
->IsSubMenu())
4168 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4171 node
= node
->GetNext();
4175 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
4176 // wxPopupMenuPositionCallback()
4178 // should be safe even in the MT case as the user can hardly popup 2 menus
4179 // simultaneously, can he?
4180 static gint gs_pop_x
= 0;
4181 static gint gs_pop_y
= 0;
4183 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4186 gboolean
* WXUNUSED(whatever
),
4188 gpointer
WXUNUSED(user_data
) )
4190 // ensure that the menu appears entirely on screen
4192 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4194 wxSize sizeScreen
= wxGetDisplaySize();
4196 gint xmax
= sizeScreen
.x
- req
.width
,
4197 ymax
= sizeScreen
.y
- req
.height
;
4199 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
4200 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
4203 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4205 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4207 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
4209 SetInvokingWindow( menu
, this );
4215 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
4217 bool is_waiting
= TRUE
;
4219 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4221 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4222 (gpointer
)&is_waiting
);
4225 GTK_MENU(menu
->m_menu
),
4226 (GtkWidget
*) NULL
, // parent menu shell
4227 (GtkWidget
*) NULL
, // parent menu item
4228 wxPopupMenuPositionCallback
, // function to position it
4229 NULL
, // client data
4230 0, // button used to activate it
4232 gtk_get_current_event_time()
4234 gs_timeLastClick
// the time of activation
4240 gtk_main_iteration();
4246 #endif // wxUSE_MENUS_NATIVE
4248 #if wxUSE_DRAG_AND_DROP
4250 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4252 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4254 GtkWidget
*dnd_widget
= GetConnectWidget();
4256 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4258 if (m_dropTarget
) delete m_dropTarget
;
4259 m_dropTarget
= dropTarget
;
4261 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4264 #endif // wxUSE_DRAG_AND_DROP
4266 GtkWidget
* wxWindowGTK::GetConnectWidget()
4268 GtkWidget
*connect_widget
= m_widget
;
4269 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4271 return connect_widget
;
4274 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4277 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4279 return (window
== m_widget
->window
);
4282 bool wxWindowGTK::SetFont( const wxFont
&font
)
4284 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4286 if (!wxWindowBase::SetFont(font
))
4291 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4292 if ( sysbg
== m_backgroundColour
)
4294 m_backgroundColour
= wxNullColour
;
4296 m_backgroundColour
= sysbg
;
4306 void wxWindowGTK::DoCaptureMouse()
4308 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4310 GdkWindow
*window
= (GdkWindow
*) NULL
;
4312 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4314 window
= GetConnectWidget()->window
;
4316 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4318 wxCursor
* cursor
= & m_cursor
;
4320 cursor
= wxSTANDARD_CURSOR
;
4322 gdk_pointer_grab( window
, FALSE
,
4324 (GDK_BUTTON_PRESS_MASK
|
4325 GDK_BUTTON_RELEASE_MASK
|
4326 GDK_POINTER_MOTION_HINT_MASK
|
4327 GDK_POINTER_MOTION_MASK
),
4329 cursor
->GetCursor(),
4330 (guint32
)GDK_CURRENT_TIME
);
4331 g_captureWindow
= this;
4332 g_captureWindowHasMouse
= TRUE
;
4335 void wxWindowGTK::DoReleaseMouse()
4337 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4339 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4341 g_captureWindow
= (wxWindowGTK
*) NULL
;
4343 GdkWindow
*window
= (GdkWindow
*) NULL
;
4345 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4347 window
= GetConnectWidget()->window
;
4352 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4356 wxWindow
*wxWindowBase::GetCapture()
4358 return (wxWindow
*)g_captureWindow
;
4361 bool wxWindowGTK::IsRetained() const
4366 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4367 int range
, bool refresh
)
4369 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4371 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4373 m_hasScrolling
= TRUE
;
4375 if (orient
== wxHORIZONTAL
)
4377 float fpos
= (float)pos
;
4378 float frange
= (float)range
;
4379 float fthumb
= (float)thumbVisible
;
4380 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4381 if (fpos
< 0.0) fpos
= 0.0;
4383 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4384 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4386 SetScrollPos( orient
, pos
, refresh
);
4390 m_oldHorizontalPos
= fpos
;
4392 m_hAdjust
->lower
= 0.0;
4393 m_hAdjust
->upper
= frange
;
4394 m_hAdjust
->value
= fpos
;
4395 m_hAdjust
->step_increment
= 1.0;
4396 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4397 m_hAdjust
->page_size
= fthumb
;
4401 float fpos
= (float)pos
;
4402 float frange
= (float)range
;
4403 float fthumb
= (float)thumbVisible
;
4404 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4405 if (fpos
< 0.0) fpos
= 0.0;
4407 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4408 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4410 SetScrollPos( orient
, pos
, refresh
);
4414 m_oldVerticalPos
= fpos
;
4416 m_vAdjust
->lower
= 0.0;
4417 m_vAdjust
->upper
= frange
;
4418 m_vAdjust
->value
= fpos
;
4419 m_vAdjust
->step_increment
= 1.0;
4420 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4421 m_vAdjust
->page_size
= fthumb
;
4424 if (orient
== wxHORIZONTAL
)
4425 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4427 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4430 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4432 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4434 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4436 if (orient
== wxHORIZONTAL
)
4438 float fpos
= (float)pos
;
4439 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4440 if (fpos
< 0.0) fpos
= 0.0;
4441 m_oldHorizontalPos
= fpos
;
4443 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4444 m_hAdjust
->value
= fpos
;
4448 float fpos
= (float)pos
;
4449 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4450 if (fpos
< 0.0) fpos
= 0.0;
4451 m_oldVerticalPos
= fpos
;
4453 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4454 m_vAdjust
->value
= fpos
;
4457 if (m_wxwindow
->window
)
4459 if (orient
== wxHORIZONTAL
)
4461 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4462 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4464 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4466 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4467 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4471 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4472 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4474 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4476 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4477 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4482 int wxWindowGTK::GetScrollThumb( int orient
) const
4484 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4486 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4488 if (orient
== wxHORIZONTAL
)
4489 return (int)(m_hAdjust
->page_size
+0.5);
4491 return (int)(m_vAdjust
->page_size
+0.5);
4494 int wxWindowGTK::GetScrollPos( int orient
) const
4496 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4498 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4500 if (orient
== wxHORIZONTAL
)
4501 return (int)(m_hAdjust
->value
+0.5);
4503 return (int)(m_vAdjust
->value
+0.5);
4506 int wxWindowGTK::GetScrollRange( int orient
) const
4508 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4510 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4512 if (orient
== wxHORIZONTAL
)
4513 return (int)(m_hAdjust
->upper
+0.5);
4515 return (int)(m_vAdjust
->upper
+0.5);
4518 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4520 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4522 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4524 // No scrolling requested.
4525 if ((dx
== 0) && (dy
== 0)) return;
4528 if (!m_updateRegion
.IsEmpty())
4530 m_updateRegion
.Offset( dx
, dy
);
4534 GetClientSize( &cw
, &ch
);
4535 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4538 if (!m_clearRegion
.IsEmpty())
4540 m_clearRegion
.Offset( dx
, dy
);
4544 GetClientSize( &cw
, &ch
);
4545 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4549 m_clipPaintRegion
= TRUE
;
4551 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4553 m_clipPaintRegion
= FALSE
;
4557 // Find the wxWindow at the current mouse position, also returning the mouse
4559 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4561 pt
= wxGetMousePosition();
4562 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4566 // Get the current mouse position.
4567 wxPoint
wxGetMousePosition()
4569 /* This crashes when used within wxHelpContext,
4570 so we have to use the X-specific implementation below.
4572 GdkModifierType *mask;
4573 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4575 return wxPoint(x, y);
4579 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4581 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4582 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4583 Window rootReturn
, childReturn
;
4584 int rootX
, rootY
, winX
, winY
;
4585 unsigned int maskReturn
;
4587 XQueryPointer (display
,
4591 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4592 return wxPoint(rootX
, rootY
);
4596 // ----------------------------------------------------------------------------
4598 // ----------------------------------------------------------------------------
4600 class wxWinModule
: public wxModule
4607 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4610 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4612 bool wxWinModule::OnInit()
4614 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4615 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4620 void wxWinModule::OnExit()
4623 gdk_gc_unref( g_eraseGC
);