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()
2453 m_widget
= (GtkWidget
*) NULL
;
2454 m_wxwindow
= (GtkWidget
*) NULL
;
2455 m_focusWidget
= (GtkWidget
*) NULL
;
2465 m_needParent
= TRUE
;
2466 m_isBeingDeleted
= FALSE
;
2469 m_nativeSizeEvent
= FALSE
;
2471 m_hasScrolling
= FALSE
;
2472 m_isScrolling
= FALSE
;
2474 m_hAdjust
= (GtkAdjustment
*) NULL
;
2475 m_vAdjust
= (GtkAdjustment
*) NULL
;
2476 m_oldHorizontalPos
=
2477 m_oldVerticalPos
= 0.0;
2479 m_oldClientHeight
= 0;
2482 m_widgetStyle
= (GtkStyle
*) NULL
;
2484 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2486 m_acceptsFocus
= FALSE
;
2489 m_clipPaintRegion
= FALSE
;
2491 m_cursor
= *wxSTANDARD_CURSOR
;
2493 m_delayedForegroundColour
= FALSE
;
2494 m_delayedBackgroundColour
= FALSE
;
2498 m_x11Context
= NULL
;
2501 m_ic
= (GdkIC
*) NULL
;
2502 m_icattr
= (GdkICAttr
*) NULL
;
2507 wxWindowGTK::wxWindowGTK()
2512 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2517 const wxString
&name
)
2521 Create( parent
, id
, pos
, size
, style
, name
);
2524 bool wxWindowGTK::Create( wxWindow
*parent
,
2529 const wxString
&name
)
2531 if (!PreCreation( parent
, pos
, size
) ||
2532 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2534 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2538 m_insertCallback
= wxInsertChildInWindow
;
2540 // always needed for background clearing
2541 m_delayedBackgroundColour
= TRUE
;
2543 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2544 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2546 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2548 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2549 scroll_class
->scrollbar_spacing
= 0;
2551 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2553 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2554 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2556 m_wxwindow
= gtk_pizza_new();
2558 #ifndef __WXUNIVERSAL__
2559 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2561 if (HasFlag(wxRAISED_BORDER
))
2563 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2565 else if (HasFlag(wxSUNKEN_BORDER
))
2567 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2569 else if (HasFlag(wxSIMPLE_BORDER
))
2571 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2575 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2577 #endif // __WXUNIVERSAL__
2579 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2581 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2582 m_acceptsFocus
= TRUE
;
2584 // I _really_ don't want scrollbars in the beginning
2585 m_vAdjust
->lower
= 0.0;
2586 m_vAdjust
->upper
= 1.0;
2587 m_vAdjust
->value
= 0.0;
2588 m_vAdjust
->step_increment
= 1.0;
2589 m_vAdjust
->page_increment
= 1.0;
2590 m_vAdjust
->page_size
= 5.0;
2591 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2592 m_hAdjust
->lower
= 0.0;
2593 m_hAdjust
->upper
= 1.0;
2594 m_hAdjust
->value
= 0.0;
2595 m_hAdjust
->step_increment
= 1.0;
2596 m_hAdjust
->page_increment
= 1.0;
2597 m_hAdjust
->page_size
= 5.0;
2598 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2600 // these handlers block mouse events to any window during scrolling such as
2601 // motion events and prevent GTK and wxWindows from fighting over where the
2604 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2605 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2607 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2608 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2610 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2611 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2613 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2614 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2616 // these handlers get notified when screen updates are required either when
2617 // scrolling or when the window size (and therefore scrollbar configuration)
2620 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2621 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2622 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2623 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2626 // Create input method handler
2627 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2629 // Cannot handle drawing preedited text yet
2630 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2632 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2633 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2636 gtk_widget_show( m_wxwindow
);
2639 m_parent
->DoAddChild( this );
2641 m_focusWidget
= m_wxwindow
;
2650 wxWindowGTK::~wxWindowGTK()
2654 if (g_focusWindow
== this)
2655 g_focusWindow
= NULL
;
2657 if (g_activeFrame
== this)
2658 g_activeFrame
= NULL
;
2660 if ( g_delayedFocus
== this )
2661 g_delayedFocus
= NULL
;
2663 m_isBeingDeleted
= TRUE
;
2673 gdk_ic_destroy (m_ic
);
2675 gdk_ic_attr_destroy (m_icattr
);
2680 #if DISABLE_STYLE_IF_BROKEN_THEME
2681 // don't delete if it's a pixmap theme style
2682 if (!m_widgetStyle
->engine_data
)
2683 gtk_style_unref( m_widgetStyle
);
2685 m_widgetStyle
= (GtkStyle
*) NULL
;
2690 gtk_widget_destroy( m_wxwindow
);
2691 m_wxwindow
= (GtkWidget
*) NULL
;
2696 gtk_widget_destroy( m_widget
);
2697 m_widget
= (GtkWidget
*) NULL
;
2701 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2703 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2705 // This turns -1 into 30 so that a minimal window is
2706 // visible even although -1,-1 has been given as the
2707 // size of the window. the same trick is used in other
2708 // ports and should make debugging easier.
2709 m_width
= WidthDefault(size
.x
) ;
2710 m_height
= HeightDefault(size
.y
);
2715 // some reasonable defaults
2720 m_x
= (gdk_screen_width () - m_width
) / 2;
2721 if (m_x
< 10) m_x
= 10;
2725 m_y
= (gdk_screen_height () - m_height
) / 2;
2726 if (m_y
< 10) m_y
= 10;
2733 void wxWindowGTK::PostCreation()
2735 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2741 // these get reported to wxWindows -> wxPaintEvent
2743 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2745 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2746 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2749 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2750 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2752 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2754 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2755 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2758 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2762 // Create input method handler
2763 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2765 // Cannot handle drawing preedited text yet
2766 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2768 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2769 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2773 // these are called when the "sunken" or "raised" borders are drawn
2774 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2775 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2778 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2779 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2785 if (m_focusWidget
== NULL
)
2786 m_focusWidget
= m_widget
;
2788 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2789 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2791 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2792 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2794 // connect to the various key and mouse handlers
2796 GtkWidget
*connect_widget
= GetConnectWidget();
2798 ConnectWidget( connect_widget
);
2800 /* We cannot set colours, fonts and cursors before the widget has
2801 been realized, so we do this directly after realization */
2802 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2803 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2807 // Catch native resize events
2808 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2809 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2811 // Initialize XIM support
2812 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2813 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2815 // And resize XIM window
2816 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2817 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2820 if ( !GTK_IS_COMBO(m_widget
))
2822 // This is needed if we want to add our windows into native
2823 // GTK control, such as the toolbar. With this callback, the
2824 // toolbar gets to know the correct size (the one set by the
2825 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2826 // when moving to GTK 2.0.
2827 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2828 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2835 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2837 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2838 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2840 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2841 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2843 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2844 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2846 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2847 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2849 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2850 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2852 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2853 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2855 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2856 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2859 bool wxWindowGTK::Destroy()
2861 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2865 return wxWindowBase::Destroy();
2868 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2870 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2873 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2875 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2876 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2879 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2882 if (m_resizing
) return; /* I don't like recursions */
2885 int currentX
, currentY
;
2886 GetPosition(¤tX
, ¤tY
);
2887 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2889 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2891 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2893 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2895 /* don't set the size for children of wxNotebook, just take the values. */
2903 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2904 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2906 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2907 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2911 m_x
= x
+ pizza
->xoffset
;
2912 m_y
= y
+ pizza
->yoffset
;
2914 if (width
!= -1) m_width
= width
;
2915 if (height
!= -1) m_height
= height
;
2917 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2919 if (width
== -1) m_width
= 80;
2922 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2924 if (height
== -1) m_height
= 26;
2927 int minWidth
= GetMinWidth(),
2928 minHeight
= GetMinHeight(),
2929 maxWidth
= GetMaxWidth(),
2930 maxHeight
= GetMaxHeight();
2932 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2933 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2934 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2935 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2938 int bottom_border
= 0;
2941 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2943 /* the default button has a border around it */
2949 DoMoveWindow( m_x
-border
,
2952 m_height
+border
+bottom_border
);
2957 /* Sometimes the client area changes size without the
2958 whole windows's size changing, but if the whole
2959 windows's size doesn't change, no wxSizeEvent will
2960 normally be sent. Here we add an extra test if
2961 the client test has been changed and this will
2963 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2967 wxPrintf( "OnSize sent from " );
2968 if (GetClassInfo() && GetClassInfo()->GetClassName())
2969 wxPrintf( GetClassInfo()->GetClassName() );
2970 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2973 if (!m_nativeSizeEvent
)
2975 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2976 event
.SetEventObject( this );
2977 GetEventHandler()->ProcessEvent( event
);
2983 void wxWindowGTK::OnInternalIdle()
2985 // Update invalidated regions.
2988 // Synthetize activate events.
2989 if ( g_sendActivateEvent
!= -1 )
2991 bool activate
= g_sendActivateEvent
!= 0;
2994 g_sendActivateEvent
= -1;
2996 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2999 if ( g_activeFrameLostFocus
)
3001 if ( g_activeFrame
)
3003 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3004 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3005 event
.SetEventObject(g_activeFrame
);
3006 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3007 g_activeFrame
= NULL
;
3009 g_activeFrameLostFocus
= FALSE
;
3012 wxCursor cursor
= m_cursor
;
3013 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3017 /* I now set the cursor anew in every OnInternalIdle call
3018 as setting the cursor in a parent window also effects the
3019 windows above so that checking for the current cursor is
3024 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3026 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3028 if (!g_globalCursor
.Ok())
3029 cursor
= *wxSTANDARD_CURSOR
;
3031 window
= m_widget
->window
;
3032 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3033 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3039 GdkWindow
*window
= m_widget
->window
;
3040 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3041 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3046 if (wxUpdateUIEvent::CanUpdate(this))
3047 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3050 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3052 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3054 if (width
) (*width
) = m_width
;
3055 if (height
) (*height
) = m_height
;
3058 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3060 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3064 SetSize( width
, height
);
3071 #ifndef __WXUNIVERSAL__
3072 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3074 /* when using GTK 1.2 we set the shadow border size to 2 */
3078 if (HasFlag(wxSIMPLE_BORDER
))
3080 /* when using GTK 1.2 we set the simple border size to 1 */
3084 #endif // __WXUNIVERSAL__
3088 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3090 GtkRequisition vscroll_req
;
3091 vscroll_req
.width
= 2;
3092 vscroll_req
.height
= 2;
3093 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3094 (scroll_window
->vscrollbar
, &vscroll_req
);
3096 GtkRequisition hscroll_req
;
3097 hscroll_req
.width
= 2;
3098 hscroll_req
.height
= 2;
3099 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3100 (scroll_window
->hscrollbar
, &hscroll_req
);
3102 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3104 if (scroll_window
->vscrollbar_visible
)
3106 dw
+= vscroll_req
.width
;
3107 dw
+= scroll_class
->scrollbar_spacing
;
3110 if (scroll_window
->hscrollbar_visible
)
3112 dh
+= hscroll_req
.height
;
3113 dh
+= scroll_class
->scrollbar_spacing
;
3117 SetSize( width
+dw
, height
+dh
);
3121 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3123 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3127 if (width
) (*width
) = m_width
;
3128 if (height
) (*height
) = m_height
;
3135 #ifndef __WXUNIVERSAL__
3136 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3138 /* when using GTK 1.2 we set the shadow border size to 2 */
3142 if (HasFlag(wxSIMPLE_BORDER
))
3144 /* when using GTK 1.2 we set the simple border size to 1 */
3148 #endif // __WXUNIVERSAL__
3152 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3154 GtkRequisition vscroll_req
;
3155 vscroll_req
.width
= 2;
3156 vscroll_req
.height
= 2;
3157 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3158 (scroll_window
->vscrollbar
, &vscroll_req
);
3160 GtkRequisition hscroll_req
;
3161 hscroll_req
.width
= 2;
3162 hscroll_req
.height
= 2;
3163 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3164 (scroll_window
->hscrollbar
, &hscroll_req
);
3166 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3168 if (scroll_window
->vscrollbar_visible
)
3170 dw
+= vscroll_req
.width
;
3171 dw
+= scroll_class
->scrollbar_spacing
;
3174 if (scroll_window
->hscrollbar_visible
)
3176 dh
+= hscroll_req
.height
;
3177 dh
+= scroll_class
->scrollbar_spacing
;
3181 if (width
) (*width
) = m_width
- dw
;
3182 if (height
) (*height
) = m_height
- dh
;
3186 printf( "GetClientSize, name %s ", GetName().c_str() );
3187 if (width) printf( " width = %d", (*width) );
3188 if (height) printf( " height = %d", (*height) );
3193 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3195 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3199 if (m_parent
&& m_parent
->m_wxwindow
)
3201 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3202 dx
= pizza
->xoffset
;
3203 dy
= pizza
->yoffset
;
3206 if (x
) (*x
) = m_x
- dx
;
3207 if (y
) (*y
) = m_y
- dy
;
3210 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3212 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3214 if (!m_widget
->window
) return;
3216 GdkWindow
*source
= (GdkWindow
*) NULL
;
3218 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3220 source
= m_widget
->window
;
3224 gdk_window_get_origin( source
, &org_x
, &org_y
);
3228 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3230 org_x
+= m_widget
->allocation
.x
;
3231 org_y
+= m_widget
->allocation
.y
;
3239 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3241 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3243 if (!m_widget
->window
) return;
3245 GdkWindow
*source
= (GdkWindow
*) NULL
;
3247 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3249 source
= m_widget
->window
;
3253 gdk_window_get_origin( source
, &org_x
, &org_y
);
3257 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3259 org_x
+= m_widget
->allocation
.x
;
3260 org_y
+= m_widget
->allocation
.y
;
3268 bool wxWindowGTK::Show( bool show
)
3270 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3272 if (!wxWindowBase::Show(show
))
3279 gtk_widget_show( m_widget
);
3281 gtk_widget_hide( m_widget
);
3283 wxShowEvent
eventShow(GetId(), show
);
3284 eventShow
.m_eventObject
= this;
3286 GetEventHandler()->ProcessEvent(eventShow
);
3291 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3293 win
->OnParentEnable(enable
);
3295 // Recurse, so that children have the opportunity to Do The Right Thing
3296 // and reset colours that have been messed up by a parent's (really ancestor's)
3298 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3300 node
= node
->GetNext() )
3302 wxWindow
*child
= node
->GetData();
3303 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3304 wxWindowNotifyEnable(child
, enable
);
3308 bool wxWindowGTK::Enable( bool enable
)
3310 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3312 if (!wxWindowBase::Enable(enable
))
3318 gtk_widget_set_sensitive( m_widget
, enable
);
3320 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3322 wxWindowNotifyEnable(this, enable
);
3327 int wxWindowGTK::GetCharHeight() const
3329 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3331 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3334 PangoContext
*context
= NULL
;
3336 context
= gtk_widget_get_pango_context( m_widget
);
3341 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3342 PangoLayout
*layout
= pango_layout_new(context
);
3343 pango_layout_set_font_description(layout
, desc
);
3344 pango_layout_set_text(layout
, "H", 1);
3345 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3347 PangoRectangle rect
;
3348 pango_layout_line_get_extents(line
, NULL
, &rect
);
3350 g_object_unref( G_OBJECT( layout
) );
3352 return (int) (rect
.height
/ PANGO_SCALE
);
3354 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3356 return font
->ascent
+ font
->descent
;
3360 int wxWindowGTK::GetCharWidth() const
3362 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3364 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3367 PangoContext
*context
= NULL
;
3369 context
= gtk_widget_get_pango_context( m_widget
);
3374 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3375 PangoLayout
*layout
= pango_layout_new(context
);
3376 pango_layout_set_font_description(layout
, desc
);
3377 pango_layout_set_text(layout
, "H", 1);
3378 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3380 PangoRectangle rect
;
3381 pango_layout_line_get_extents(line
, NULL
, &rect
);
3383 g_object_unref( G_OBJECT( layout
) );
3385 return (int) (rect
.width
/ PANGO_SCALE
);
3387 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3389 return gdk_string_width( font
, "H" );
3393 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3397 int *externalLeading
,
3398 const wxFont
*theFont
) const
3400 wxFont fontToUse
= m_font
;
3401 if (theFont
) fontToUse
= *theFont
;
3403 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3405 if (string
.IsEmpty())
3413 PangoContext
*context
= NULL
;
3415 context
= gtk_widget_get_pango_context( m_widget
);
3424 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3425 PangoLayout
*layout
= pango_layout_new(context
);
3426 pango_layout_set_font_description(layout
, desc
);
3429 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3430 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3432 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3433 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3434 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3437 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3439 PangoRectangle rect
;
3440 pango_layout_line_get_extents(line
, NULL
, &rect
);
3442 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3443 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3446 // Do something about metrics here
3449 if (externalLeading
) (*externalLeading
) = 0; // ??
3451 g_object_unref( G_OBJECT( layout
) );
3453 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3454 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3455 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3456 if (descent
) (*descent
) = font
->descent
;
3457 if (externalLeading
) (*externalLeading
) = 0; // ??
3461 void wxWindowGTK::SetFocus()
3463 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3467 // don't do anything if we already have focus
3473 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3475 gtk_widget_grab_focus (m_wxwindow
);
3480 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3482 if (!GTK_WIDGET_REALIZED(m_widget
))
3484 // we can't set the focus to the widget now so we remember that
3485 // it should be focused and will do it later, during the idle
3486 // time, as soon as we can
3487 wxLogTrace(TRACE_FOCUS
,
3488 _T("Delaying setting focus to %s(%s)"),
3489 GetClassInfo()->GetClassName(), GetLabel().c_str());
3491 g_delayedFocus
= this;
3495 wxLogTrace(TRACE_FOCUS
,
3496 _T("Setting focus to %s(%s)"),
3497 GetClassInfo()->GetClassName(), GetLabel().c_str());
3499 gtk_widget_grab_focus (m_widget
);
3502 else if (GTK_IS_CONTAINER(m_widget
))
3504 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3508 wxLogTrace(TRACE_FOCUS
,
3509 _T("Can't set focus to %s(%s)"),
3510 GetClassInfo()->GetClassName(), GetLabel().c_str());
3515 bool wxWindowGTK::AcceptsFocus() const
3517 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3520 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3522 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3524 wxWindowGTK
*oldParent
= m_parent
,
3525 *newParent
= (wxWindowGTK
*)newParentBase
;
3527 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3529 if ( !wxWindowBase::Reparent(newParent
) )
3532 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3534 /* prevent GTK from deleting the widget arbitrarily */
3535 gtk_widget_ref( m_widget
);
3539 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3542 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3546 /* insert GTK representation */
3547 (*(newParent
->m_insertCallback
))(newParent
, this);
3550 /* reverse: prevent GTK from deleting the widget arbitrarily */
3551 gtk_widget_unref( m_widget
);
3556 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3558 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3560 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3562 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3567 /* insert GTK representation */
3568 (*m_insertCallback
)(this, child
);
3571 void wxWindowGTK::Raise()
3573 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3575 if (!m_widget
->window
) return;
3577 gdk_window_raise( m_widget
->window
);
3580 void wxWindowGTK::Lower()
3582 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3584 if (!m_widget
->window
) return;
3586 gdk_window_lower( m_widget
->window
);
3589 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3591 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3593 if (cursor
== m_cursor
)
3597 wxapp_install_idle_handler();
3599 if (cursor
== wxNullCursor
)
3600 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3602 return wxWindowBase::SetCursor( cursor
);
3605 void wxWindowGTK::WarpPointer( int x
, int y
)
3607 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3609 // We provide this function ourselves as it is
3610 // missing in GDK (top of this file).
3612 GdkWindow
*window
= (GdkWindow
*) NULL
;
3614 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3616 window
= GetConnectWidget()->window
;
3619 gdk_window_warp_pointer( window
, x
, y
);
3623 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3625 if (!m_widget
) return;
3626 if (!m_widget
->window
) return;
3630 wxapp_install_idle_handler();
3632 wxRect
myRect(0,0,0,0);
3633 if (m_wxwindow
&& rect
)
3635 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3636 m_wxwindow
->allocation
.height
));
3637 myRect
.Intersect(*rect
);
3638 if (!myRect
.width
|| !myRect
.height
)
3639 // nothing to do, rectangle is empty
3644 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3648 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3649 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3653 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3654 m_clearRegion
.Clear();
3655 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3663 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3664 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3668 GdkRectangle gdk_rect
;
3669 gdk_rect
.x
= rect
->x
;
3670 gdk_rect
.y
= rect
->y
;
3671 gdk_rect
.width
= rect
->width
;
3672 gdk_rect
.height
= rect
->height
;
3673 gtk_widget_draw( m_widget
, &gdk_rect
);
3680 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3681 m_updateRegion
.Clear();
3682 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3686 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3694 GdkRectangle gdk_rect
;
3695 gdk_rect
.x
= rect
->x
;
3696 gdk_rect
.y
= rect
->y
;
3697 gdk_rect
.width
= rect
->width
;
3698 gdk_rect
.height
= rect
->height
;
3699 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3703 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3709 void wxWindowGTK::Update()
3714 void wxWindowGTK::GtkUpdate()
3717 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3718 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3720 if (!m_updateRegion
.IsEmpty())
3721 GtkSendPaintEvents();
3725 void wxWindowGTK::GtkSendPaintEvents()
3730 m_clearRegion
.Clear();
3732 m_updateRegion
.Clear();
3736 // Clip to paint region in wxClientDC
3737 m_clipPaintRegion
= TRUE
;
3740 // widget to draw on
3741 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3743 // later for GTK 2.0, too.
3744 if (GetThemeEnabled())
3746 // find ancestor from which to steal background
3747 wxWindow
*parent
= GetParent();
3748 while (parent
&& !parent
->IsTopLevel())
3749 parent
= parent
->GetParent();
3751 parent
= (wxWindow
*)this;
3753 wxRegionIterator
upd( m_updateRegion
);
3757 rect
.x
= upd
.GetX();
3758 rect
.y
= upd
.GetY();
3759 rect
.width
= upd
.GetWidth();
3760 rect
.height
= upd
.GetHeight();
3762 gtk_paint_flat_box( parent
->m_widget
->style
,
3779 wxWindowDC
dc( (wxWindow
*)this );
3780 dc
.SetClippingRegion( m_updateRegion
);
3782 wxEraseEvent
erase_event( GetId(), &dc
);
3783 erase_event
.SetEventObject( this );
3785 GetEventHandler()->ProcessEvent(erase_event
);
3788 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3790 wxWindowDC
dc( (wxWindow
*)this );
3791 if (m_clearRegion
.IsEmpty())
3792 dc
.SetClippingRegion( m_updateRegion
);
3794 dc
.SetClippingRegion( m_clearRegion
);
3796 wxEraseEvent
erase_event( GetId(), &dc
);
3797 erase_event
.SetEventObject( this );
3799 if (!GetEventHandler()->ProcessEvent(erase_event
))
3803 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3804 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3806 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3808 wxRegionIterator
upd( m_clearRegion
);
3811 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3812 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3816 m_clearRegion
.Clear();
3820 wxNcPaintEvent
nc_paint_event( GetId() );
3821 nc_paint_event
.SetEventObject( this );
3822 GetEventHandler()->ProcessEvent( nc_paint_event
);
3824 wxPaintEvent
paint_event( GetId() );
3825 paint_event
.SetEventObject( this );
3826 GetEventHandler()->ProcessEvent( paint_event
);
3828 m_clipPaintRegion
= FALSE
;
3830 #ifndef __WXUNIVERSAL__
3832 // The following code will result in all window-less widgets
3833 // being redrawn because the wxWindows class is allowed to
3834 // paint over the window-less widgets.
3836 GList
*children
= pizza
->children
;
3839 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3840 children
= children
->next
;
3842 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3843 GTK_WIDGET_DRAWABLE (child
->widget
))
3845 // Get intersection of widget area and update region
3846 wxRegion
region( m_updateRegion
);
3848 GdkEventExpose gdk_event
;
3849 gdk_event
.type
= GDK_EXPOSE
;
3850 gdk_event
.window
= pizza
->bin_window
;
3851 gdk_event
.count
= 0;
3853 wxRegionIterator
upd( m_updateRegion
);
3857 rect
.x
= upd
.GetX();
3858 rect
.y
= upd
.GetY();
3859 rect
.width
= upd
.GetWidth();
3860 rect
.height
= upd
.GetHeight();
3862 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3864 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3874 m_updateRegion
.Clear();
3877 void wxWindowGTK::ClearBackground()
3879 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3882 if (m_wxwindow
&& m_wxwindow
->window
)
3884 m_clearRegion
.Clear();
3885 wxSize
size( GetClientSize() );
3886 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3888 // Better do this in idle?
3895 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3897 wxWindowBase::DoSetToolTip(tip
);
3900 m_tooltip
->Apply( (wxWindow
*)this );
3903 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3905 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3907 #endif // wxUSE_TOOLTIPS
3909 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3911 GdkWindow
*window
= (GdkWindow
*) NULL
;
3913 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3915 window
= GetConnectWidget()->window
;
3919 // We need the pixel value e.g. for background clearing.
3920 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3924 // wxMSW doesn't clear the window here, either.
3925 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3931 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3933 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3935 if (!wxWindowBase::SetBackgroundColour(colour
))
3938 GdkWindow
*window
= (GdkWindow
*) NULL
;
3940 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3942 window
= GetConnectWidget()->window
;
3946 // indicate that a new style has been set
3947 // but it couldn't get applied as the
3948 // widget hasn't been realized yet.
3949 m_delayedBackgroundColour
= TRUE
;
3954 GtkSetBackgroundColour( colour
);
3960 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3962 GdkWindow
*window
= (GdkWindow
*) NULL
;
3964 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3966 window
= GetConnectWidget()->window
;
3973 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3975 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3977 if (!wxWindowBase::SetForegroundColour(colour
))
3979 // don't leave if the GTK widget has just
3981 if (!m_delayedForegroundColour
) return FALSE
;
3984 GdkWindow
*window
= (GdkWindow
*) NULL
;
3986 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3988 window
= GetConnectWidget()->window
;
3992 // indicate that a new style has been set
3993 // but it couldn't get applied as the
3994 // widget hasn't been realized yet.
3995 m_delayedForegroundColour
= TRUE
;
3999 GtkSetForegroundColour( colour
);
4006 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4008 return gtk_widget_get_pango_context( m_widget
);
4011 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4014 m_x11Context
= pango_x_get_context( gdk_display
);
4016 return m_x11Context
;
4020 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4024 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4026 // FIXME: no more klass in 2.0
4028 remake
->klass
= m_widgetStyle
->klass
;
4031 gtk_style_unref( m_widgetStyle
);
4032 m_widgetStyle
= remake
;
4036 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4039 def
= gtk_widget_get_default_style();
4041 m_widgetStyle
= gtk_style_copy( def
);
4043 // FIXME: no more klass in 2.0
4045 m_widgetStyle
->klass
= def
->klass
;
4049 return m_widgetStyle
;
4052 void wxWindowGTK::SetWidgetStyle()
4054 #if DISABLE_STYLE_IF_BROKEN_THEME
4055 if (m_widget
->style
->engine_data
)
4057 static bool s_warningPrinted
= FALSE
;
4058 if (!s_warningPrinted
)
4060 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
4061 s_warningPrinted
= TRUE
;
4063 m_widgetStyle
= m_widget
->style
;
4068 GtkStyle
*style
= GetWidgetStyle();
4070 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
4073 pango_font_description_free( style
->font_desc
);
4074 style
->font_desc
= pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4076 gdk_font_unref( style
->font
);
4077 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4081 if (m_foregroundColour
.Ok())
4083 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4084 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4086 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4087 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4088 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4092 // Try to restore the gtk default style. This is still a little
4093 // oversimplified for what is probably really needed here for controls
4094 // other than buttons, but is better than not being able to (re)set a
4095 // control's foreground colour to *wxBLACK -- RL
4096 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4099 def
= gtk_widget_get_default_style();
4101 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4102 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4103 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4107 if (m_backgroundColour
.Ok())
4109 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4110 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4112 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4113 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4114 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4115 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4116 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4117 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4118 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4119 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4123 // Try to restore the gtk default style. This is still a little
4124 // oversimplified for what is probably really needed here for controls
4125 // other than buttons, but is better than not being able to (re)set a
4126 // control's background colour to default grey and means resetting a
4127 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4129 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4132 def
= gtk_widget_get_default_style();
4134 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4135 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4136 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4137 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4138 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4139 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4140 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4141 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4146 void wxWindowGTK::ApplyWidgetStyle()
4150 //-----------------------------------------------------------------------------
4151 // Pop-up menu stuff
4152 //-----------------------------------------------------------------------------
4154 #if wxUSE_MENUS_NATIVE
4157 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4159 *is_waiting
= FALSE
;
4162 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4164 menu
->SetInvokingWindow( win
);
4165 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4168 wxMenuItem
*menuitem
= node
->GetData();
4169 if (menuitem
->IsSubMenu())
4171 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4174 node
= node
->GetNext();
4178 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
4179 // wxPopupMenuPositionCallback()
4181 // should be safe even in the MT case as the user can hardly popup 2 menus
4182 // simultaneously, can he?
4183 static gint gs_pop_x
= 0;
4184 static gint gs_pop_y
= 0;
4186 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4189 gboolean
* WXUNUSED(whatever
),
4191 gpointer
WXUNUSED(user_data
) )
4193 // ensure that the menu appears entirely on screen
4195 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4197 wxSize sizeScreen
= wxGetDisplaySize();
4199 gint xmax
= sizeScreen
.x
- req
.width
,
4200 ymax
= sizeScreen
.y
- req
.height
;
4202 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
4203 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
4206 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4208 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4210 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
4212 SetInvokingWindow( menu
, this );
4218 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
4220 bool is_waiting
= TRUE
;
4222 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4224 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4225 (gpointer
)&is_waiting
);
4228 GTK_MENU(menu
->m_menu
),
4229 (GtkWidget
*) NULL
, // parent menu shell
4230 (GtkWidget
*) NULL
, // parent menu item
4231 wxPopupMenuPositionCallback
, // function to position it
4232 NULL
, // client data
4233 0, // button used to activate it
4235 gtk_get_current_event_time()
4237 gs_timeLastClick
// the time of activation
4243 gtk_main_iteration();
4249 #endif // wxUSE_MENUS_NATIVE
4251 #if wxUSE_DRAG_AND_DROP
4253 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4255 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4257 GtkWidget
*dnd_widget
= GetConnectWidget();
4259 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4261 if (m_dropTarget
) delete m_dropTarget
;
4262 m_dropTarget
= dropTarget
;
4264 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4267 #endif // wxUSE_DRAG_AND_DROP
4269 GtkWidget
* wxWindowGTK::GetConnectWidget()
4271 GtkWidget
*connect_widget
= m_widget
;
4272 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4274 return connect_widget
;
4277 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4280 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4282 return (window
== m_widget
->window
);
4285 bool wxWindowGTK::SetFont( const wxFont
&font
)
4287 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4289 if (!wxWindowBase::SetFont(font
))
4294 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4295 if ( sysbg
== m_backgroundColour
)
4297 m_backgroundColour
= wxNullColour
;
4299 m_backgroundColour
= sysbg
;
4309 void wxWindowGTK::DoCaptureMouse()
4311 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4313 GdkWindow
*window
= (GdkWindow
*) NULL
;
4315 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4317 window
= GetConnectWidget()->window
;
4319 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4321 wxCursor
* cursor
= & m_cursor
;
4323 cursor
= wxSTANDARD_CURSOR
;
4325 gdk_pointer_grab( window
, FALSE
,
4327 (GDK_BUTTON_PRESS_MASK
|
4328 GDK_BUTTON_RELEASE_MASK
|
4329 GDK_POINTER_MOTION_HINT_MASK
|
4330 GDK_POINTER_MOTION_MASK
),
4332 cursor
->GetCursor(),
4333 (guint32
)GDK_CURRENT_TIME
);
4334 g_captureWindow
= this;
4335 g_captureWindowHasMouse
= TRUE
;
4338 void wxWindowGTK::DoReleaseMouse()
4340 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4342 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4344 g_captureWindow
= (wxWindowGTK
*) NULL
;
4346 GdkWindow
*window
= (GdkWindow
*) NULL
;
4348 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4350 window
= GetConnectWidget()->window
;
4355 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4359 wxWindow
*wxWindowBase::GetCapture()
4361 return (wxWindow
*)g_captureWindow
;
4364 bool wxWindowGTK::IsRetained() const
4369 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4370 int range
, bool refresh
)
4372 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4374 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4376 m_hasScrolling
= TRUE
;
4378 if (orient
== wxHORIZONTAL
)
4380 float fpos
= (float)pos
;
4381 float frange
= (float)range
;
4382 float fthumb
= (float)thumbVisible
;
4383 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4384 if (fpos
< 0.0) fpos
= 0.0;
4386 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4387 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4389 SetScrollPos( orient
, pos
, refresh
);
4393 m_oldHorizontalPos
= fpos
;
4395 m_hAdjust
->lower
= 0.0;
4396 m_hAdjust
->upper
= frange
;
4397 m_hAdjust
->value
= fpos
;
4398 m_hAdjust
->step_increment
= 1.0;
4399 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4400 m_hAdjust
->page_size
= fthumb
;
4404 float fpos
= (float)pos
;
4405 float frange
= (float)range
;
4406 float fthumb
= (float)thumbVisible
;
4407 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4408 if (fpos
< 0.0) fpos
= 0.0;
4410 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4411 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4413 SetScrollPos( orient
, pos
, refresh
);
4417 m_oldVerticalPos
= fpos
;
4419 m_vAdjust
->lower
= 0.0;
4420 m_vAdjust
->upper
= frange
;
4421 m_vAdjust
->value
= fpos
;
4422 m_vAdjust
->step_increment
= 1.0;
4423 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4424 m_vAdjust
->page_size
= fthumb
;
4427 if (orient
== wxHORIZONTAL
)
4428 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4430 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4433 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4435 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4437 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4439 if (orient
== wxHORIZONTAL
)
4441 float fpos
= (float)pos
;
4442 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4443 if (fpos
< 0.0) fpos
= 0.0;
4444 m_oldHorizontalPos
= fpos
;
4446 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4447 m_hAdjust
->value
= fpos
;
4451 float fpos
= (float)pos
;
4452 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4453 if (fpos
< 0.0) fpos
= 0.0;
4454 m_oldVerticalPos
= fpos
;
4456 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4457 m_vAdjust
->value
= fpos
;
4460 if (m_wxwindow
->window
)
4462 if (orient
== wxHORIZONTAL
)
4464 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4465 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4467 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4469 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4470 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4474 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4475 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4477 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4479 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4480 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4485 int wxWindowGTK::GetScrollThumb( int orient
) const
4487 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4489 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4491 if (orient
== wxHORIZONTAL
)
4492 return (int)(m_hAdjust
->page_size
+0.5);
4494 return (int)(m_vAdjust
->page_size
+0.5);
4497 int wxWindowGTK::GetScrollPos( int orient
) const
4499 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4501 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4503 if (orient
== wxHORIZONTAL
)
4504 return (int)(m_hAdjust
->value
+0.5);
4506 return (int)(m_vAdjust
->value
+0.5);
4509 int wxWindowGTK::GetScrollRange( int orient
) const
4511 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4513 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4515 if (orient
== wxHORIZONTAL
)
4516 return (int)(m_hAdjust
->upper
+0.5);
4518 return (int)(m_vAdjust
->upper
+0.5);
4521 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4523 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4525 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4527 // No scrolling requested.
4528 if ((dx
== 0) && (dy
== 0)) return;
4531 if (!m_updateRegion
.IsEmpty())
4533 m_updateRegion
.Offset( dx
, dy
);
4537 GetClientSize( &cw
, &ch
);
4538 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4541 if (!m_clearRegion
.IsEmpty())
4543 m_clearRegion
.Offset( dx
, dy
);
4547 GetClientSize( &cw
, &ch
);
4548 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4552 m_clipPaintRegion
= TRUE
;
4554 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4556 m_clipPaintRegion
= FALSE
;
4560 // Find the wxWindow at the current mouse position, also returning the mouse
4562 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4564 pt
= wxGetMousePosition();
4565 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4569 // Get the current mouse position.
4570 wxPoint
wxGetMousePosition()
4572 /* This crashes when used within wxHelpContext,
4573 so we have to use the X-specific implementation below.
4575 GdkModifierType *mask;
4576 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4578 return wxPoint(x, y);
4582 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4584 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4585 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4586 Window rootReturn
, childReturn
;
4587 int rootX
, rootY
, winX
, winY
;
4588 unsigned int maskReturn
;
4590 XQueryPointer (display
,
4594 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4595 return wxPoint(rootX
, rootY
);
4599 // ----------------------------------------------------------------------------
4601 // ----------------------------------------------------------------------------
4603 class wxWinModule
: public wxModule
4610 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4613 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4615 bool wxWinModule::OnInit()
4617 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4618 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4623 void wxWinModule::OnExit()
4626 gdk_gc_unref( g_eraseGC
);