1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
19 #define XWarpPointer XWARPPOINTER
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
26 #include "wx/layout.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
32 #if wxUSE_DRAG_AND_DROP
37 #include "wx/tooltip.h"
45 #include "wx/textctrl.h"
49 #include "wx/statusbr.h"
51 #include "wx/settings.h"
53 #include "wx/fontutil.h"
56 #include "wx/thread.h"
62 #include "wx/gtk/private.h"
63 #include <gdk/gdkprivate.h>
64 #include <gdk/gdkkeysyms.h>
68 #include <gtk/gtkprivate.h>
70 #include "wx/gtk/win_gtk.h"
73 #include <pango/pangox.h>
77 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
79 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
89 extern GtkContainerClass
*pizza_parent_class
;
92 //-----------------------------------------------------------------------------
93 // documentation on internals
94 //-----------------------------------------------------------------------------
97 I have been asked several times about writing some documentation about
98 the GTK port of wxWindows, especially its internal structures. Obviously,
99 you cannot understand wxGTK without knowing a little about the GTK, but
100 some more information about what the wxWindow, which is the base class
101 for all other window classes, does seems required as well.
105 What does wxWindow do? It contains the common interface for the following
106 jobs of its descendants:
108 1) Define the rudimentary behaviour common to all window classes, such as
109 resizing, intercepting user input (so as to make it possible to use these
110 events for special purposes in a derived class), window names etc.
112 2) Provide the possibility to contain and manage children, if the derived
113 class is allowed to contain children, which holds true for those window
114 classes which do not display a native GTK widget. To name them, these
115 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
116 work classes are a special case and are handled a bit differently from
117 the rest. The same holds true for the wxNotebook class.
119 3) Provide the possibility to draw into a client area of a window. This,
120 too, only holds true for classes that do not display a native GTK widget
123 4) Provide the entire mechanism for scrolling widgets. This actual inter-
124 face for this is usually in wxScrolledWindow, but the GTK implementation
127 5) A multitude of helper or extra methods for special purposes, such as
128 Drag'n'Drop, managing validators etc.
130 6) Display a border (sunken, raised, simple or none).
132 Normally one might expect, that one wxWindows window would always correspond
133 to one GTK widget. Under GTK, there is no such allround widget that has all
134 the functionality. Moreover, the GTK defines a client area as a different
135 widget from the actual widget you are handling. Last but not least some
136 special classes (e.g. wxFrame) handle different categories of widgets and
137 still have the possibility to draw something in the client area.
138 It was therefore required to write a special purpose GTK widget, that would
139 represent a client area in the sense of wxWindows capable to do the jobs
140 2), 3) and 4). I have written this class and it resides in win_gtk.c of
143 All windows must have a widget, with which they interact with other under-
144 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
145 thw wxWindow class has a member variable called m_widget which holds a
146 pointer to this widget. When the window class represents a GTK native widget,
147 this is (in most cases) the only GTK widget the class manages. E.g. the
148 wxStatitText class handles only a GtkLabel widget a pointer to which you
149 can find in m_widget (defined in wxWindow)
151 When the class has a client area for drawing into and for containing children
152 it has to handle the client area widget (of the type GtkPizza, defined in
153 win_gtk.c), but there could be any number of widgets, handled by a class
154 The common rule for all windows is only, that the widget that interacts with
155 the rest of GTK must be referenced in m_widget and all other widgets must be
156 children of this widget on the GTK level. The top-most widget, which also
157 represents the client area, must be in the m_wxwindow field and must be of
160 As I said, the window classes that display a GTK native widget only have
161 one widget, so in the case of e.g. the wxButton class m_widget holds a
162 pointer to a GtkButton widget. But windows with client areas (for drawing
163 and children) have a m_widget field that is a pointer to a GtkScrolled-
164 Window and a m_wxwindow field that is pointer to a GtkPizza and this
165 one is (in the GTK sense) a child of the GtkScrolledWindow.
167 If the m_wxwindow field is set, then all input to this widget is inter-
168 cepted and sent to the wxWindows class. If not, all input to the widget
169 that gets pointed to by m_widget gets intercepted and sent to the class.
173 The design of scrolling in wxWindows is markedly different from that offered
174 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
175 clicking on a scrollbar belonging to scrolled window will inevitably move
176 the window. In wxWindows, the scrollbar will only emit an event, send this
177 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
178 which actually moves the window and its subchildren. Note that GtkPizza
179 memorizes how much it has been scrolled but that wxWindows forgets this
180 so that the two coordinates systems have to be kept in synch. This is done
181 in various places using the pizza->xoffset and pizza->yoffset values.
185 Singularily the most broken code in GTK is the code that is supposes to
186 inform subwindows (child windows) about new positions. Very often, duplicate
187 events are sent without changes in size or position, equally often no
188 events are sent at all (All this is due to a bug in the GtkContainer code
189 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
190 GTK's own system and it simply waits for size events for toplevel windows
191 and then iterates down the respective size events to all window. This has
192 the disadvantage, that windows might get size events before the GTK widget
193 actually has the reported size. This doesn't normally pose any problem, but
194 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
195 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
196 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
197 window that is used for OpenGl output really has that size (as reported by
202 If someone at some point of time feels the immense desire to have a look at,
203 change or attempt to optimse the Refresh() logic, this person will need an
204 intimate understanding of what a "draw" and what an "expose" events are and
205 what there are used for, in particular when used in connection with GTK's
206 own windowless widgets. Beware.
210 Cursors, too, have been a constant source of pleasure. The main difficulty
211 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
212 for the parent. To prevent this from doing too much harm, I use idle time
213 to set the cursor over and over again, starting from the toplevel windows
214 and ending with the youngest generation (speaking of parent and child windows).
215 Also don't forget that cursors (like much else) are connected to GdkWindows,
216 not GtkWidgets and that the "window" field of a GtkWidget might very well
217 point to the GdkWindow of the parent widget (-> "window less widget") and
218 that the two obviously have very different meanings.
222 //-----------------------------------------------------------------------------
224 //-----------------------------------------------------------------------------
226 extern wxList wxPendingDelete
;
227 extern bool g_blockEventsOnDrag
;
228 extern bool g_blockEventsOnScroll
;
229 extern wxCursor g_globalCursor
;
231 static GdkGC
*g_eraseGC
= NULL
;
233 // mouse capture state: the window which has it and if the mouse is currently
235 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
236 static bool g_captureWindowHasMouse
= FALSE
;
238 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
240 // the last window which had the focus - this is normally never NULL (except
241 // if we never had focus at all) as even when g_focusWindow is NULL it still
242 // keeps its previous value
243 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
245 // the frame that is currently active (i.e. its child has focus). It is
246 // used to generate wxActivateEvents
247 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
248 static bool g_activeFrameLostFocus
= FALSE
;
250 // If a window get the focus set but has not been realized
251 // yet, defer setting the focus to idle time.
252 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
254 // if we detect that the app has got/lost the focus, we set this variable to
255 // either TRUE or FALSE and an activate event will be sent during the next
256 // OnIdle() call and it is reset to -1: this value means that we shouldn't
257 // send any activate events at all
258 static int g_sendActivateEvent
= -1;
260 // hack: we need something to pass to gtk_menu_popup, so we store the time of
261 // the last click here
262 static guint32 gs_timeLastClick
= 0;
264 extern bool g_mainThreadLocked
;
266 //-----------------------------------------------------------------------------
268 //-----------------------------------------------------------------------------
271 #define DISABLE_STYLE_IF_BROKEN_THEME 0
277 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
279 # define DEBUG_MAIN_THREAD
282 #define DEBUG_MAIN_THREAD
285 // the trace mask used for the focus debugging messages
286 #define TRACE_FOCUS _T("focus")
288 //-----------------------------------------------------------------------------
289 // missing gdk functions
290 //-----------------------------------------------------------------------------
293 gdk_window_warp_pointer (GdkWindow
*window
,
298 GdkWindowPrivate
*priv
;
302 window
= GDK_ROOT_PARENT();
305 if (!GDK_WINDOW_DESTROYED(window
))
307 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
308 None
, /* not source window -> move from anywhere */
309 GDK_WINDOW_XID(window
), /* dest window */
310 0, 0, 0, 0, /* not source window -> move from anywhere */
314 priv
= (GdkWindowPrivate
*) window
;
316 if (!priv
->destroyed
)
318 XWarpPointer (priv
->xdisplay
,
319 None
, /* not source window -> move from anywhere */
320 priv
->xwindow
, /* dest window */
321 0, 0, 0, 0, /* not source window -> move from anywhere */
327 //-----------------------------------------------------------------------------
329 //-----------------------------------------------------------------------------
331 extern void wxapp_install_idle_handler();
332 extern bool g_isIdle
;
334 //-----------------------------------------------------------------------------
335 // local code (see below)
336 //-----------------------------------------------------------------------------
338 // returns the child of win which currently has focus or NULL if not found
340 // Note: can't be static, needed by textctrl.cpp.
341 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
343 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
345 return (wxWindow
*)NULL
;
347 if ( winFocus
== win
)
348 return (wxWindow
*)win
;
350 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
352 node
= node
->GetNext() )
354 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
359 return (wxWindow
*)NULL
;
362 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
364 // wxUniversal widgets draw the borders and scrollbars themselves
365 #ifndef __WXUNIVERSAL__
372 if (win
->m_hasScrolling
)
374 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
376 GtkRequisition vscroll_req
;
377 vscroll_req
.width
= 2;
378 vscroll_req
.height
= 2;
379 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
380 (scroll_window
->vscrollbar
, &vscroll_req
);
382 GtkRequisition hscroll_req
;
383 hscroll_req
.width
= 2;
384 hscroll_req
.height
= 2;
385 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
386 (scroll_window
->hscrollbar
, &hscroll_req
);
388 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
390 if (scroll_window
->vscrollbar_visible
)
392 dw
+= vscroll_req
.width
;
393 dw
+= scroll_class
->scrollbar_spacing
;
396 if (scroll_window
->hscrollbar_visible
)
398 dh
+= hscroll_req
.height
;
399 dh
+= scroll_class
->scrollbar_spacing
;
405 if (GTK_WIDGET_NO_WINDOW (widget
))
407 dx
+= widget
->allocation
.x
;
408 dy
+= widget
->allocation
.y
;
411 if (win
->HasFlag(wxRAISED_BORDER
))
413 gtk_draw_shadow( widget
->style
,
418 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
422 if (win
->HasFlag(wxSUNKEN_BORDER
))
424 gtk_draw_shadow( widget
->style
,
429 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
433 if (win
->HasFlag(wxSIMPLE_BORDER
))
436 gc
= gdk_gc_new( widget
->window
);
437 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
438 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
440 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
444 #endif // __WXUNIVERSAL__
447 //-----------------------------------------------------------------------------
448 // "expose_event" of m_widget
449 //-----------------------------------------------------------------------------
451 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
453 if (gdk_event
->count
> 0) return FALSE
;
455 draw_frame( widget
, win
);
459 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
465 //-----------------------------------------------------------------------------
466 // "draw" of m_widget
467 //-----------------------------------------------------------------------------
471 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
473 draw_frame( widget
, win
);
478 //-----------------------------------------------------------------------------
479 // "size_request" of m_widget
480 //-----------------------------------------------------------------------------
482 // make it extern because wxStatitText needs to disconnect this one
484 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
485 GtkRequisition
*requisition
,
489 win
->GetSize( &w
, &h
);
495 requisition
->height
= h
;
496 requisition
->width
= w
;
499 //-----------------------------------------------------------------------------
500 // "expose_event" of m_wxwindow
501 //-----------------------------------------------------------------------------
503 static int gtk_window_expose_callback( GtkWidget
*widget
,
504 GdkEventExpose
*gdk_event
,
510 wxapp_install_idle_handler();
513 // This callback gets called in drawing-idle time under
514 // GTK 2.0, so we don't need to defer anything to idle
517 GtkPizza
*pizza
= GTK_PIZZA( widget
);
518 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
523 wxPrintf( wxT("OnExpose from ") );
524 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
525 wxPrintf( win
->GetClassInfo()->GetClassName() );
526 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
527 (int)gdk_event
->area
.y
,
528 (int)gdk_event
->area
.width
,
529 (int)gdk_event
->area
.height
);
534 win
->m_wxwindow
->style
,
538 (GdkRectangle
*) NULL
,
540 (char *)"button", // const_cast
545 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
547 win
->GtkSendPaintEvents();
550 // Let parent window draw window less widgets
551 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
553 // This gets called immediately after an expose event
554 // under GTK 1.2 so we collect the calls and wait for
555 // the idle handler to pick things up.
557 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
559 gdk_event
->area
.width
,
560 gdk_event
->area
.height
);
561 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
563 gdk_event
->area
.width
,
564 gdk_event
->area
.height
);
566 // Actual redrawing takes place in idle time.
573 //-----------------------------------------------------------------------------
574 // "event" of m_wxwindow
575 //-----------------------------------------------------------------------------
577 // GTK thinks it is clever and filters out a certain amount of "unneeded"
578 // expose events. We need them, of course, so we override the main event
579 // procedure in GtkWidget by giving our own handler for all system events.
580 // There, we look for expose events ourselves whereas all other events are
583 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
584 GdkEventExpose
*event
,
587 if (event
->type
== GDK_EXPOSE
)
589 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
596 //-----------------------------------------------------------------------------
597 // "draw" of m_wxwindow
598 //-----------------------------------------------------------------------------
602 // This callback is a complete replacement of the gtk_pizza_draw() function,
603 // which is disabled.
605 static void gtk_window_draw_callback( GtkWidget
*widget
,
612 wxapp_install_idle_handler();
614 // if there are any children we must refresh everything
617 if ( !win
->HasFlag(wxFULL_REPAINT_ON_RESIZE
) &&
618 win
->GetChildren().IsEmpty() )
626 wxPrintf( wxT("OnDraw from ") );
627 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
628 wxPrintf( win
->GetClassInfo()->GetClassName() );
629 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
636 #ifndef __WXUNIVERSAL__
637 GtkPizza
*pizza
= GTK_PIZZA (widget
);
639 if (win
->GetThemeEnabled())
641 wxWindow
*parent
= win
->GetParent();
642 while (parent
&& !parent
->IsTopLevel())
643 parent
= parent
->GetParent();
647 gtk_paint_flat_box (parent
->m_widget
->style
,
658 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
659 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
661 // Update immediately, not in idle time.
664 #ifndef __WXUNIVERSAL__
665 // Redraw child widgets
666 GList
*children
= pizza
->children
;
669 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
670 children
= children
->next
;
672 GdkRectangle child_area
;
673 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
675 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
683 //-----------------------------------------------------------------------------
684 // "key_press_event" from any window
685 //-----------------------------------------------------------------------------
687 // set WXTRACE to this to see the key event codes on the console
688 #define TRACE_KEYS _T("keyevent")
690 // translates an X key symbol to WXK_XXX value
692 // if isChar is true it means that the value returned will be used for EVT_CHAR
693 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
694 // for example, while if it is false it means that the value is going to be
695 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
697 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
703 // Shift, Control and Alt don't generate the CHAR events at all
706 key_code
= isChar
? 0 : WXK_SHIFT
;
710 key_code
= isChar
? 0 : WXK_CONTROL
;
718 key_code
= isChar
? 0 : WXK_ALT
;
721 // neither do the toggle modifies
722 case GDK_Scroll_Lock
:
723 key_code
= isChar
? 0 : WXK_SCROLL
;
727 key_code
= isChar
? 0 : WXK_CAPITAL
;
731 key_code
= isChar
? 0 : WXK_NUMLOCK
;
735 // various other special keys
748 case GDK_ISO_Left_Tab
:
755 key_code
= WXK_RETURN
;
759 key_code
= WXK_CLEAR
;
763 key_code
= WXK_PAUSE
;
767 key_code
= WXK_SELECT
;
771 key_code
= WXK_PRINT
;
775 key_code
= WXK_EXECUTE
;
779 key_code
= WXK_ESCAPE
;
782 // cursor and other extended keyboard keys
784 key_code
= WXK_DELETE
;
800 key_code
= WXK_RIGHT
;
807 case GDK_Prior
: // == GDK_Page_Up
808 key_code
= WXK_PRIOR
;
811 case GDK_Next
: // == GDK_Page_Down
824 key_code
= WXK_INSERT
;
839 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
843 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
847 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
851 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
855 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
859 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
863 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
867 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
871 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
875 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
879 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
883 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
887 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
890 case GDK_KP_Prior
: // == GDK_KP_Page_Up
891 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
894 case GDK_KP_Next
: // == GDK_KP_Page_Down
895 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
899 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
903 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
907 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
911 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
915 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
918 case GDK_KP_Multiply
:
919 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
923 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
926 case GDK_KP_Separator
:
927 // FIXME: what is this?
928 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
931 case GDK_KP_Subtract
:
932 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
936 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
940 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
957 key_code
= WXK_F1
+ keysym
- GDK_F1
;
967 static inline bool wxIsAsciiKeysym(KeySym ks
)
973 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
975 GdkEventKey
*gdk_event
)
977 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
978 // but only event->keyval which is quite useless to us, so remember
979 // the last character from GDK_KEY_PRESS and reuse it as last resort
981 // NB: should be MT-safe as we're always called from the main thread only
986 } s_lastKeyPress
= { 0, 0 };
988 KeySym keysym
= gdk_event
->keyval
;
990 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
991 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
995 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
999 // do we have the translation or is it a plain ASCII character?
1000 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1002 // we should use keysym if it is ASCII as X does some translations
1003 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1004 // which we don't want here (but which we do use for OnChar())
1005 if ( !wxIsAsciiKeysym(keysym
) )
1007 keysym
= (KeySym
)gdk_event
->string
[0];
1010 // we want to always get the same key code when the same key is
1011 // pressed regardless of the state of the modifies, i.e. on a
1012 // standard US keyboard pressing '5' or '%' ('5' key with
1013 // Shift) should result in the same key code in OnKeyDown():
1014 // '5' (although OnChar() will get either '5' or '%').
1016 // to do it we first translate keysym to keycode (== scan code)
1017 // and then back but always using the lower register
1018 Display
*dpy
= (Display
*)wxGetDisplay();
1019 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1021 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1023 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1025 // use the normalized, i.e. lower register, keysym if we've
1027 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1029 // as explained above, we want to have lower register key codes
1030 // normally but for the letter keys we want to have the upper ones
1032 // NB: don't use XConvertCase() here, we want to do it for letters
1034 key_code
= toupper(key_code
);
1036 else // non ASCII key, what to do?
1038 // by default, ignore it
1041 // but if we have cached information from the last KEY_PRESS
1042 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1045 if ( keysym
== s_lastKeyPress
.keysym
)
1047 key_code
= s_lastKeyPress
.keycode
;
1052 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1054 // remember it to be reused for KEY_UP event later
1055 s_lastKeyPress
.keysym
= keysym
;
1056 s_lastKeyPress
.keycode
= key_code
;
1060 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1062 // sending unknown key events doesn't really make sense
1066 // now fill all the other fields
1069 GdkModifierType state
;
1070 if (gdk_event
->window
)
1071 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1073 event
.SetTimestamp( gdk_event
->time
);
1074 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1075 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1076 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1077 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1078 event
.m_keyCode
= key_code
;
1079 event
.m_scanCode
= gdk_event
->keyval
;
1080 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1081 event
.m_rawFlags
= 0;
1084 event
.SetEventObject( win
);
1090 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1091 GdkEventKey
*gdk_event
,
1097 wxapp_install_idle_handler();
1101 if (g_blockEventsOnDrag
)
1105 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1106 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1108 // unknown key pressed, ignore (the event would be useless anyhow)
1112 // Emit KEY_DOWN event
1113 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1118 wxWindowGTK
*ancestor
= win
;
1121 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1124 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1125 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1128 if (ancestor
->IsTopLevel())
1130 ancestor
= ancestor
->GetParent();
1133 #endif // wxUSE_ACCEL
1135 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1136 // will only be sent if it is not in an accelerator table.
1140 KeySym keysym
= gdk_event
->keyval
;
1142 // In GTK 2.0, we need to hand over the key event to an input method
1143 // and the IM will emit a "commit" event containing the actual utf8
1144 // character. In that case the EVT_CHAR events will be sent from
1145 // there. But only do it this way for non-KeySym keys.
1146 key_code
= wxTranslateKeySymToWXKey(gdk_event
->keyval
, FALSE
/* isChar */);
1147 if ( !key_code
&& win
->m_imContext
)
1149 gtk_im_context_filter_keypress ( (GtkIMContext
*) win
->m_imContext
, gdk_event
);
1155 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1156 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1159 if ( gdk_event
->length
== 1 )
1161 key_code
= (unsigned char)gdk_event
->string
[0];
1163 else if ( wxIsAsciiKeysym(keysym
) )
1166 key_code
= (unsigned char)keysym
;
1172 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1174 event
.m_keyCode
= key_code
;
1176 // Implement OnCharHook by checking ancesteror top level windows
1177 wxWindow
*parent
= win
;
1178 while (parent
&& !parent
->IsTopLevel())
1179 parent
= parent
->GetParent();
1182 event
.SetEventType( wxEVT_CHAR_HOOK
);
1183 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1188 event
.SetEventType(wxEVT_CHAR
);
1189 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1195 // win is a control: tab can be propagated up
1197 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1198 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1199 // have this style, yet choose not to process this particular TAB in which
1200 // case TAB must still work as a navigational character
1202 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1204 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1206 wxNavigationKeyEvent new_event
;
1207 new_event
.SetEventObject( win
->GetParent() );
1208 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1209 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1210 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1211 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1212 new_event
.SetCurrentFocus( win
);
1213 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1216 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1218 (gdk_event
->keyval
== GDK_Escape
) )
1220 // however only do it if we have a Cancel button in the dialog,
1221 // otherwise the user code may get confused by the events from a
1222 // non-existing button and, worse, a wxButton might get button event
1223 // from another button which is not really expected
1224 wxWindow
*winForCancel
= win
,
1226 while ( winForCancel
)
1228 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1231 // found a cancel button
1235 if ( winForCancel
->IsTopLevel() )
1237 // no need to look further
1241 // maybe our parent has a cancel button?
1242 winForCancel
= winForCancel
->GetParent();
1247 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1248 event
.SetEventObject(btnCancel
);
1249 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1255 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1263 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1269 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1272 event
.m_uniChar
= g_utf8_get_char( str
);
1274 // Backward compatible for ISO-8859
1275 if (event
.m_uniChar
< 256)
1276 event
.m_keyCode
= event
.m_uniChar
;
1278 gunichar uniChar
= g_utf8_get_char( str
);
1279 // We cannot handle Unicode in non-Unicode mode
1280 if (uniChar
> 255) return;
1282 event
.m_keyCode
= uniChar
;
1286 // TODO: We still need to set all the extra attributes of the
1287 // event, modifiers and such...
1290 // Implement OnCharHook by checking ancestor top level windows
1291 wxWindow
*parent
= window
;
1292 while (parent
&& !parent
->IsTopLevel())
1293 parent
= parent
->GetParent();
1296 event
.SetEventType( wxEVT_CHAR_HOOK
);
1297 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1302 event
.SetEventType(wxEVT_CHAR
);
1303 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1309 //-----------------------------------------------------------------------------
1310 // "key_release_event" from any window
1311 //-----------------------------------------------------------------------------
1313 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1314 GdkEventKey
*gdk_event
,
1320 wxapp_install_idle_handler();
1325 if (g_blockEventsOnDrag
)
1328 wxKeyEvent
event( wxEVT_KEY_UP
);
1329 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1331 // unknown key pressed, ignore (the event would be useless anyhow
1335 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1338 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1342 // ============================================================================
1344 // ============================================================================
1346 // ----------------------------------------------------------------------------
1347 // mouse event processing helpers
1348 // ----------------------------------------------------------------------------
1350 // init wxMouseEvent with the info from gdk_event
1352 // NB: this has to be a macro as gdk_event type is different for different
1353 // events we're used with
1354 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1355 /* wxMouseEvent& */ event, \
1356 /* GdkEventXXX * */ gdk_event) \
1358 event.SetTimestamp( gdk_event->time ); \
1359 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1360 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1361 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1362 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1363 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1364 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1365 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1366 if (event.GetEventType()==wxEVT_MOUSEWHEEL) \
1368 if (((GdkEventButton*)gdk_event)->button == 4) \
1369 event.m_wheelRotation = 120; \
1370 else if (((GdkEventButton*)gdk_event)->button == 5) \
1371 event.m_wheelRotation = -120; \
1374 wxPoint pt = win->GetClientAreaOrigin(); \
1375 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1376 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1378 event.SetEventObject( win ); \
1379 event.SetId( win->GetId() ); \
1380 event.SetTimestamp( gdk_event->time ); \
1383 static void AdjustEventButtonState(wxMouseEvent& event)
1385 // GDK reports the old state of the button for a button press event, but
1386 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1387 // for a LEFT_DOWN event, not FALSE, so we will invert
1388 // left/right/middleDown for the corresponding click events
1390 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1391 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1392 (event
.GetEventType() == wxEVT_LEFT_UP
))
1394 event
.m_leftDown
= !event
.m_leftDown
;
1398 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1399 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1400 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1402 event
.m_middleDown
= !event
.m_middleDown
;
1406 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1407 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1408 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1410 event
.m_rightDown
= !event
.m_rightDown
;
1415 // find the window to send the mouse event too
1417 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1422 if (win
->m_wxwindow
)
1424 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1425 xx
+= pizza
->xoffset
;
1426 yy
+= pizza
->yoffset
;
1429 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1432 wxWindowGTK
*child
= node
->GetData();
1434 node
= node
->GetNext();
1435 if (!child
->IsShown())
1438 if (child
->IsTransparentForMouse())
1440 // wxStaticBox is transparent in the box itself
1441 int xx1
= child
->m_x
;
1442 int yy1
= child
->m_y
;
1443 int xx2
= child
->m_x
+ child
->m_width
;
1444 int yy2
= child
->m_y
+ child
->m_height
;
1447 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1449 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1451 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1453 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1464 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1465 (child
->m_x
<= xx
) &&
1466 (child
->m_y
<= yy
) &&
1467 (child
->m_x
+child
->m_width
>= xx
) &&
1468 (child
->m_y
+child
->m_height
>= yy
))
1481 //-----------------------------------------------------------------------------
1482 // "button_press_event"
1483 //-----------------------------------------------------------------------------
1485 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1486 GdkEventButton
*gdk_event
,
1492 wxapp_install_idle_handler();
1495 wxPrintf( wxT("1) OnButtonPress from ") );
1496 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1497 wxPrintf( win->GetClassInfo()->GetClassName() );
1498 wxPrintf( wxT(".\n") );
1500 if (!win
->m_hasVMT
) return FALSE
;
1501 if (g_blockEventsOnDrag
) return TRUE
;
1502 if (g_blockEventsOnScroll
) return TRUE
;
1504 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1506 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1508 gtk_widget_grab_focus( win
->m_wxwindow
);
1510 wxPrintf( wxT("GrabFocus from ") );
1511 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1512 wxPrintf( win->GetClassInfo()->GetClassName() );
1513 wxPrintf( wxT(".\n") );
1517 // GDK sends surplus button down event
1518 // before a double click event. We
1519 // need to filter these out.
1520 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1522 GdkEvent
*peek_event
= gdk_event_peek();
1525 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1526 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1528 gdk_event_free( peek_event
);
1533 gdk_event_free( peek_event
);
1538 wxEventType event_type
= wxEVT_NULL
;
1540 if (gdk_event
->button
== 1)
1542 // note that GDK generates triple click events which are not supported
1543 // by wxWindows but still have to be passed to the app as otherwise
1544 // clicks would simply go missing
1545 switch (gdk_event
->type
)
1547 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1548 case GDK_BUTTON_PRESS
:
1549 event_type
= wxEVT_LEFT_DOWN
;
1552 case GDK_2BUTTON_PRESS
:
1553 event_type
= wxEVT_LEFT_DCLICK
;
1557 else if (gdk_event
->button
== 2)
1559 switch (gdk_event
->type
)
1561 case GDK_BUTTON_PRESS
:
1562 event_type
= wxEVT_MIDDLE_DOWN
;
1565 case GDK_2BUTTON_PRESS
:
1566 event_type
= wxEVT_MIDDLE_DCLICK
;
1570 else if (gdk_event
->button
== 3)
1572 switch (gdk_event
->type
)
1574 case GDK_BUTTON_PRESS
:
1575 event_type
= wxEVT_RIGHT_DOWN
;
1578 case GDK_2BUTTON_PRESS
:
1579 event_type
= wxEVT_RIGHT_DCLICK
;
1583 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1585 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1587 event_type
= wxEVT_MOUSEWHEEL
;
1591 if ( event_type
== wxEVT_NULL
)
1593 // unknown mouse button or click type
1597 wxMouseEvent
event( event_type
);
1598 InitMouseEvent( win
, event
, gdk_event
);
1600 AdjustEventButtonState(event
);
1602 // wxListBox actually get mouse events from the item, so we need to give it
1603 // a chance to correct this
1604 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1606 // find the correct window to send the event too: it may be a different one
1607 // from the one which got it at GTK+ level because some control don't have
1608 // their own X window and thus cannot get any events.
1609 if ( !g_captureWindow
)
1610 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1612 gs_timeLastClick
= gdk_event
->time
;
1615 wxPrintf( wxT("2) OnButtonPress from ") );
1616 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1617 wxPrintf( win->GetClassInfo()->GetClassName() );
1618 wxPrintf( wxT(".\n") );
1622 if (event_type
== wxEVT_LEFT_DCLICK
)
1624 // GTK 1.2 crashes when intercepting double
1625 // click events from both wxSpinButton and
1627 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1629 // Just disable this event for now.
1635 if (win
->GetEventHandler()->ProcessEvent( event
))
1637 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1644 //-----------------------------------------------------------------------------
1645 // "button_release_event"
1646 //-----------------------------------------------------------------------------
1648 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1649 GdkEventButton
*gdk_event
,
1655 wxapp_install_idle_handler();
1657 if (!win
->m_hasVMT
) return FALSE
;
1658 if (g_blockEventsOnDrag
) return FALSE
;
1659 if (g_blockEventsOnScroll
) return FALSE
;
1661 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1663 wxEventType event_type
= wxEVT_NULL
;
1665 switch (gdk_event
->button
)
1668 event_type
= wxEVT_LEFT_UP
;
1672 event_type
= wxEVT_MIDDLE_UP
;
1676 event_type
= wxEVT_RIGHT_UP
;
1680 // unknwon button, don't process
1684 wxMouseEvent
event( event_type
);
1685 InitMouseEvent( win
, event
, gdk_event
);
1687 AdjustEventButtonState(event
);
1689 // same wxListBox hack as above
1690 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1692 if ( event_type
== wxEVT_RIGHT_UP
)
1694 // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
1697 // (a) it's a command event and so is propagated to the parent
1698 // (b) under MSW it can be generated from kbd too
1699 // (c) it uses screen coords (because of (a))
1700 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1702 win
->ClientToScreen(event
.GetPosition()));
1703 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1706 if ( !g_captureWindow
)
1707 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1709 if (win
->GetEventHandler()->ProcessEvent( event
))
1711 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1718 //-----------------------------------------------------------------------------
1719 // "motion_notify_event"
1720 //-----------------------------------------------------------------------------
1722 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1723 GdkEventMotion
*gdk_event
,
1729 wxapp_install_idle_handler();
1731 if (!win
->m_hasVMT
) return FALSE
;
1732 if (g_blockEventsOnDrag
) return FALSE
;
1733 if (g_blockEventsOnScroll
) return FALSE
;
1735 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1737 if (gdk_event
->is_hint
)
1741 GdkModifierType state
;
1742 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1748 printf( "OnMotion from " );
1749 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1750 printf( win->GetClassInfo()->GetClassName() );
1754 wxMouseEvent
event( wxEVT_MOTION
);
1755 InitMouseEvent(win
, event
, gdk_event
);
1757 if ( g_captureWindow
)
1759 // synthetize a mouse enter or leave event if needed
1760 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1761 // This seems to be necessary and actually been added to
1762 // GDK itself in version 2.0.X
1765 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1766 if ( hasMouse
!= g_captureWindowHasMouse
)
1768 // the mouse changed window
1769 g_captureWindowHasMouse
= hasMouse
;
1771 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1772 : wxEVT_LEAVE_WINDOW
);
1773 InitMouseEvent(win
, event
, gdk_event
);
1774 event
.SetEventObject(win
);
1775 win
->GetEventHandler()->ProcessEvent(event
);
1780 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1783 if (win
->GetEventHandler()->ProcessEvent( event
))
1785 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1793 //-----------------------------------------------------------------------------
1794 // "mouse_wheel_event"
1795 //-----------------------------------------------------------------------------
1797 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1798 GdkEventScroll
* gdk_event
,
1804 wxapp_install_idle_handler();
1806 wxEventType event_type
= wxEVT_NULL
;
1807 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1808 event_type
= wxEVT_MOUSEWHEEL
;
1809 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1810 event_type
= wxEVT_MOUSEWHEEL
;
1814 wxMouseEvent
event( event_type
);
1815 // Can't use InitMouse macro because scroll events don't have button
1816 event
.SetTimestamp( gdk_event
->time
);
1817 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1818 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1819 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1820 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1821 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1822 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1823 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1824 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1825 event
.m_wheelRotation
= 120;
1827 event
.m_wheelRotation
= -120;
1829 wxPoint pt
= win
->GetClientAreaOrigin();
1830 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1831 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1833 event
.SetEventObject( win
);
1834 event
.SetId( win
->GetId() );
1835 event
.SetTimestamp( gdk_event
->time
);
1837 if (win
->GetEventHandler()->ProcessEvent( event
))
1839 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1847 //-----------------------------------------------------------------------------
1849 //-----------------------------------------------------------------------------
1851 // send the wxChildFocusEvent and wxFocusEvent, common code of
1852 // gtk_window_focus_in_callback() and SetFocus()
1853 static bool DoSendFocusEvents(wxWindow
*win
)
1855 // Notify the parent keeping track of focus for the kbd navigation
1856 // purposes that we got it.
1857 wxChildFocusEvent
eventChildFocus(win
);
1858 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1860 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1861 eventFocus
.SetEventObject(win
);
1863 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1866 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1867 GdkEvent
*WXUNUSED(event
),
1873 wxapp_install_idle_handler();
1875 if (!win
->m_hasVMT
) return FALSE
;
1876 if (g_blockEventsOnDrag
) return FALSE
;
1878 switch ( g_sendActivateEvent
)
1881 // we've got focus from outside, synthetize wxActivateEvent
1882 g_sendActivateEvent
= 1;
1886 // another our window just lost focus, it was already ours before
1887 // - don't send any wxActivateEvent
1888 g_sendActivateEvent
= -1;
1893 g_focusWindow
= win
;
1895 wxLogTrace(TRACE_FOCUS
,
1896 _T("%s: focus in"), win
->GetName().c_str());
1900 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1904 // caret needs to be informed about focus change
1905 wxCaret
*caret
= win
->GetCaret();
1908 caret
->OnSetFocus();
1910 #endif // wxUSE_CARET
1912 g_activeFrameLostFocus
= FALSE
;
1914 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1915 if ( active
!= g_activeFrame
)
1917 if ( g_activeFrame
)
1919 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1920 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1921 event
.SetEventObject(g_activeFrame
);
1922 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1925 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1926 g_activeFrame
= active
;
1927 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1928 event
.SetEventObject(g_activeFrame
);
1929 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1931 // Don't send focus events in addition to activate
1932 // if (win == g_activeFrame)
1936 // does the window itself think that it has the focus?
1937 if ( !win
->m_hasFocus
)
1939 // not yet, notify it
1940 win
->m_hasFocus
= TRUE
;
1942 if ( DoSendFocusEvents(win
) )
1944 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1952 //-----------------------------------------------------------------------------
1953 // "focus_out_event"
1954 //-----------------------------------------------------------------------------
1956 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1961 wxapp_install_idle_handler();
1963 if (!win
->m_hasVMT
) return FALSE
;
1964 if (g_blockEventsOnDrag
) return FALSE
;
1966 wxLogTrace( TRACE_FOCUS
,
1967 _T("%s: focus out"), win
->GetName().c_str() );
1969 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1971 // VZ: commenting this out because it does happen (although not easy
1972 // to reproduce, I only see it when using wxMiniFrame and not
1973 // always) and makes using Mahogany quite annoying
1975 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1976 wxT("unfocusing window that hasn't gained focus properly") );
1979 g_activeFrameLostFocus
= TRUE
;
1982 // if the focus goes out of our app alltogether, OnIdle() will send
1983 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1984 // g_sendActivateEvent to -1
1985 g_sendActivateEvent
= 0;
1987 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1991 g_focusWindow
= (wxWindowGTK
*)NULL
;
1999 // caret needs to be informed about focus change
2000 wxCaret
*caret
= win
->GetCaret();
2003 caret
->OnKillFocus();
2005 #endif // wxUSE_CARET
2007 // don't send the window a kill focus event if it thinks that it doesn't
2008 // have focus already
2009 if ( win
->m_hasFocus
)
2011 win
->m_hasFocus
= FALSE
;
2013 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2014 event
.SetEventObject( win
);
2016 if (win
->GetEventHandler()->ProcessEvent( event
))
2018 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
2026 //-----------------------------------------------------------------------------
2027 // "enter_notify_event"
2028 //-----------------------------------------------------------------------------
2031 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2032 GdkEventCrossing
*gdk_event
,
2038 wxapp_install_idle_handler();
2040 if (!win
->m_hasVMT
) return FALSE
;
2041 if (g_blockEventsOnDrag
) return FALSE
;
2043 // Event was emitted after a grab
2044 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2046 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2050 GdkModifierType state
= (GdkModifierType
)0;
2052 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2054 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2055 InitMouseEvent(win
, event
, gdk_event
);
2056 wxPoint pt
= win
->GetClientAreaOrigin();
2057 event
.m_x
= x
+ pt
.x
;
2058 event
.m_y
= y
+ pt
.y
;
2060 if (win
->GetEventHandler()->ProcessEvent( event
))
2062 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2069 //-----------------------------------------------------------------------------
2070 // "leave_notify_event"
2071 //-----------------------------------------------------------------------------
2073 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2078 wxapp_install_idle_handler();
2080 if (!win
->m_hasVMT
) return FALSE
;
2081 if (g_blockEventsOnDrag
) return FALSE
;
2083 // Event was emitted after an ungrab
2084 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2086 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2088 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2089 event
.SetTimestamp( gdk_event
->time
);
2090 event
.SetEventObject( win
);
2094 GdkModifierType state
= (GdkModifierType
)0;
2096 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2098 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2099 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2100 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2101 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2102 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2103 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2104 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2106 wxPoint pt
= win
->GetClientAreaOrigin();
2107 event
.m_x
= x
+ pt
.x
;
2108 event
.m_y
= y
+ pt
.y
;
2110 if (win
->GetEventHandler()->ProcessEvent( event
))
2112 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2119 //-----------------------------------------------------------------------------
2120 // "value_changed" from m_vAdjust
2121 //-----------------------------------------------------------------------------
2123 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2130 wxapp_install_idle_handler();
2132 if (g_blockEventsOnDrag
) return;
2134 if (!win
->m_hasVMT
) return;
2136 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2137 if (fabs(diff
) < 0.2) return;
2139 win
->m_oldVerticalPos
= adjust
->value
;
2142 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2144 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2146 int value
= (int)(adjust
->value
+0.5);
2148 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2149 event
.SetEventObject( win
);
2150 win
->GetEventHandler()->ProcessEvent( event
);
2153 //-----------------------------------------------------------------------------
2154 // "value_changed" from m_hAdjust
2155 //-----------------------------------------------------------------------------
2157 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2164 wxapp_install_idle_handler();
2166 if (g_blockEventsOnDrag
) return;
2167 if (!win
->m_hasVMT
) return;
2169 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2170 if (fabs(diff
) < 0.2) return;
2173 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2175 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2177 win
->m_oldHorizontalPos
= adjust
->value
;
2179 int value
= (int)(adjust
->value
+0.5);
2181 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2182 event
.SetEventObject( win
);
2183 win
->GetEventHandler()->ProcessEvent( event
);
2186 //-----------------------------------------------------------------------------
2187 // "button_press_event" from scrollbar
2188 //-----------------------------------------------------------------------------
2190 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2191 GdkEventButton
*gdk_event
,
2197 wxapp_install_idle_handler();
2200 g_blockEventsOnScroll
= TRUE
;
2202 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2204 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2210 //-----------------------------------------------------------------------------
2211 // "button_release_event" from scrollbar
2212 //-----------------------------------------------------------------------------
2214 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2215 GdkEventButton
*WXUNUSED(gdk_event
),
2220 // don't test here as we can release the mouse while being over
2221 // a different window than the slider
2223 // if (gdk_event->window != widget->slider) return FALSE;
2225 g_blockEventsOnScroll
= FALSE
;
2227 if (win
->m_isScrolling
)
2229 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2233 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2234 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2236 value
= (int)(win
->m_hAdjust
->value
+0.5);
2239 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2241 value
= (int)(win
->m_vAdjust
->value
+0.5);
2245 wxScrollWinEvent
event( command
, value
, dir
);
2246 event
.SetEventObject( win
);
2247 win
->GetEventHandler()->ProcessEvent( event
);
2250 win
->m_isScrolling
= FALSE
;
2255 // ----------------------------------------------------------------------------
2256 // this wxWindowBase function is implemented here (in platform-specific file)
2257 // because it is static and so couldn't be made virtual
2258 // ----------------------------------------------------------------------------
2260 wxWindow
*wxWindowBase::FindFocus()
2262 // the cast is necessary when we compile in wxUniversal mode
2263 return (wxWindow
*)g_focusWindow
;
2267 //-----------------------------------------------------------------------------
2268 // "realize" from m_widget
2269 //-----------------------------------------------------------------------------
2271 /* We cannot set colours and fonts before the widget has
2272 been realized, so we do this directly after realization. */
2275 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2280 wxapp_install_idle_handler();
2282 if (win
->m_delayedBackgroundColour
&& !win
->GetThemeEnabled())
2283 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2285 if (win
->m_delayedForegroundColour
&& !win
->GetThemeEnabled())
2286 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2289 if (win
->m_imContext
)
2291 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2292 gtk_im_context_set_client_window( (GtkIMContext
*) win
->m_imContext
, pizza
->bin_window
);
2296 wxWindowCreateEvent
event( win
);
2297 event
.SetEventObject( win
);
2298 win
->GetEventHandler()->ProcessEvent( event
);
2303 //-----------------------------------------------------------------------------
2305 //-----------------------------------------------------------------------------
2308 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2309 GtkAllocation
*WXUNUSED(alloc
),
2313 wxapp_install_idle_handler();
2315 if (!win
->m_hasScrolling
) return;
2317 int client_width
= 0;
2318 int client_height
= 0;
2319 win
->GetClientSize( &client_width
, &client_height
);
2320 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2323 win
->m_oldClientWidth
= client_width
;
2324 win
->m_oldClientHeight
= client_height
;
2326 if (!win
->m_nativeSizeEvent
)
2328 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2329 event
.SetEventObject( win
);
2330 win
->GetEventHandler()->ProcessEvent( event
);
2336 #define WXUNUSED_UNLESS_XIM(param) param
2338 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2341 /* Resize XIM window */
2344 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2345 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2346 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2349 wxapp_install_idle_handler();
2355 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2359 gdk_window_get_size (widget
->window
, &width
, &height
);
2360 win
->m_icattr
->preedit_area
.width
= width
;
2361 win
->m_icattr
->preedit_area
.height
= height
;
2362 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2367 //-----------------------------------------------------------------------------
2368 // "realize" from m_wxwindow
2369 //-----------------------------------------------------------------------------
2371 /* Initialize XIM support */
2374 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2375 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2378 wxapp_install_idle_handler();
2381 if (win
->m_ic
) return FALSE
;
2382 if (!widget
) return FALSE
;
2383 if (!gdk_im_ready()) return FALSE
;
2385 win
->m_icattr
= gdk_ic_attr_new();
2386 if (!win
->m_icattr
) return FALSE
;
2390 GdkColormap
*colormap
;
2391 GdkICAttr
*attr
= win
->m_icattr
;
2392 unsigned attrmask
= GDK_IC_ALL_REQ
;
2394 GdkIMStyle supported_style
= (GdkIMStyle
)
2395 (GDK_IM_PREEDIT_NONE
|
2396 GDK_IM_PREEDIT_NOTHING
|
2397 GDK_IM_PREEDIT_POSITION
|
2398 GDK_IM_STATUS_NONE
|
2399 GDK_IM_STATUS_NOTHING
);
2401 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2402 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2404 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2405 attr
->client_window
= widget
->window
;
2407 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2408 gtk_widget_get_default_colormap ())
2410 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2411 attr
->preedit_colormap
= colormap
;
2414 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2415 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2416 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2417 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2419 switch (style
& GDK_IM_PREEDIT_MASK
)
2421 case GDK_IM_PREEDIT_POSITION
:
2422 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2424 g_warning ("over-the-spot style requires fontset");
2428 gdk_window_get_size (widget
->window
, &width
, &height
);
2430 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2431 attr
->spot_location
.x
= 0;
2432 attr
->spot_location
.y
= height
;
2433 attr
->preedit_area
.x
= 0;
2434 attr
->preedit_area
.y
= 0;
2435 attr
->preedit_area
.width
= width
;
2436 attr
->preedit_area
.height
= height
;
2437 attr
->preedit_fontset
= widget
->style
->font
;
2442 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2444 if (win
->m_ic
== NULL
)
2445 g_warning ("Can't create input context.");
2448 mask
= gdk_window_get_events (widget
->window
);
2449 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2450 gdk_window_set_events (widget
->window
, mask
);
2452 if (GTK_WIDGET_HAS_FOCUS(widget
))
2453 gdk_im_begin (win
->m_ic
, widget
->window
);
2460 //-----------------------------------------------------------------------------
2461 // InsertChild for wxWindowGTK.
2462 //-----------------------------------------------------------------------------
2464 /* Callback for wxWindowGTK. This very strange beast has to be used because
2465 * C++ has no virtual methods in a constructor. We have to emulate a
2466 * virtual function here as wxNotebook requires a different way to insert
2467 * a child in it. I had opted for creating a wxNotebookPage window class
2468 * which would have made this superfluous (such in the MDI window system),
2469 * but no-one was listening to me... */
2471 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2473 /* the window might have been scrolled already, do we
2474 have to adapt the position */
2475 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2476 child
->m_x
+= pizza
->xoffset
;
2477 child
->m_y
+= pizza
->yoffset
;
2479 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2480 GTK_WIDGET(child
->m_widget
),
2487 //-----------------------------------------------------------------------------
2489 //-----------------------------------------------------------------------------
2491 wxWindow
*wxGetActiveWindow()
2493 return wxWindow::FindFocus();
2496 //-----------------------------------------------------------------------------
2498 //-----------------------------------------------------------------------------
2500 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2502 #ifdef __WXUNIVERSAL__
2503 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2505 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2506 #endif // __WXUNIVERSAL__/__WXGTK__
2508 void wxWindowGTK::Init()
2511 m_widget
= (GtkWidget
*) NULL
;
2512 m_wxwindow
= (GtkWidget
*) NULL
;
2513 m_focusWidget
= (GtkWidget
*) NULL
;
2523 m_needParent
= TRUE
;
2524 m_isBeingDeleted
= FALSE
;
2527 m_nativeSizeEvent
= FALSE
;
2529 m_hasScrolling
= FALSE
;
2530 m_isScrolling
= FALSE
;
2532 m_hAdjust
= (GtkAdjustment
*) NULL
;
2533 m_vAdjust
= (GtkAdjustment
*) NULL
;
2534 m_oldHorizontalPos
=
2535 m_oldVerticalPos
= 0.0;
2537 m_oldClientHeight
= 0;
2540 m_widgetStyle
= (GtkStyle
*) NULL
;
2542 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2544 m_acceptsFocus
= FALSE
;
2547 m_clipPaintRegion
= FALSE
;
2549 m_cursor
= *wxSTANDARD_CURSOR
;
2551 m_delayedForegroundColour
= FALSE
;
2552 m_delayedBackgroundColour
= FALSE
;
2556 m_x11Context
= NULL
;
2559 m_ic
= (GdkIC
*) NULL
;
2560 m_icattr
= (GdkICAttr
*) NULL
;
2565 wxWindowGTK::wxWindowGTK()
2570 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2575 const wxString
&name
)
2579 Create( parent
, id
, pos
, size
, style
, name
);
2582 bool wxWindowGTK::Create( wxWindow
*parent
,
2587 const wxString
&name
)
2589 if (!PreCreation( parent
, pos
, size
) ||
2590 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2592 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2596 m_insertCallback
= wxInsertChildInWindow
;
2598 // always needed for background clearing
2599 m_delayedBackgroundColour
= TRUE
;
2601 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2602 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2604 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2606 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2607 scroll_class
->scrollbar_spacing
= 0;
2609 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2611 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2612 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2614 m_wxwindow
= gtk_pizza_new();
2616 #ifndef __WXUNIVERSAL__
2617 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2619 if (HasFlag(wxRAISED_BORDER
))
2621 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2623 else if (HasFlag(wxSUNKEN_BORDER
))
2625 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2627 else if (HasFlag(wxSIMPLE_BORDER
))
2629 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2633 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2635 #endif // __WXUNIVERSAL__
2637 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2639 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2640 m_acceptsFocus
= TRUE
;
2642 // I _really_ don't want scrollbars in the beginning
2643 m_vAdjust
->lower
= 0.0;
2644 m_vAdjust
->upper
= 1.0;
2645 m_vAdjust
->value
= 0.0;
2646 m_vAdjust
->step_increment
= 1.0;
2647 m_vAdjust
->page_increment
= 1.0;
2648 m_vAdjust
->page_size
= 5.0;
2649 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2650 m_hAdjust
->lower
= 0.0;
2651 m_hAdjust
->upper
= 1.0;
2652 m_hAdjust
->value
= 0.0;
2653 m_hAdjust
->step_increment
= 1.0;
2654 m_hAdjust
->page_increment
= 1.0;
2655 m_hAdjust
->page_size
= 5.0;
2656 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2658 // these handlers block mouse events to any window during scrolling such as
2659 // motion events and prevent GTK and wxWindows from fighting over where the
2662 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2663 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2665 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2666 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2668 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2669 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2671 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2672 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2674 // these handlers get notified when screen updates are required either when
2675 // scrolling or when the window size (and therefore scrollbar configuration)
2678 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2679 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2680 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2681 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2684 // Create input method handler
2685 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2687 // Cannot handle drawing preedited text yet
2688 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2690 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2691 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2694 gtk_widget_show( m_wxwindow
);
2697 m_parent
->DoAddChild( this );
2699 m_focusWidget
= m_wxwindow
;
2708 wxWindowGTK::~wxWindowGTK()
2712 if (g_focusWindow
== this)
2713 g_focusWindow
= NULL
;
2715 if (g_activeFrame
== this)
2716 g_activeFrame
= NULL
;
2718 if ( g_delayedFocus
== this )
2719 g_delayedFocus
= NULL
;
2721 m_isBeingDeleted
= TRUE
;
2731 gdk_ic_destroy (m_ic
);
2733 gdk_ic_attr_destroy (m_icattr
);
2738 #if DISABLE_STYLE_IF_BROKEN_THEME
2739 // don't delete if it's a pixmap theme style
2740 if (!m_widgetStyle
->engine_data
)
2741 gtk_style_unref( m_widgetStyle
);
2743 m_widgetStyle
= (GtkStyle
*) NULL
;
2748 gtk_widget_destroy( m_wxwindow
);
2749 m_wxwindow
= (GtkWidget
*) NULL
;
2754 gtk_widget_destroy( m_widget
);
2755 m_widget
= (GtkWidget
*) NULL
;
2759 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2761 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2763 // This turns -1 into 30 so that a minimal window is
2764 // visible even although -1,-1 has been given as the
2765 // size of the window. the same trick is used in other
2766 // ports and should make debugging easier.
2767 m_width
= WidthDefault(size
.x
) ;
2768 m_height
= HeightDefault(size
.y
);
2773 // some reasonable defaults
2778 m_x
= (gdk_screen_width () - m_width
) / 2;
2779 if (m_x
< 10) m_x
= 10;
2783 m_y
= (gdk_screen_height () - m_height
) / 2;
2784 if (m_y
< 10) m_y
= 10;
2791 void wxWindowGTK::PostCreation()
2793 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2799 // these get reported to wxWindows -> wxPaintEvent
2801 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2803 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2804 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2807 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2808 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2810 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2812 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2813 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2816 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2820 // Create input method handler
2821 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2823 // Cannot handle drawing preedited text yet
2824 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2826 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2827 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2831 // these are called when the "sunken" or "raised" borders are drawn
2832 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2833 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2836 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2837 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2843 if (m_focusWidget
== NULL
)
2844 m_focusWidget
= m_widget
;
2846 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2847 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2849 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2850 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2852 // connect to the various key and mouse handlers
2854 GtkWidget
*connect_widget
= GetConnectWidget();
2856 ConnectWidget( connect_widget
);
2858 /* We cannot set colours, fonts and cursors before the widget has
2859 been realized, so we do this directly after realization */
2860 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2861 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2865 // Catch native resize events
2866 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2867 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2869 // Initialize XIM support
2870 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2871 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2873 // And resize XIM window
2874 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2875 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2878 if ( !GTK_IS_COMBO(m_widget
))
2880 // This is needed if we want to add our windows into native
2881 // GTK control, such as the toolbar. With this callback, the
2882 // toolbar gets to know the correct size (the one set by the
2883 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2884 // when moving to GTK 2.0.
2885 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2886 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2893 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2895 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2896 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2898 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2899 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2901 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2902 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2904 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2905 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2907 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2908 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2911 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2912 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2915 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2916 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2918 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2919 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2922 bool wxWindowGTK::Destroy()
2924 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2928 return wxWindowBase::Destroy();
2931 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2933 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2936 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2938 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2939 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2942 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2945 if (m_resizing
) return; /* I don't like recursions */
2948 int currentX
, currentY
;
2949 GetPosition(¤tX
, ¤tY
);
2950 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2952 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2954 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2956 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2958 /* don't set the size for children of wxNotebook, just take the values. */
2966 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2967 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2969 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2970 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2974 m_x
= x
+ pizza
->xoffset
;
2975 m_y
= y
+ pizza
->yoffset
;
2977 if (width
!= -1) m_width
= width
;
2978 if (height
!= -1) m_height
= height
;
2980 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2982 if (width
== -1) m_width
= 80;
2985 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2987 if (height
== -1) m_height
= 26;
2990 int minWidth
= GetMinWidth(),
2991 minHeight
= GetMinHeight(),
2992 maxWidth
= GetMaxWidth(),
2993 maxHeight
= GetMaxHeight();
2995 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2996 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2997 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2998 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3001 int bottom_border
= 0;
3004 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3006 /* the default button has a border around it */
3012 DoMoveWindow( m_x
-border
,
3015 m_height
+border
+bottom_border
);
3020 /* Sometimes the client area changes size without the
3021 whole windows's size changing, but if the whole
3022 windows's size doesn't change, no wxSizeEvent will
3023 normally be sent. Here we add an extra test if
3024 the client test has been changed and this will
3026 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3030 wxPrintf( "OnSize sent from " );
3031 if (GetClassInfo() && GetClassInfo()->GetClassName())
3032 wxPrintf( GetClassInfo()->GetClassName() );
3033 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3036 if (!m_nativeSizeEvent
)
3038 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3039 event
.SetEventObject( this );
3040 GetEventHandler()->ProcessEvent( event
);
3046 void wxWindowGTK::OnInternalIdle()
3048 // Update invalidated regions.
3051 // Synthetize activate events.
3052 if ( g_sendActivateEvent
!= -1 )
3054 bool activate
= g_sendActivateEvent
!= 0;
3057 g_sendActivateEvent
= -1;
3059 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
3062 if ( g_activeFrameLostFocus
)
3064 if ( g_activeFrame
)
3066 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3067 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3068 event
.SetEventObject(g_activeFrame
);
3069 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3070 g_activeFrame
= NULL
;
3072 g_activeFrameLostFocus
= FALSE
;
3075 wxCursor cursor
= m_cursor
;
3076 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3080 /* I now set the cursor anew in every OnInternalIdle call
3081 as setting the cursor in a parent window also effects the
3082 windows above so that checking for the current cursor is
3087 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3089 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3091 if (!g_globalCursor
.Ok())
3092 cursor
= *wxSTANDARD_CURSOR
;
3094 window
= m_widget
->window
;
3095 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3096 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3102 GdkWindow
*window
= m_widget
->window
;
3103 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3104 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3109 if (wxUpdateUIEvent::CanUpdate(this))
3110 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3113 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3115 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3117 if (width
) (*width
) = m_width
;
3118 if (height
) (*height
) = m_height
;
3121 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3123 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3127 SetSize( width
, height
);
3134 #ifndef __WXUNIVERSAL__
3135 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3137 /* when using GTK 1.2 we set the shadow border size to 2 */
3141 if (HasFlag(wxSIMPLE_BORDER
))
3143 /* when using GTK 1.2 we set the simple border size to 1 */
3147 #endif // __WXUNIVERSAL__
3151 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3153 GtkRequisition vscroll_req
;
3154 vscroll_req
.width
= 2;
3155 vscroll_req
.height
= 2;
3156 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3157 (scroll_window
->vscrollbar
, &vscroll_req
);
3159 GtkRequisition hscroll_req
;
3160 hscroll_req
.width
= 2;
3161 hscroll_req
.height
= 2;
3162 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3163 (scroll_window
->hscrollbar
, &hscroll_req
);
3165 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3167 if (scroll_window
->vscrollbar_visible
)
3169 dw
+= vscroll_req
.width
;
3170 dw
+= scroll_class
->scrollbar_spacing
;
3173 if (scroll_window
->hscrollbar_visible
)
3175 dh
+= hscroll_req
.height
;
3176 dh
+= scroll_class
->scrollbar_spacing
;
3180 SetSize( width
+dw
, height
+dh
);
3184 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3186 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3190 if (width
) (*width
) = m_width
;
3191 if (height
) (*height
) = m_height
;
3198 #ifndef __WXUNIVERSAL__
3199 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3201 /* when using GTK 1.2 we set the shadow border size to 2 */
3205 if (HasFlag(wxSIMPLE_BORDER
))
3207 /* when using GTK 1.2 we set the simple border size to 1 */
3211 #endif // __WXUNIVERSAL__
3215 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3217 GtkRequisition vscroll_req
;
3218 vscroll_req
.width
= 2;
3219 vscroll_req
.height
= 2;
3220 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3221 (scroll_window
->vscrollbar
, &vscroll_req
);
3223 GtkRequisition hscroll_req
;
3224 hscroll_req
.width
= 2;
3225 hscroll_req
.height
= 2;
3226 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3227 (scroll_window
->hscrollbar
, &hscroll_req
);
3229 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3231 if (scroll_window
->vscrollbar_visible
)
3233 dw
+= vscroll_req
.width
;
3234 dw
+= scroll_class
->scrollbar_spacing
;
3237 if (scroll_window
->hscrollbar_visible
)
3239 dh
+= hscroll_req
.height
;
3240 dh
+= scroll_class
->scrollbar_spacing
;
3244 if (width
) (*width
) = m_width
- dw
;
3245 if (height
) (*height
) = m_height
- dh
;
3249 printf( "GetClientSize, name %s ", GetName().c_str() );
3250 if (width) printf( " width = %d", (*width) );
3251 if (height) printf( " height = %d", (*height) );
3256 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3258 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3262 if (m_parent
&& m_parent
->m_wxwindow
)
3264 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3265 dx
= pizza
->xoffset
;
3266 dy
= pizza
->yoffset
;
3269 if (x
) (*x
) = m_x
- dx
;
3270 if (y
) (*y
) = m_y
- dy
;
3273 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3275 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3277 if (!m_widget
->window
) return;
3279 GdkWindow
*source
= (GdkWindow
*) NULL
;
3281 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3283 source
= m_widget
->window
;
3287 gdk_window_get_origin( source
, &org_x
, &org_y
);
3291 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3293 org_x
+= m_widget
->allocation
.x
;
3294 org_y
+= m_widget
->allocation
.y
;
3302 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3304 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3306 if (!m_widget
->window
) return;
3308 GdkWindow
*source
= (GdkWindow
*) NULL
;
3310 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3312 source
= m_widget
->window
;
3316 gdk_window_get_origin( source
, &org_x
, &org_y
);
3320 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3322 org_x
+= m_widget
->allocation
.x
;
3323 org_y
+= m_widget
->allocation
.y
;
3331 bool wxWindowGTK::Show( bool show
)
3333 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3335 if (!wxWindowBase::Show(show
))
3342 gtk_widget_show( m_widget
);
3344 gtk_widget_hide( m_widget
);
3346 wxShowEvent
eventShow(GetId(), show
);
3347 eventShow
.m_eventObject
= this;
3349 GetEventHandler()->ProcessEvent(eventShow
);
3354 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3356 win
->OnParentEnable(enable
);
3358 // Recurse, so that children have the opportunity to Do The Right Thing
3359 // and reset colours that have been messed up by a parent's (really ancestor's)
3361 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3363 node
= node
->GetNext() )
3365 wxWindow
*child
= node
->GetData();
3366 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3367 wxWindowNotifyEnable(child
, enable
);
3371 bool wxWindowGTK::Enable( bool enable
)
3373 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3375 if (!wxWindowBase::Enable(enable
))
3381 gtk_widget_set_sensitive( m_widget
, enable
);
3383 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3385 wxWindowNotifyEnable(this, enable
);
3390 int wxWindowGTK::GetCharHeight() const
3392 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3394 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3397 PangoContext
*context
= NULL
;
3399 context
= gtk_widget_get_pango_context( m_widget
);
3404 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3405 PangoLayout
*layout
= pango_layout_new(context
);
3406 pango_layout_set_font_description(layout
, desc
);
3407 pango_layout_set_text(layout
, "H", 1);
3408 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3410 PangoRectangle rect
;
3411 pango_layout_line_get_extents(line
, NULL
, &rect
);
3413 g_object_unref( G_OBJECT( layout
) );
3415 return (int) (rect
.height
/ PANGO_SCALE
);
3417 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3419 return font
->ascent
+ font
->descent
;
3423 int wxWindowGTK::GetCharWidth() const
3425 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3427 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3430 PangoContext
*context
= NULL
;
3432 context
= gtk_widget_get_pango_context( m_widget
);
3437 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3438 PangoLayout
*layout
= pango_layout_new(context
);
3439 pango_layout_set_font_description(layout
, desc
);
3440 pango_layout_set_text(layout
, "g", 1);
3441 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3443 PangoRectangle rect
;
3444 pango_layout_line_get_extents(line
, NULL
, &rect
);
3446 g_object_unref( G_OBJECT( layout
) );
3448 return (int) (rect
.width
/ PANGO_SCALE
);
3450 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3452 return gdk_string_width( font
, "g" );
3456 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3460 int *externalLeading
,
3461 const wxFont
*theFont
) const
3463 wxFont fontToUse
= m_font
;
3464 if (theFont
) fontToUse
= *theFont
;
3466 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3468 if (string
.IsEmpty())
3476 PangoContext
*context
= NULL
;
3478 context
= gtk_widget_get_pango_context( m_widget
);
3487 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3488 PangoLayout
*layout
= pango_layout_new(context
);
3489 pango_layout_set_font_description(layout
, desc
);
3492 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3493 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3495 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3496 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3497 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3500 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3502 PangoRectangle rect
;
3503 pango_layout_line_get_extents(line
, NULL
, &rect
);
3505 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3506 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3509 // Do something about metrics here
3512 if (externalLeading
) (*externalLeading
) = 0; // ??
3514 g_object_unref( G_OBJECT( layout
) );
3516 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3517 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3518 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3519 if (descent
) (*descent
) = font
->descent
;
3520 if (externalLeading
) (*externalLeading
) = 0; // ??
3524 void wxWindowGTK::SetFocus()
3526 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3530 // don't do anything if we already have focus
3536 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3538 gtk_widget_grab_focus (m_wxwindow
);
3543 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3545 if (!GTK_WIDGET_REALIZED(m_widget
))
3547 // we can't set the focus to the widget now so we remember that
3548 // it should be focused and will do it later, during the idle
3549 // time, as soon as we can
3550 wxLogTrace(TRACE_FOCUS
,
3551 _T("Delaying setting focus to %s(%s)"),
3552 GetClassInfo()->GetClassName(), GetLabel().c_str());
3554 g_delayedFocus
= this;
3558 wxLogTrace(TRACE_FOCUS
,
3559 _T("Setting focus to %s(%s)"),
3560 GetClassInfo()->GetClassName(), GetLabel().c_str());
3562 gtk_widget_grab_focus (m_widget
);
3565 else if (GTK_IS_CONTAINER(m_widget
))
3567 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3571 wxLogTrace(TRACE_FOCUS
,
3572 _T("Can't set focus to %s(%s)"),
3573 GetClassInfo()->GetClassName(), GetLabel().c_str());
3578 bool wxWindowGTK::AcceptsFocus() const
3580 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3583 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3585 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3587 wxWindowGTK
*oldParent
= m_parent
,
3588 *newParent
= (wxWindowGTK
*)newParentBase
;
3590 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3592 if ( !wxWindowBase::Reparent(newParent
) )
3595 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3597 /* prevent GTK from deleting the widget arbitrarily */
3598 gtk_widget_ref( m_widget
);
3602 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3605 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3609 /* insert GTK representation */
3610 (*(newParent
->m_insertCallback
))(newParent
, this);
3613 /* reverse: prevent GTK from deleting the widget arbitrarily */
3614 gtk_widget_unref( m_widget
);
3619 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3621 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3623 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3625 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3630 /* insert GTK representation */
3631 (*m_insertCallback
)(this, child
);
3634 void wxWindowGTK::Raise()
3636 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3638 if (!m_widget
->window
) return;
3640 gdk_window_raise( m_widget
->window
);
3643 void wxWindowGTK::Lower()
3645 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3647 if (!m_widget
->window
) return;
3649 gdk_window_lower( m_widget
->window
);
3652 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3654 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3656 if (cursor
== m_cursor
)
3660 wxapp_install_idle_handler();
3662 if (cursor
== wxNullCursor
)
3663 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3665 return wxWindowBase::SetCursor( cursor
);
3668 void wxWindowGTK::WarpPointer( int x
, int y
)
3670 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3672 // We provide this function ourselves as it is
3673 // missing in GDK (top of this file).
3675 GdkWindow
*window
= (GdkWindow
*) NULL
;
3677 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3679 window
= GetConnectWidget()->window
;
3682 gdk_window_warp_pointer( window
, x
, y
);
3686 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3688 if (!m_widget
) return;
3689 if (!m_widget
->window
) return;
3693 wxapp_install_idle_handler();
3695 wxRect
myRect(0,0,0,0);
3696 if (m_wxwindow
&& rect
)
3698 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3699 m_wxwindow
->allocation
.height
));
3700 myRect
.Intersect(*rect
);
3701 if (!myRect
.width
|| !myRect
.height
)
3702 // nothing to do, rectangle is empty
3707 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3711 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3712 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3716 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3717 m_clearRegion
.Clear();
3718 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3726 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3727 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3731 GdkRectangle gdk_rect
;
3732 gdk_rect
.x
= rect
->x
;
3733 gdk_rect
.y
= rect
->y
;
3734 gdk_rect
.width
= rect
->width
;
3735 gdk_rect
.height
= rect
->height
;
3736 gtk_widget_draw( m_widget
, &gdk_rect
);
3743 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3744 m_updateRegion
.Clear();
3745 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3749 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3757 GdkRectangle gdk_rect
;
3758 gdk_rect
.x
= rect
->x
;
3759 gdk_rect
.y
= rect
->y
;
3760 gdk_rect
.width
= rect
->width
;
3761 gdk_rect
.height
= rect
->height
;
3762 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3766 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3772 void wxWindowGTK::Update()
3777 void wxWindowGTK::GtkUpdate()
3780 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3781 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3783 if (!m_updateRegion
.IsEmpty())
3784 GtkSendPaintEvents();
3788 void wxWindowGTK::GtkSendPaintEvents()
3793 m_clearRegion
.Clear();
3795 m_updateRegion
.Clear();
3799 // Clip to paint region in wxClientDC
3800 m_clipPaintRegion
= TRUE
;
3803 // widget to draw on
3804 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3806 // later for GTK 2.0, too.
3807 if (GetThemeEnabled())
3809 // find ancestor from which to steal background
3810 wxWindow
*parent
= GetParent();
3811 while (parent
&& !parent
->IsTopLevel())
3812 parent
= parent
->GetParent();
3814 parent
= (wxWindow
*)this;
3816 wxRegionIterator
upd( m_updateRegion
);
3820 rect
.x
= upd
.GetX();
3821 rect
.y
= upd
.GetY();
3822 rect
.width
= upd
.GetWidth();
3823 rect
.height
= upd
.GetHeight();
3825 gtk_paint_flat_box( parent
->m_widget
->style
,
3842 wxWindowDC
dc( (wxWindow
*)this );
3843 dc
.SetClippingRegion( m_updateRegion
);
3845 wxEraseEvent
erase_event( GetId(), &dc
);
3846 erase_event
.SetEventObject( this );
3848 GetEventHandler()->ProcessEvent(erase_event
);
3851 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3853 wxWindowDC
dc( (wxWindow
*)this );
3854 if (m_clearRegion
.IsEmpty())
3855 dc
.SetClippingRegion( m_updateRegion
);
3857 dc
.SetClippingRegion( m_clearRegion
);
3859 wxEraseEvent
erase_event( GetId(), &dc
);
3860 erase_event
.SetEventObject( this );
3862 if (!GetEventHandler()->ProcessEvent(erase_event
))
3866 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3867 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3869 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3871 wxRegionIterator
upd( m_clearRegion
);
3874 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3875 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3879 m_clearRegion
.Clear();
3883 wxNcPaintEvent
nc_paint_event( GetId() );
3884 nc_paint_event
.SetEventObject( this );
3885 GetEventHandler()->ProcessEvent( nc_paint_event
);
3887 wxPaintEvent
paint_event( GetId() );
3888 paint_event
.SetEventObject( this );
3889 GetEventHandler()->ProcessEvent( paint_event
);
3891 m_clipPaintRegion
= FALSE
;
3893 #ifndef __WXUNIVERSAL__
3895 // The following code will result in all window-less widgets
3896 // being redrawn because the wxWindows class is allowed to
3897 // paint over the window-less widgets.
3899 GList
*children
= pizza
->children
;
3902 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3903 children
= children
->next
;
3905 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3906 GTK_WIDGET_DRAWABLE (child
->widget
))
3908 // Get intersection of widget area and update region
3909 wxRegion
region( m_updateRegion
);
3911 GdkEventExpose gdk_event
;
3912 gdk_event
.type
= GDK_EXPOSE
;
3913 gdk_event
.window
= pizza
->bin_window
;
3914 gdk_event
.count
= 0;
3916 wxRegionIterator
upd( m_updateRegion
);
3920 rect
.x
= upd
.GetX();
3921 rect
.y
= upd
.GetY();
3922 rect
.width
= upd
.GetWidth();
3923 rect
.height
= upd
.GetHeight();
3925 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3927 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3937 m_updateRegion
.Clear();
3940 void wxWindowGTK::ClearBackground()
3942 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3945 if (m_wxwindow
&& m_wxwindow
->window
)
3947 m_clearRegion
.Clear();
3948 wxSize
size( GetClientSize() );
3949 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3951 // Better do this in idle?
3958 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3960 wxWindowBase::DoSetToolTip(tip
);
3963 m_tooltip
->Apply( (wxWindow
*)this );
3966 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3968 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3970 #endif // wxUSE_TOOLTIPS
3972 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3974 GdkWindow
*window
= (GdkWindow
*) NULL
;
3976 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3978 window
= GetConnectWidget()->window
;
3982 // We need the pixel value e.g. for background clearing.
3983 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3987 // wxMSW doesn't clear the window here, either.
3988 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3994 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3996 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3998 if (!wxWindowBase::SetBackgroundColour(colour
))
4001 GdkWindow
*window
= (GdkWindow
*) NULL
;
4003 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4005 window
= GetConnectWidget()->window
;
4009 // indicate that a new style has been set
4010 // but it couldn't get applied as the
4011 // widget hasn't been realized yet.
4012 m_delayedBackgroundColour
= TRUE
;
4017 GtkSetBackgroundColour( colour
);
4023 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
4025 GdkWindow
*window
= (GdkWindow
*) NULL
;
4027 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4029 window
= GetConnectWidget()->window
;
4036 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4038 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4040 if (!wxWindowBase::SetForegroundColour(colour
))
4042 // don't leave if the GTK widget has just
4044 if (!m_delayedForegroundColour
) return FALSE
;
4047 GdkWindow
*window
= (GdkWindow
*) NULL
;
4049 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4051 window
= GetConnectWidget()->window
;
4055 // indicate that a new style has been set
4056 // but it couldn't get applied as the
4057 // widget hasn't been realized yet.
4058 m_delayedForegroundColour
= TRUE
;
4062 GtkSetForegroundColour( colour
);
4069 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4071 return gtk_widget_get_pango_context( m_widget
);
4074 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4077 m_x11Context
= pango_x_get_context( gdk_display
);
4079 return m_x11Context
;
4083 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4087 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4089 // FIXME: no more klass in 2.0
4091 remake
->klass
= m_widgetStyle
->klass
;
4094 gtk_style_unref( m_widgetStyle
);
4095 m_widgetStyle
= remake
;
4099 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4102 def
= gtk_widget_get_default_style();
4104 m_widgetStyle
= gtk_style_copy( def
);
4106 // FIXME: no more klass in 2.0
4108 m_widgetStyle
->klass
= def
->klass
;
4112 return m_widgetStyle
;
4115 void wxWindowGTK::SetWidgetStyle()
4117 #if DISABLE_STYLE_IF_BROKEN_THEME
4118 if (m_widget
->style
->engine_data
)
4120 static bool s_warningPrinted
= FALSE
;
4121 if (!s_warningPrinted
)
4123 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
4124 s_warningPrinted
= TRUE
;
4126 m_widgetStyle
= m_widget
->style
;
4131 GtkStyle
*style
= GetWidgetStyle();
4133 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
4136 pango_font_description_free( style
->font_desc
);
4137 style
->font_desc
= pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4139 gdk_font_unref( style
->font
);
4140 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4144 if (m_foregroundColour
.Ok())
4146 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4147 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4149 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4150 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4151 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4155 // Try to restore the gtk default style. This is still a little
4156 // oversimplified for what is probably really needed here for controls
4157 // other than buttons, but is better than not being able to (re)set a
4158 // control's foreground colour to *wxBLACK -- RL
4159 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4162 def
= gtk_widget_get_default_style();
4164 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4165 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4166 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4170 if (m_backgroundColour
.Ok())
4172 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4173 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4175 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4176 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4177 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4178 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4179 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4180 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4181 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4182 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4186 // Try to restore the gtk default style. This is still a little
4187 // oversimplified for what is probably really needed here for controls
4188 // other than buttons, but is better than not being able to (re)set a
4189 // control's background colour to default grey and means resetting a
4190 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4192 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4195 def
= gtk_widget_get_default_style();
4197 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4198 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4199 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4200 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4201 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4202 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4203 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4204 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4209 void wxWindowGTK::ApplyWidgetStyle()
4213 //-----------------------------------------------------------------------------
4214 // Pop-up menu stuff
4215 //-----------------------------------------------------------------------------
4217 #if wxUSE_MENUS_NATIVE
4220 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4222 *is_waiting
= FALSE
;
4225 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4227 menu
->SetInvokingWindow( win
);
4228 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4231 wxMenuItem
*menuitem
= node
->GetData();
4232 if (menuitem
->IsSubMenu())
4234 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4237 node
= node
->GetNext();
4241 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
4242 // wxPopupMenuPositionCallback()
4244 // should be safe even in the MT case as the user can hardly popup 2 menus
4245 // simultaneously, can he?
4246 static gint gs_pop_x
= 0;
4247 static gint gs_pop_y
= 0;
4249 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4252 gboolean
* WXUNUSED(whatever
),
4254 gpointer
WXUNUSED(user_data
) )
4256 // ensure that the menu appears entirely on screen
4258 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4260 wxSize sizeScreen
= wxGetDisplaySize();
4262 gint xmax
= sizeScreen
.x
- req
.width
,
4263 ymax
= sizeScreen
.y
- req
.height
;
4265 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
4266 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
4269 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4271 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4273 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
4275 SetInvokingWindow( menu
, this );
4281 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
4283 bool is_waiting
= TRUE
;
4285 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4287 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4288 (gpointer
)&is_waiting
);
4291 GTK_MENU(menu
->m_menu
),
4292 (GtkWidget
*) NULL
, // parent menu shell
4293 (GtkWidget
*) NULL
, // parent menu item
4294 wxPopupMenuPositionCallback
, // function to position it
4295 NULL
, // client data
4296 0, // button used to activate it
4298 gtk_get_current_event_time()
4300 gs_timeLastClick
// the time of activation
4306 gtk_main_iteration();
4312 #endif // wxUSE_MENUS_NATIVE
4314 #if wxUSE_DRAG_AND_DROP
4316 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4318 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4320 GtkWidget
*dnd_widget
= GetConnectWidget();
4322 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4324 if (m_dropTarget
) delete m_dropTarget
;
4325 m_dropTarget
= dropTarget
;
4327 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4330 #endif // wxUSE_DRAG_AND_DROP
4332 GtkWidget
* wxWindowGTK::GetConnectWidget()
4334 GtkWidget
*connect_widget
= m_widget
;
4335 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4337 return connect_widget
;
4340 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4343 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4345 return (window
== m_widget
->window
);
4348 bool wxWindowGTK::SetFont( const wxFont
&font
)
4350 if (!wxWindowBase::SetFont(font
) || !m_widget
)
4355 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4356 if ( sysbg
== m_backgroundColour
)
4358 m_backgroundColour
= wxNullColour
;
4360 m_backgroundColour
= sysbg
;
4370 void wxWindowGTK::DoCaptureMouse()
4372 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4374 GdkWindow
*window
= (GdkWindow
*) NULL
;
4376 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4378 window
= GetConnectWidget()->window
;
4380 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4382 wxCursor
* cursor
= & m_cursor
;
4384 cursor
= wxSTANDARD_CURSOR
;
4386 gdk_pointer_grab( window
, FALSE
,
4388 (GDK_BUTTON_PRESS_MASK
|
4389 GDK_BUTTON_RELEASE_MASK
|
4390 GDK_POINTER_MOTION_HINT_MASK
|
4391 GDK_POINTER_MOTION_MASK
),
4393 cursor
->GetCursor(),
4394 (guint32
)GDK_CURRENT_TIME
);
4395 g_captureWindow
= this;
4396 g_captureWindowHasMouse
= TRUE
;
4399 void wxWindowGTK::DoReleaseMouse()
4401 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4403 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4405 g_captureWindow
= (wxWindowGTK
*) NULL
;
4407 GdkWindow
*window
= (GdkWindow
*) NULL
;
4409 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4411 window
= GetConnectWidget()->window
;
4416 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4420 wxWindow
*wxWindowBase::GetCapture()
4422 return (wxWindow
*)g_captureWindow
;
4425 bool wxWindowGTK::IsRetained() const
4430 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4431 int range
, bool refresh
)
4433 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4435 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4437 m_hasScrolling
= TRUE
;
4439 if (orient
== wxHORIZONTAL
)
4441 float fpos
= (float)pos
;
4442 float frange
= (float)range
;
4443 float fthumb
= (float)thumbVisible
;
4444 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4445 if (fpos
< 0.0) fpos
= 0.0;
4447 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4448 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4450 SetScrollPos( orient
, pos
, refresh
);
4454 m_oldHorizontalPos
= fpos
;
4456 m_hAdjust
->lower
= 0.0;
4457 m_hAdjust
->upper
= frange
;
4458 m_hAdjust
->value
= fpos
;
4459 m_hAdjust
->step_increment
= 1.0;
4460 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4461 m_hAdjust
->page_size
= fthumb
;
4465 float fpos
= (float)pos
;
4466 float frange
= (float)range
;
4467 float fthumb
= (float)thumbVisible
;
4468 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4469 if (fpos
< 0.0) fpos
= 0.0;
4471 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4472 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4474 SetScrollPos( orient
, pos
, refresh
);
4478 m_oldVerticalPos
= fpos
;
4480 m_vAdjust
->lower
= 0.0;
4481 m_vAdjust
->upper
= frange
;
4482 m_vAdjust
->value
= fpos
;
4483 m_vAdjust
->step_increment
= 1.0;
4484 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4485 m_vAdjust
->page_size
= fthumb
;
4488 if (orient
== wxHORIZONTAL
)
4489 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4491 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4494 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4496 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4498 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4500 if (orient
== wxHORIZONTAL
)
4502 float fpos
= (float)pos
;
4503 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4504 if (fpos
< 0.0) fpos
= 0.0;
4505 m_oldHorizontalPos
= fpos
;
4507 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4508 m_hAdjust
->value
= fpos
;
4512 float fpos
= (float)pos
;
4513 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4514 if (fpos
< 0.0) fpos
= 0.0;
4515 m_oldVerticalPos
= fpos
;
4517 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4518 m_vAdjust
->value
= fpos
;
4521 if (m_wxwindow
->window
)
4523 if (orient
== wxHORIZONTAL
)
4525 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4526 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4528 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4530 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4531 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4535 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4536 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4538 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4540 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4541 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4546 int wxWindowGTK::GetScrollThumb( int orient
) const
4548 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4550 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4552 if (orient
== wxHORIZONTAL
)
4553 return (int)(m_hAdjust
->page_size
+0.5);
4555 return (int)(m_vAdjust
->page_size
+0.5);
4558 int wxWindowGTK::GetScrollPos( int orient
) const
4560 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4562 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4564 if (orient
== wxHORIZONTAL
)
4565 return (int)(m_hAdjust
->value
+0.5);
4567 return (int)(m_vAdjust
->value
+0.5);
4570 int wxWindowGTK::GetScrollRange( int orient
) const
4572 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4574 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4576 if (orient
== wxHORIZONTAL
)
4577 return (int)(m_hAdjust
->upper
+0.5);
4579 return (int)(m_vAdjust
->upper
+0.5);
4582 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4584 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4586 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4588 // No scrolling requested.
4589 if ((dx
== 0) && (dy
== 0)) return;
4592 if (!m_updateRegion
.IsEmpty())
4594 m_updateRegion
.Offset( dx
, dy
);
4598 GetClientSize( &cw
, &ch
);
4599 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4602 if (!m_clearRegion
.IsEmpty())
4604 m_clearRegion
.Offset( dx
, dy
);
4608 GetClientSize( &cw
, &ch
);
4609 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4613 m_clipPaintRegion
= TRUE
;
4615 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4617 m_clipPaintRegion
= FALSE
;
4621 // Find the wxWindow at the current mouse position, also returning the mouse
4623 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4625 pt
= wxGetMousePosition();
4626 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4630 // Get the current mouse position.
4631 wxPoint
wxGetMousePosition()
4633 /* This crashes when used within wxHelpContext,
4634 so we have to use the X-specific implementation below.
4636 GdkModifierType *mask;
4637 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4639 return wxPoint(x, y);
4643 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4645 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4646 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4647 Window rootReturn
, childReturn
;
4648 int rootX
, rootY
, winX
, winY
;
4649 unsigned int maskReturn
;
4651 XQueryPointer (display
,
4655 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4656 return wxPoint(rootX
, rootY
);
4660 // ----------------------------------------------------------------------------
4662 // ----------------------------------------------------------------------------
4664 class wxWinModule
: public wxModule
4671 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4674 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4676 bool wxWinModule::OnInit()
4678 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4679 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4684 void wxWinModule::OnExit()
4687 gdk_gc_unref( g_eraseGC
);