1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "window.h"
16 #define XWarpPointer XWARPPOINTER
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
24 #include "wx/layout.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28 #include "wx/module.h"
30 #if wxUSE_DRAG_AND_DROP
35 #include "wx/tooltip.h"
43 #include "wx/textctrl.h"
47 #include "wx/statusbr.h"
49 #include "wx/settings.h"
51 #include "wx/fontutil.h"
54 #include "wx/thread.h"
60 #include "wx/gtk/private.h"
61 #include <gdk/gdkprivate.h>
62 #include <gdk/gdkkeysyms.h>
66 #include <gtk/gtkprivate.h>
68 #include "wx/gtk/win_gtk.h"
71 #include <pango/pangox.h>
75 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
77 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
87 extern GtkContainerClass
*pizza_parent_class
;
90 //-----------------------------------------------------------------------------
91 // documentation on internals
92 //-----------------------------------------------------------------------------
95 I have been asked several times about writing some documentation about
96 the GTK port of wxWindows, especially its internal structures. Obviously,
97 you cannot understand wxGTK without knowing a little about the GTK, but
98 some more information about what the wxWindow, which is the base class
99 for all other window classes, does seems required as well.
103 What does wxWindow do? It contains the common interface for the following
104 jobs of its descendants:
106 1) Define the rudimentary behaviour common to all window classes, such as
107 resizing, intercepting user input (so as to make it possible to use these
108 events for special purposes in a derived class), window names etc.
110 2) Provide the possibility to contain and manage children, if the derived
111 class is allowed to contain children, which holds true for those window
112 classes which do not display a native GTK widget. To name them, these
113 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
114 work classes are a special case and are handled a bit differently from
115 the rest. The same holds true for the wxNotebook class.
117 3) Provide the possibility to draw into a client area of a window. This,
118 too, only holds true for classes that do not display a native GTK widget
121 4) Provide the entire mechanism for scrolling widgets. This actual inter-
122 face for this is usually in wxScrolledWindow, but the GTK implementation
125 5) A multitude of helper or extra methods for special purposes, such as
126 Drag'n'Drop, managing validators etc.
128 6) Display a border (sunken, raised, simple or none).
130 Normally one might expect, that one wxWindows window would always correspond
131 to one GTK widget. Under GTK, there is no such allround widget that has all
132 the functionality. Moreover, the GTK defines a client area as a different
133 widget from the actual widget you are handling. Last but not least some
134 special classes (e.g. wxFrame) handle different categories of widgets and
135 still have the possibility to draw something in the client area.
136 It was therefore required to write a special purpose GTK widget, that would
137 represent a client area in the sense of wxWindows capable to do the jobs
138 2), 3) and 4). I have written this class and it resides in win_gtk.c of
141 All windows must have a widget, with which they interact with other under-
142 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
143 thw wxWindow class has a member variable called m_widget which holds a
144 pointer to this widget. When the window class represents a GTK native widget,
145 this is (in most cases) the only GTK widget the class manages. E.g. the
146 wxStatitText class handles only a GtkLabel widget a pointer to which you
147 can find in m_widget (defined in wxWindow)
149 When the class has a client area for drawing into and for containing children
150 it has to handle the client area widget (of the type GtkPizza, defined in
151 win_gtk.c), but there could be any number of widgets, handled by a class
152 The common rule for all windows is only, that the widget that interacts with
153 the rest of GTK must be referenced in m_widget and all other widgets must be
154 children of this widget on the GTK level. The top-most widget, which also
155 represents the client area, must be in the m_wxwindow field and must be of
158 As I said, the window classes that display a GTK native widget only have
159 one widget, so in the case of e.g. the wxButton class m_widget holds a
160 pointer to a GtkButton widget. But windows with client areas (for drawing
161 and children) have a m_widget field that is a pointer to a GtkScrolled-
162 Window and a m_wxwindow field that is pointer to a GtkPizza and this
163 one is (in the GTK sense) a child of the GtkScrolledWindow.
165 If the m_wxwindow field is set, then all input to this widget is inter-
166 cepted and sent to the wxWindows class. If not, all input to the widget
167 that gets pointed to by m_widget gets intercepted and sent to the class.
171 The design of scrolling in wxWindows is markedly different from that offered
172 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
173 clicking on a scrollbar belonging to scrolled window will inevitably move
174 the window. In wxWindows, the scrollbar will only emit an event, send this
175 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
176 which actually moves the window and its subchildren. Note that GtkPizza
177 memorizes how much it has been scrolled but that wxWindows forgets this
178 so that the two coordinates systems have to be kept in synch. This is done
179 in various places using the pizza->xoffset and pizza->yoffset values.
183 Singularily the most broken code in GTK is the code that is supposes to
184 inform subwindows (child windows) about new positions. Very often, duplicate
185 events are sent without changes in size or position, equally often no
186 events are sent at all (All this is due to a bug in the GtkContainer code
187 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
188 GTK's own system and it simply waits for size events for toplevel windows
189 and then iterates down the respective size events to all window. This has
190 the disadvantage, that windows might get size events before the GTK widget
191 actually has the reported size. This doesn't normally pose any problem, but
192 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
193 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
194 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
195 window that is used for OpenGl output really has that size (as reported by
200 If someone at some point of time feels the immense desire to have a look at,
201 change or attempt to optimse the Refresh() logic, this person will need an
202 intimate understanding of what a "draw" and what an "expose" events are and
203 what there are used for, in particular when used in connection with GTK's
204 own windowless widgets. Beware.
208 Cursors, too, have been a constant source of pleasure. The main difficulty
209 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
210 for the parent. To prevent this from doing too much harm, I use idle time
211 to set the cursor over and over again, starting from the toplevel windows
212 and ending with the youngest generation (speaking of parent and child windows).
213 Also don't forget that cursors (like much else) are connected to GdkWindows,
214 not GtkWidgets and that the "window" field of a GtkWidget might very well
215 point to the GdkWindow of the parent widget (-> "window less widget") and
216 that the two obviously have very different meanings.
220 //-----------------------------------------------------------------------------
222 //-----------------------------------------------------------------------------
224 extern wxList wxPendingDelete
;
225 extern bool g_blockEventsOnDrag
;
226 extern bool g_blockEventsOnScroll
;
227 extern wxCursor g_globalCursor
;
229 static GdkGC
*g_eraseGC
= NULL
;
231 // mouse capture state: the window which has it and if the mouse is currently
233 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
234 static bool g_captureWindowHasMouse
= FALSE
;
236 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
238 // the last window which had the focus - this is normally never NULL (except
239 // if we never had focus at all) as even when g_focusWindow is NULL it still
240 // keeps its previous value
241 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
243 // the frame that is currently active (i.e. its child has focus). It is
244 // used to generate wxActivateEvents
245 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
246 static bool g_activeFrameLostFocus
= FALSE
;
248 // If a window get the focus set but has not been realized
249 // yet, defer setting the focus to idle time.
250 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
252 // if we detect that the app has got/lost the focus, we set this variable to
253 // either TRUE or FALSE and an activate event will be sent during the next
254 // OnIdle() call and it is reset to -1: this value means that we shouldn't
255 // send any activate events at all
256 static int g_sendActivateEvent
= -1;
258 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
259 the last click here */
260 static guint32 gs_timeLastClick
= 0;
262 extern bool g_mainThreadLocked
;
264 //-----------------------------------------------------------------------------
266 //-----------------------------------------------------------------------------
269 #define DISABLE_STYLE_IF_BROKEN_THEME 0
275 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
277 # define DEBUG_MAIN_THREAD
280 #define DEBUG_MAIN_THREAD
283 // the trace mask used for the focus debugging messages
284 #define TRACE_FOCUS _T("focus")
286 //-----------------------------------------------------------------------------
287 // missing gdk functions
288 //-----------------------------------------------------------------------------
291 gdk_window_warp_pointer (GdkWindow
*window
,
296 GdkWindowPrivate
*priv
;
300 window
= GDK_ROOT_PARENT();
303 if (!GDK_WINDOW_DESTROYED(window
))
305 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
306 None
, /* not source window -> move from anywhere */
307 GDK_WINDOW_XID(window
), /* dest window */
308 0, 0, 0, 0, /* not source window -> move from anywhere */
312 priv
= (GdkWindowPrivate
*) window
;
314 if (!priv
->destroyed
)
316 XWarpPointer (priv
->xdisplay
,
317 None
, /* not source window -> move from anywhere */
318 priv
->xwindow
, /* dest window */
319 0, 0, 0, 0, /* not source window -> move from anywhere */
325 //-----------------------------------------------------------------------------
327 //-----------------------------------------------------------------------------
329 extern void wxapp_install_idle_handler();
330 extern bool g_isIdle
;
332 //-----------------------------------------------------------------------------
333 // local code (see below)
334 //-----------------------------------------------------------------------------
336 // returns the child of win which currently has focus or NULL if not found
338 // Note: can't be static, needed by textctrl.cpp.
339 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
341 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
343 return (wxWindow
*)NULL
;
345 if ( winFocus
== win
)
346 return (wxWindow
*)win
;
348 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
350 node
= node
->GetNext() )
352 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
357 return (wxWindow
*)NULL
;
360 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
362 // wxUniversal widgets draw the borders and scrollbars themselves
363 #ifndef __WXUNIVERSAL__
370 if (win
->m_hasScrolling
)
372 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
374 GtkRequisition vscroll_req
;
375 vscroll_req
.width
= 2;
376 vscroll_req
.height
= 2;
377 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
378 (scroll_window
->vscrollbar
, &vscroll_req
);
380 GtkRequisition hscroll_req
;
381 hscroll_req
.width
= 2;
382 hscroll_req
.height
= 2;
383 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
384 (scroll_window
->hscrollbar
, &hscroll_req
);
386 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
388 if (scroll_window
->vscrollbar_visible
)
390 dw
+= vscroll_req
.width
;
391 dw
+= scroll_class
->scrollbar_spacing
;
394 if (scroll_window
->hscrollbar_visible
)
396 dh
+= hscroll_req
.height
;
397 dh
+= scroll_class
->scrollbar_spacing
;
403 if (GTK_WIDGET_NO_WINDOW (widget
))
405 dx
+= widget
->allocation
.x
;
406 dy
+= widget
->allocation
.y
;
409 if (win
->HasFlag(wxRAISED_BORDER
))
411 gtk_draw_shadow( widget
->style
,
416 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
420 if (win
->HasFlag(wxSUNKEN_BORDER
))
422 gtk_draw_shadow( widget
->style
,
427 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
431 if (win
->HasFlag(wxSIMPLE_BORDER
))
434 gc
= gdk_gc_new( widget
->window
);
435 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
436 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
438 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
442 #endif // __WXUNIVERSAL__
445 //-----------------------------------------------------------------------------
446 // "expose_event" of m_widget
447 //-----------------------------------------------------------------------------
449 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
451 if (gdk_event
->count
> 0) return FALSE
;
453 draw_frame( widget
, win
);
457 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
463 //-----------------------------------------------------------------------------
464 // "draw" of m_widget
465 //-----------------------------------------------------------------------------
469 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
471 draw_frame( widget
, win
);
476 //-----------------------------------------------------------------------------
477 // "size_request" of m_widget
478 //-----------------------------------------------------------------------------
480 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
483 win
->GetSize( &w
, &h
);
487 requisition
->height
= h
;
488 requisition
->width
= w
;
491 //-----------------------------------------------------------------------------
492 // "expose_event" of m_wxwindow
493 //-----------------------------------------------------------------------------
495 static int gtk_window_expose_callback( GtkWidget
*widget
,
496 GdkEventExpose
*gdk_event
,
502 wxapp_install_idle_handler();
505 // This callback gets called in drawing-idle time under
506 // GTK 2.0, so we don't need to defer anything to idle
509 GtkPizza
*pizza
= GTK_PIZZA( widget
);
510 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
515 wxPrintf( wxT("OnExpose from ") );
516 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
517 wxPrintf( win
->GetClassInfo()->GetClassName() );
518 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
519 (int)gdk_event
->area
.y
,
520 (int)gdk_event
->area
.width
,
521 (int)gdk_event
->area
.height
);
525 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
527 win
->GtkSendPaintEvents();
530 // Let parent window draw window less widgets
531 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
533 // This gets called immediately after an expose event
534 // under GTK 1.2 so we collect the calls and wait for
535 // the idle handler to pick things up.
537 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
539 gdk_event
->area
.width
,
540 gdk_event
->area
.height
);
541 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
543 gdk_event
->area
.width
,
544 gdk_event
->area
.height
);
546 // Actual redrawing takes place in idle time.
553 //-----------------------------------------------------------------------------
554 // "event" of m_wxwindow
555 //-----------------------------------------------------------------------------
557 // GTK thinks it is clever and filters out a certain amount of "unneeded"
558 // expose events. We need them, of course, so we override the main event
559 // procedure in GtkWidget by giving our own handler for all system events.
560 // There, we look for expose events ourselves whereas all other events are
563 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
564 GdkEventExpose
*event
,
567 if (event
->type
== GDK_EXPOSE
)
569 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
576 //-----------------------------------------------------------------------------
577 // "draw" of m_wxwindow
578 //-----------------------------------------------------------------------------
582 // This callback is a complete replacement of the gtk_pizza_draw() function,
583 // which is disabled.
585 static void gtk_window_draw_callback( GtkWidget
*widget
,
592 wxapp_install_idle_handler();
594 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
595 // there are no child windows.
596 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
597 (win
->GetChildren().GetCount() == 0))
605 wxPrintf( wxT("OnDraw from ") );
606 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
607 wxPrintf( win
->GetClassInfo()->GetClassName() );
608 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
615 #ifndef __WXUNIVERSAL__
616 GtkPizza
*pizza
= GTK_PIZZA (widget
);
618 if (win
->GetThemeEnabled())
620 wxWindow
*parent
= win
->GetParent();
621 while (parent
&& !parent
->IsTopLevel())
622 parent
= parent
->GetParent();
626 gtk_paint_flat_box (parent
->m_widget
->style
,
637 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
638 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
640 // Update immediately, not in idle time.
643 #ifndef __WXUNIVERSAL__
644 // Redraw child widgets
645 GList
*children
= pizza
->children
;
648 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
649 children
= children
->next
;
651 GdkRectangle child_area
;
652 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
654 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
662 //-----------------------------------------------------------------------------
663 // "key_press_event" from any window
664 //-----------------------------------------------------------------------------
666 // set WXTRACE to this to see the key event codes on the console
667 #define TRACE_KEYS _T("keyevent")
669 // translates an X key symbol to WXK_XXX value
671 // if isChar is true it means that the value returned will be used for EVT_CHAR
672 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
673 // for example, while if it is false it means that the value is going to be
674 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
676 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
682 // Shift, Control and Alt don't generate the CHAR events at all
685 key_code
= isChar
? 0 : WXK_SHIFT
;
689 key_code
= isChar
? 0 : WXK_CONTROL
;
697 key_code
= isChar
? 0 : WXK_ALT
;
700 // neither do the toggle modifies
701 case GDK_Scroll_Lock
:
702 key_code
= isChar
? 0 : WXK_SCROLL
;
706 key_code
= isChar
? 0 : WXK_CAPITAL
;
710 key_code
= isChar
? 0 : WXK_NUMLOCK
;
714 // various other special keys
727 case GDK_ISO_Left_Tab
:
734 key_code
= WXK_RETURN
;
738 key_code
= WXK_CLEAR
;
742 key_code
= WXK_PAUSE
;
746 key_code
= WXK_SELECT
;
750 key_code
= WXK_PRINT
;
754 key_code
= WXK_EXECUTE
;
758 key_code
= WXK_ESCAPE
;
761 // cursor and other extended keyboard keys
763 key_code
= WXK_DELETE
;
779 key_code
= WXK_RIGHT
;
786 case GDK_Prior
: // == GDK_Page_Up
787 key_code
= WXK_PRIOR
;
790 case GDK_Next
: // == GDK_Page_Down
803 key_code
= WXK_INSERT
;
818 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
822 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
826 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
830 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
834 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
838 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
842 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
846 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
850 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
854 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
858 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
862 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
866 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
869 case GDK_KP_Prior
: // == GDK_KP_Page_Up
870 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
873 case GDK_KP_Next
: // == GDK_KP_Page_Down
874 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
878 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
882 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
886 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
890 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
894 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
897 case GDK_KP_Multiply
:
898 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
902 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
905 case GDK_KP_Separator
:
906 // FIXME: what is this?
907 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
910 case GDK_KP_Subtract
:
911 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
915 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
919 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
936 key_code
= WXK_F1
+ keysym
- GDK_F1
;
946 static inline bool wxIsAsciiKeysym(KeySym ks
)
952 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
954 GdkEventKey
*gdk_event
)
956 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
957 // but only event->keyval which is quite useless to us, so remember
958 // the last character from GDK_KEY_PRESS and reuse it as last resort
960 // NB: should be MT-safe as we're always called from the main thread only
965 } s_lastKeyPress
= { 0, 0 };
967 KeySym keysym
= gdk_event
->keyval
;
969 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
970 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
974 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
978 // do we have the translation or is it a plain ASCII character?
979 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
981 // we should use keysym if it is ASCII as X does some translations
982 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
983 // which we don't want here (but which we do use for OnChar())
984 if ( !wxIsAsciiKeysym(keysym
) )
986 keysym
= (KeySym
)gdk_event
->string
[0];
989 // we want to always get the same key code when the same key is
990 // pressed regardless of the state of the modifies, i.e. on a
991 // standard US keyboard pressing '5' or '%' ('5' key with
992 // Shift) should result in the same key code in OnKeyDown():
993 // '5' (although OnChar() will get either '5' or '%').
995 // to do it we first translate keysym to keycode (== scan code)
996 // and then back but always using the lower register
997 Display
*dpy
= (Display
*)wxGetDisplay();
998 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1000 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1002 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1004 // use the normalized, i.e. lower register, keysym if we've
1006 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1008 // as explained above, we want to have lower register key codes
1009 // normally but for the letter keys we want to have the upper ones
1011 // NB: don't use XConvertCase() here, we want to do it for letters
1013 key_code
= toupper(key_code
);
1015 else // non ASCII key, what to do?
1017 // by default, ignore it
1020 // but if we have cached information from the last KEY_PRESS
1021 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1024 if ( keysym
== s_lastKeyPress
.keysym
)
1026 key_code
= s_lastKeyPress
.keycode
;
1031 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1033 // remember it to be reused for KEY_UP event later
1034 s_lastKeyPress
.keysym
= keysym
;
1035 s_lastKeyPress
.keycode
= key_code
;
1039 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1041 // sending unknown key events doesn't really make sense
1045 // now fill all the other fields
1048 GdkModifierType state
;
1049 if (gdk_event
->window
)
1050 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1052 event
.SetTimestamp( gdk_event
->time
);
1053 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1054 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1055 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1056 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1057 event
.m_keyCode
= key_code
;
1058 event
.m_scanCode
= gdk_event
->keyval
;
1059 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1060 event
.m_rawFlags
= 0;
1063 event
.SetEventObject( win
);
1069 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1070 GdkEventKey
*gdk_event
,
1076 wxapp_install_idle_handler();
1080 if (g_blockEventsOnDrag
)
1084 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1085 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1087 // unknown key pressed, ignore (the event would be useless anyhow)
1091 // Emit KEY_DOWN event
1092 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1097 wxWindowGTK
*ancestor
= win
;
1100 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1103 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1104 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1107 if (ancestor
->IsTopLevel())
1109 ancestor
= ancestor
->GetParent();
1112 #endif // wxUSE_ACCEL
1114 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1115 // will only be sent if it is not in an accelerator table.
1118 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1119 KeySym keysym
= gdk_event
->keyval
;
1120 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1123 if ( gdk_event
->length
== 1 )
1125 key_code
= (unsigned char)gdk_event
->string
[0];
1127 else if ( wxIsAsciiKeysym(keysym
) )
1130 key_code
= (unsigned char)keysym
;
1136 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1138 event
.m_keyCode
= key_code
;
1140 // Implement OnCharHook by checking ancesteror top level windows
1141 wxWindow
*parent
= win
;
1142 while (parent
&& !parent
->IsTopLevel())
1143 parent
= parent
->GetParent();
1146 event
.SetEventType( wxEVT_CHAR_HOOK
);
1147 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1152 event
.SetEventType(wxEVT_CHAR
);
1153 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1158 // win is a control: tab can be propagated up
1160 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1161 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1162 // have this style, yet choose not to process this particular TAB in which
1163 // case TAB must still work as a navigational character
1165 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1167 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1169 wxNavigationKeyEvent new_event
;
1170 new_event
.SetEventObject( win
->GetParent() );
1171 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1172 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1173 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1174 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1175 new_event
.SetCurrentFocus( win
);
1176 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1179 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1181 (gdk_event
->keyval
== GDK_Escape
) )
1183 // however only do it if we have a Cancel button in the dialog,
1184 // otherwise the user code may get confused by the events from a
1185 // non-existing button and, worse, a wxButton might get button event
1186 // from another button which is not really expected
1187 wxWindow
*winForCancel
= win
,
1189 while ( winForCancel
)
1191 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1194 // found a cancel button
1198 if ( winForCancel
->IsTopLevel() )
1200 // no need to look further
1204 // maybe our parent has a cancel button?
1205 winForCancel
= winForCancel
->GetParent();
1210 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1211 event
.SetEventObject(btnCancel
);
1212 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1218 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1227 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1228 GdkEventKey
*gdk_event
,
1232 wxapp_install_idle_handler();
1236 if (g_blockEventsOnDrag
)
1240 bool dont_use_IM
= FALSE
;
1242 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1243 long keycode
= wxTranslateKeySymToWXKey( gdk_event
->keyval
, FALSE
);
1246 // We were able to decode the key press without
1247 // any input method, so don't use it.
1250 // now fill all the other fields
1253 GdkModifierType state
;
1254 if (gdk_event
->window
)
1255 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1257 event
.SetTimestamp( gdk_event
->time
);
1258 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1259 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1260 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1261 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1262 event
.m_keyCode
= keycode
;
1263 event
.m_scanCode
= gdk_event
->keyval
;
1264 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1265 event
.m_rawFlags
= 0;
1268 event
.SetEventObject( win
);
1270 // send key down event
1271 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1275 // Implement OnCharHook by checking ancesteror top level windows
1276 wxWindow
*parent
= win
;
1277 while (parent
&& !parent
->IsTopLevel())
1278 parent
= parent
->GetParent();
1281 event
.SetEventType( wxEVT_CHAR_HOOK
);
1282 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1287 event
.SetEventType(wxEVT_CHAR
);
1288 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1292 // win is a control: tab can be propagated up
1294 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1295 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1297 wxNavigationKeyEvent new_event
;
1298 new_event
.SetEventObject( win
->GetParent() );
1299 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1300 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1301 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1302 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1303 new_event
.SetCurrentFocus( win
);
1304 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1308 (gdk_event
->keyval
== GDK_Escape
) )
1310 wxWindow
*winForCancel
= win
, *btnCancel
= NULL
;
1311 while ( winForCancel
)
1313 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1314 if ( btnCancel
) break;
1316 if ( winForCancel
->IsTopLevel() ) break;
1318 winForCancel
= winForCancel
->GetParent();
1323 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1324 event
.SetEventObject(btnCancel
);
1325 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1332 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1336 if (!dont_use_IM
&& win
->m_imContext
)
1338 // In GTK 2.0, we need to hand over the key
1339 // event to an input method and the IM will
1340 // emit a "commit" event containing the
1341 // actual utf8 character.
1342 gtk_im_context_filter_keypress ( (GtkIMContext
*) win
->m_imContext
, gdk_event
);
1350 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1356 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1359 event
.m_uniChar
= g_utf8_get_char( str
);
1361 // Backward compatible for ISO-8859
1362 if (event
.m_uniChar
< 256)
1363 event
.m_keyCode
= event
.m_uniChar
;
1365 gunichar uniChar
= g_utf8_get_char( str
);
1366 // We cannot handle Unicode in non-Unicode mode
1367 if (uniChar
> 255) return;
1369 event
.m_keyCode
= uniChar
;
1374 // Implement OnCharHook by checking ancesteror top level windows
1375 wxWindow
*parent
= window
;
1376 while (parent
&& !parent
->IsTopLevel())
1377 parent
= parent
->GetParent();
1380 event
.SetEventType( wxEVT_CHAR_HOOK
);
1381 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1386 event
.SetEventType(wxEVT_CHAR
);
1387 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1394 //-----------------------------------------------------------------------------
1395 // "key_release_event" from any window
1396 //-----------------------------------------------------------------------------
1398 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1399 GdkEventKey
*gdk_event
,
1405 wxapp_install_idle_handler();
1410 if (g_blockEventsOnDrag
)
1413 wxKeyEvent
event( wxEVT_KEY_UP
);
1414 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1416 // unknown key pressed, ignore (the event would be useless anyhow
1420 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1423 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1427 // ============================================================================
1429 // ============================================================================
1431 // ----------------------------------------------------------------------------
1432 // mouse event processing helpers
1433 // ----------------------------------------------------------------------------
1435 // init wxMouseEvent with the info from gdk_event
1437 // NB: this has to be a macro as gdk_event type is different for different
1438 // events we're used with
1439 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1440 /* wxMouseEvent& */ event, \
1441 /* GdkEventXXX * */ gdk_event) \
1443 event.SetTimestamp( gdk_event->time ); \
1444 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1445 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1446 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1447 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1448 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1449 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1450 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1451 if (event.GetEventType()==wxEVT_MOUSEWHEEL) \
1453 if (((GdkEventButton*)gdk_event)->button == 4) \
1454 event.m_wheelRotation = 120; \
1455 else if (((GdkEventButton*)gdk_event)->button == 5) \
1456 event.m_wheelRotation = -120; \
1459 wxPoint pt = win->GetClientAreaOrigin(); \
1460 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1461 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1463 event.SetEventObject( win ); \
1464 event.SetId( win->GetId() ); \
1465 event.SetTimestamp( gdk_event->time ); \
1468 static void AdjustEventButtonState(wxMouseEvent& event)
1470 // GDK reports the old state of the button for a button press event, but
1471 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1472 // for a LEFT_DOWN event, not FALSE, so we will invert
1473 // left/right/middleDown for the corresponding click events
1475 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1476 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1477 (event
.GetEventType() == wxEVT_LEFT_UP
))
1479 event
.m_leftDown
= !event
.m_leftDown
;
1483 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1484 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1485 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1487 event
.m_middleDown
= !event
.m_middleDown
;
1491 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1492 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1493 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1495 event
.m_rightDown
= !event
.m_rightDown
;
1500 // find the window to send the mouse event too
1502 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1507 if (win
->m_wxwindow
)
1509 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1510 xx
+= pizza
->xoffset
;
1511 yy
+= pizza
->yoffset
;
1514 wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
1517 wxWindowGTK
*child
= node
->GetData();
1519 node
= node
->GetNext();
1520 if (!child
->IsShown())
1523 if (child
->IsTransparentForMouse())
1525 // wxStaticBox is transparent in the box itself
1526 int xx1
= child
->m_x
;
1527 int yy1
= child
->m_y
;
1528 int xx2
= child
->m_x
+ child
->m_width
;
1529 int yy2
= child
->m_x
+ child
->m_height
;
1532 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1534 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1536 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1538 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1549 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1550 (child
->m_x
<= xx
) &&
1551 (child
->m_y
<= yy
) &&
1552 (child
->m_x
+child
->m_width
>= xx
) &&
1553 (child
->m_y
+child
->m_height
>= yy
))
1566 //-----------------------------------------------------------------------------
1567 // "button_press_event"
1568 //-----------------------------------------------------------------------------
1570 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1571 GdkEventButton
*gdk_event
,
1577 wxapp_install_idle_handler();
1580 wxPrintf( wxT("1) OnButtonPress from ") );
1581 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1582 wxPrintf( win->GetClassInfo()->GetClassName() );
1583 wxPrintf( wxT(".\n") );
1585 if (!win
->m_hasVMT
) return FALSE
;
1586 if (g_blockEventsOnDrag
) return TRUE
;
1587 if (g_blockEventsOnScroll
) return TRUE
;
1589 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1591 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1593 gtk_widget_grab_focus( win
->m_wxwindow
);
1595 wxPrintf( wxT("GrabFocus from ") );
1596 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1597 wxPrintf( win->GetClassInfo()->GetClassName() );
1598 wxPrintf( wxT(".\n") );
1602 // GDK sends surplus button down event
1603 // before a double click event. We
1604 // need to filter these out.
1605 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1607 GdkEvent
*peek_event
= gdk_event_peek();
1610 if (peek_event
->type
== GDK_2BUTTON_PRESS
)
1612 gdk_event_free( peek_event
);
1617 gdk_event_free( peek_event
);
1622 wxEventType event_type
= wxEVT_NULL
;
1624 if (gdk_event
->button
== 1)
1626 switch (gdk_event
->type
)
1628 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1629 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1633 else if (gdk_event
->button
== 2)
1635 switch (gdk_event
->type
)
1637 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1638 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1642 else if (gdk_event
->button
== 3)
1644 switch (gdk_event
->type
)
1646 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1647 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1651 else if (gdk_event
->button
== 4)
1653 switch (gdk_event
->type
)
1655 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1659 else if (gdk_event
->button
== 5)
1661 switch (gdk_event
->type
)
1663 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1668 if ( event_type
== wxEVT_NULL
)
1670 // unknown mouse button or click type
1674 wxMouseEvent
event( event_type
);
1675 InitMouseEvent( win
, event
, gdk_event
);
1677 AdjustEventButtonState(event
);
1679 // wxListBox actually get mouse events from the item, so we need to give it
1680 // a chance to correct this
1681 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1683 // find the correct window to send the event too: it may be a different one
1684 // from the one which got it at GTK+ level because some control don't have
1685 // their own X window and thus cannot get any events.
1686 if ( !g_captureWindow
)
1687 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1689 gs_timeLastClick
= gdk_event
->time
;
1692 wxPrintf( wxT("2) OnButtonPress from ") );
1693 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1694 wxPrintf( win->GetClassInfo()->GetClassName() );
1695 wxPrintf( wxT(".\n") );
1699 if (event_type
== wxEVT_LEFT_DCLICK
)
1701 // GTK 1.2 crashes when intercepting double
1702 // click events from both wxSpinButton and
1704 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1706 // Just disable this event for now.
1712 if (win
->GetEventHandler()->ProcessEvent( event
))
1714 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1721 //-----------------------------------------------------------------------------
1722 // "button_release_event"
1723 //-----------------------------------------------------------------------------
1725 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1726 GdkEventButton
*gdk_event
,
1732 wxapp_install_idle_handler();
1734 if (!win
->m_hasVMT
) return FALSE
;
1735 if (g_blockEventsOnDrag
) return FALSE
;
1736 if (g_blockEventsOnScroll
) return FALSE
;
1738 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1740 wxEventType event_type
= wxEVT_NULL
;
1742 switch (gdk_event
->button
)
1745 event_type
= wxEVT_LEFT_UP
;
1749 event_type
= wxEVT_MIDDLE_UP
;
1753 event_type
= wxEVT_RIGHT_UP
;
1757 // unknwon button, don't process
1761 wxMouseEvent
event( event_type
);
1762 InitMouseEvent( win
, event
, gdk_event
);
1764 AdjustEventButtonState(event
);
1766 // same wxListBox hack as above
1767 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1769 if ( event_type
== wxEVT_RIGHT_UP
)
1771 // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
1774 // (a) it's a command event and so is propagated to the parent
1775 // (b) under MSW it can be generated from kbd too
1776 // (c) it uses screen coords (because of (a))
1777 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1779 win
->ClientToScreen(event
.GetPosition()));
1780 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1783 if ( !g_captureWindow
)
1784 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1786 if (win
->GetEventHandler()->ProcessEvent( event
))
1788 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1795 //-----------------------------------------------------------------------------
1796 // "motion_notify_event"
1797 //-----------------------------------------------------------------------------
1799 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1800 GdkEventMotion
*gdk_event
,
1806 wxapp_install_idle_handler();
1808 if (!win
->m_hasVMT
) return FALSE
;
1809 if (g_blockEventsOnDrag
) return FALSE
;
1810 if (g_blockEventsOnScroll
) return FALSE
;
1812 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1814 if (gdk_event
->is_hint
)
1818 GdkModifierType state
;
1819 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1825 printf( "OnMotion from " );
1826 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1827 printf( win->GetClassInfo()->GetClassName() );
1831 wxMouseEvent
event( wxEVT_MOTION
);
1832 InitMouseEvent(win
, event
, gdk_event
);
1834 if ( g_captureWindow
)
1836 // synthetize a mouse enter or leave event if needed
1837 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1838 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1839 if ( hasMouse
!= g_captureWindowHasMouse
)
1841 // the mouse changed window
1842 g_captureWindowHasMouse
= hasMouse
;
1844 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1845 : wxEVT_LEAVE_WINDOW
);
1846 InitMouseEvent(win
, event
, gdk_event
);
1847 event
.SetEventObject(win
);
1848 win
->GetEventHandler()->ProcessEvent(event
);
1853 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1856 if (win
->GetEventHandler()->ProcessEvent( event
))
1858 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1865 //-----------------------------------------------------------------------------
1867 //-----------------------------------------------------------------------------
1869 // send the wxChildFocusEvent and wxFocusEvent, common code of
1870 // gtk_window_focus_in_callback() and SetFocus()
1871 static bool DoSendFocusEvents(wxWindow
*win
)
1873 // Notify the parent keeping track of focus for the kbd navigation
1874 // purposes that we got it.
1875 wxChildFocusEvent
eventChildFocus(win
);
1876 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1878 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1879 eventFocus
.SetEventObject(win
);
1881 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1884 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1885 GdkEvent
*WXUNUSED(event
),
1891 wxapp_install_idle_handler();
1893 if (!win
->m_hasVMT
) return FALSE
;
1894 if (g_blockEventsOnDrag
) return FALSE
;
1896 switch ( g_sendActivateEvent
)
1899 // we've got focus from outside, synthetize wxActivateEvent
1900 g_sendActivateEvent
= 1;
1904 // another our window just lost focus, it was already ours before
1905 // - don't send any wxActivateEvent
1906 g_sendActivateEvent
= -1;
1911 g_focusWindow
= win
;
1913 wxLogTrace(TRACE_FOCUS
,
1914 _T("%s: focus in"), win
->GetName().c_str());
1918 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1922 // caret needs to be informed about focus change
1923 wxCaret
*caret
= win
->GetCaret();
1926 caret
->OnSetFocus();
1928 #endif // wxUSE_CARET
1930 g_activeFrameLostFocus
= FALSE
;
1932 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1933 if ( active
!= g_activeFrame
)
1935 if ( g_activeFrame
)
1937 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1938 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1939 event
.SetEventObject(g_activeFrame
);
1940 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1943 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1944 g_activeFrame
= active
;
1945 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1946 event
.SetEventObject(g_activeFrame
);
1947 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1949 // Don't send focus events in addition to activate
1950 // if (win == g_activeFrame)
1954 // does the window itself think that it has the focus?
1955 if ( !win
->m_hasFocus
)
1957 // not yet, notify it
1958 win
->m_hasFocus
= TRUE
;
1960 if ( DoSendFocusEvents(win
) )
1962 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1970 //-----------------------------------------------------------------------------
1971 // "focus_out_event"
1972 //-----------------------------------------------------------------------------
1974 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1979 wxapp_install_idle_handler();
1981 if (!win
->m_hasVMT
) return FALSE
;
1982 if (g_blockEventsOnDrag
) return FALSE
;
1984 wxLogTrace( TRACE_FOCUS
,
1985 _T("%s: focus out"), win
->GetName().c_str() );
1987 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1989 // VZ: commenting this out because it does happen (although not easy
1990 // to reproduce, I only see it when using wxMiniFrame and not
1991 // always) and makes using Mahogany quite annoying
1993 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1994 wxT("unfocusing window that hasn't gained focus properly") );
1997 g_activeFrameLostFocus
= TRUE
;
2000 // if the focus goes out of our app alltogether, OnIdle() will send
2001 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
2002 // g_sendActivateEvent to -1
2003 g_sendActivateEvent
= 0;
2005 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2009 g_focusWindow
= (wxWindowGTK
*)NULL
;
2017 // caret needs to be informed about focus change
2018 wxCaret
*caret
= win
->GetCaret();
2021 caret
->OnKillFocus();
2023 #endif // wxUSE_CARET
2025 // don't send the window a kill focus event if it thinks that it doesn't
2026 // have focus already
2027 if ( win
->m_hasFocus
)
2029 win
->m_hasFocus
= FALSE
;
2031 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2032 event
.SetEventObject( win
);
2034 if (win
->GetEventHandler()->ProcessEvent( event
))
2036 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
2044 //-----------------------------------------------------------------------------
2045 // "enter_notify_event"
2046 //-----------------------------------------------------------------------------
2049 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2050 GdkEventCrossing
*gdk_event
,
2056 wxapp_install_idle_handler();
2058 if (!win
->m_hasVMT
) return FALSE
;
2059 if (g_blockEventsOnDrag
) return FALSE
;
2061 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2065 GdkModifierType state
= (GdkModifierType
)0;
2067 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2069 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2070 InitMouseEvent(win
, event
, gdk_event
);
2071 wxPoint pt
= win
->GetClientAreaOrigin();
2072 event
.m_x
= x
+ pt
.x
;
2073 event
.m_y
= y
+ pt
.y
;
2075 if (win
->GetEventHandler()->ProcessEvent( event
))
2077 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2084 //-----------------------------------------------------------------------------
2085 // "leave_notify_event"
2086 //-----------------------------------------------------------------------------
2088 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2093 wxapp_install_idle_handler();
2095 if (!win
->m_hasVMT
) return FALSE
;
2096 if (g_blockEventsOnDrag
) return FALSE
;
2098 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2100 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2101 event
.SetTimestamp( gdk_event
->time
);
2102 event
.SetEventObject( win
);
2106 GdkModifierType state
= (GdkModifierType
)0;
2108 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2110 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2111 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2112 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2113 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2114 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2115 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2116 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2118 wxPoint pt
= win
->GetClientAreaOrigin();
2119 event
.m_x
= x
+ pt
.x
;
2120 event
.m_y
= y
+ pt
.y
;
2122 if (win
->GetEventHandler()->ProcessEvent( event
))
2124 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2131 //-----------------------------------------------------------------------------
2132 // "value_changed" from m_vAdjust
2133 //-----------------------------------------------------------------------------
2135 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2142 wxapp_install_idle_handler();
2144 if (g_blockEventsOnDrag
) return;
2146 if (!win
->m_hasVMT
) return;
2148 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2149 if (fabs(diff
) < 0.2) return;
2151 win
->m_oldVerticalPos
= adjust
->value
;
2154 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2156 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2158 int value
= (int)(adjust
->value
+0.5);
2160 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2161 event
.SetEventObject( win
);
2162 win
->GetEventHandler()->ProcessEvent( event
);
2165 //-----------------------------------------------------------------------------
2166 // "value_changed" from m_hAdjust
2167 //-----------------------------------------------------------------------------
2169 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2176 wxapp_install_idle_handler();
2178 if (g_blockEventsOnDrag
) return;
2179 if (!win
->m_hasVMT
) return;
2181 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2182 if (fabs(diff
) < 0.2) return;
2185 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2187 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2189 win
->m_oldHorizontalPos
= adjust
->value
;
2191 int value
= (int)(adjust
->value
+0.5);
2193 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2194 event
.SetEventObject( win
);
2195 win
->GetEventHandler()->ProcessEvent( event
);
2198 //-----------------------------------------------------------------------------
2199 // "button_press_event" from scrollbar
2200 //-----------------------------------------------------------------------------
2202 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2203 GdkEventButton
*gdk_event
,
2209 wxapp_install_idle_handler();
2212 g_blockEventsOnScroll
= TRUE
;
2214 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2216 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2222 //-----------------------------------------------------------------------------
2223 // "button_release_event" from scrollbar
2224 //-----------------------------------------------------------------------------
2226 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2227 GdkEventButton
*WXUNUSED(gdk_event
),
2232 // don't test here as we can release the mouse while being over
2233 // a different window than the slider
2235 // if (gdk_event->window != widget->slider) return FALSE;
2237 g_blockEventsOnScroll
= FALSE
;
2239 if (win
->m_isScrolling
)
2241 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2245 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2246 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2248 value
= (int)(win
->m_hAdjust
->value
+0.5);
2251 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2253 value
= (int)(win
->m_vAdjust
->value
+0.5);
2257 wxScrollWinEvent
event( command
, value
, dir
);
2258 event
.SetEventObject( win
);
2259 win
->GetEventHandler()->ProcessEvent( event
);
2262 win
->m_isScrolling
= FALSE
;
2267 // ----------------------------------------------------------------------------
2268 // this wxWindowBase function is implemented here (in platform-specific file)
2269 // because it is static and so couldn't be made virtual
2270 // ----------------------------------------------------------------------------
2272 wxWindow
*wxWindowBase::FindFocus()
2274 // the cast is necessary when we compile in wxUniversal mode
2275 return (wxWindow
*)g_focusWindow
;
2278 //-----------------------------------------------------------------------------
2280 //-----------------------------------------------------------------------------
2282 // VZ: Robert commented the code using out so it generates warnings: should
2283 // be either fixed or removed completely
2286 static void gtk_window_destroy_callback( GtkWidget
* widget
, wxWindow
*win
)
2288 wxWindowDestroyEvent
event(win
);
2289 win
->GetEventHandler()->ProcessEvent(event
);
2294 //-----------------------------------------------------------------------------
2295 // "realize" from m_widget
2296 //-----------------------------------------------------------------------------
2298 /* We cannot set colours and fonts before the widget has
2299 been realized, so we do this directly after realization. */
2302 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2307 wxapp_install_idle_handler();
2309 if (win
->m_delayedBackgroundColour
)
2310 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2312 if (win
->m_delayedForegroundColour
)
2313 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2316 if (win
->m_imContext
)
2318 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2319 gtk_im_context_set_client_window( (GtkIMContext
*) win
->m_imContext
, pizza
->bin_window
);
2323 wxWindowCreateEvent
event( win
);
2324 event
.SetEventObject( win
);
2325 win
->GetEventHandler()->ProcessEvent( event
);
2330 //-----------------------------------------------------------------------------
2332 //-----------------------------------------------------------------------------
2335 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2336 GtkAllocation
*WXUNUSED(alloc
),
2340 wxapp_install_idle_handler();
2342 if (!win
->m_hasScrolling
) return;
2344 int client_width
= 0;
2345 int client_height
= 0;
2346 win
->GetClientSize( &client_width
, &client_height
);
2347 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2350 win
->m_oldClientWidth
= client_width
;
2351 win
->m_oldClientHeight
= client_height
;
2353 if (!win
->m_nativeSizeEvent
)
2355 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2356 event
.SetEventObject( win
);
2357 win
->GetEventHandler()->ProcessEvent( event
);
2363 #define WXUNUSED_UNLESS_XIM(param) param
2365 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2368 /* Resize XIM window */
2371 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2372 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2373 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2376 wxapp_install_idle_handler();
2382 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2386 gdk_window_get_size (widget
->window
, &width
, &height
);
2387 win
->m_icattr
->preedit_area
.width
= width
;
2388 win
->m_icattr
->preedit_area
.height
= height
;
2389 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2394 //-----------------------------------------------------------------------------
2395 // "realize" from m_wxwindow
2396 //-----------------------------------------------------------------------------
2398 /* Initialize XIM support */
2401 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2402 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2405 wxapp_install_idle_handler();
2408 if (win
->m_ic
) return FALSE
;
2409 if (!widget
) return FALSE
;
2410 if (!gdk_im_ready()) return FALSE
;
2412 win
->m_icattr
= gdk_ic_attr_new();
2413 if (!win
->m_icattr
) return FALSE
;
2417 GdkColormap
*colormap
;
2418 GdkICAttr
*attr
= win
->m_icattr
;
2419 unsigned attrmask
= GDK_IC_ALL_REQ
;
2421 GdkIMStyle supported_style
= (GdkIMStyle
)
2422 (GDK_IM_PREEDIT_NONE
|
2423 GDK_IM_PREEDIT_NOTHING
|
2424 GDK_IM_PREEDIT_POSITION
|
2425 GDK_IM_STATUS_NONE
|
2426 GDK_IM_STATUS_NOTHING
);
2428 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2429 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2431 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2432 attr
->client_window
= widget
->window
;
2434 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2435 gtk_widget_get_default_colormap ())
2437 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2438 attr
->preedit_colormap
= colormap
;
2441 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2442 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2443 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2444 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2446 switch (style
& GDK_IM_PREEDIT_MASK
)
2448 case GDK_IM_PREEDIT_POSITION
:
2449 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2451 g_warning ("over-the-spot style requires fontset");
2455 gdk_window_get_size (widget
->window
, &width
, &height
);
2457 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2458 attr
->spot_location
.x
= 0;
2459 attr
->spot_location
.y
= height
;
2460 attr
->preedit_area
.x
= 0;
2461 attr
->preedit_area
.y
= 0;
2462 attr
->preedit_area
.width
= width
;
2463 attr
->preedit_area
.height
= height
;
2464 attr
->preedit_fontset
= widget
->style
->font
;
2469 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2471 if (win
->m_ic
== NULL
)
2472 g_warning ("Can't create input context.");
2475 mask
= gdk_window_get_events (widget
->window
);
2476 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2477 gdk_window_set_events (widget
->window
, mask
);
2479 if (GTK_WIDGET_HAS_FOCUS(widget
))
2480 gdk_im_begin (win
->m_ic
, widget
->window
);
2487 //-----------------------------------------------------------------------------
2488 // InsertChild for wxWindowGTK.
2489 //-----------------------------------------------------------------------------
2491 /* Callback for wxWindowGTK. This very strange beast has to be used because
2492 * C++ has no virtual methods in a constructor. We have to emulate a
2493 * virtual function here as wxNotebook requires a different way to insert
2494 * a child in it. I had opted for creating a wxNotebookPage window class
2495 * which would have made this superfluous (such in the MDI window system),
2496 * but no-one was listening to me... */
2498 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2500 /* the window might have been scrolled already, do we
2501 have to adapt the position */
2502 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2503 child
->m_x
+= pizza
->xoffset
;
2504 child
->m_y
+= pizza
->yoffset
;
2506 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2507 GTK_WIDGET(child
->m_widget
),
2514 //-----------------------------------------------------------------------------
2516 //-----------------------------------------------------------------------------
2518 wxWindow
*wxGetActiveWindow()
2520 return wxWindow::FindFocus();
2523 //-----------------------------------------------------------------------------
2525 //-----------------------------------------------------------------------------
2527 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2529 #ifdef __WXUNIVERSAL__
2530 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2532 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2533 #endif // __WXUNIVERSAL__/__WXGTK__
2535 void wxWindowGTK::Init()
2541 m_widget
= (GtkWidget
*) NULL
;
2542 m_wxwindow
= (GtkWidget
*) NULL
;
2543 m_focusWidget
= (GtkWidget
*) NULL
;
2553 m_needParent
= TRUE
;
2554 m_isBeingDeleted
= FALSE
;
2557 m_nativeSizeEvent
= FALSE
;
2559 m_hasScrolling
= FALSE
;
2560 m_isScrolling
= FALSE
;
2562 m_hAdjust
= (GtkAdjustment
*) NULL
;
2563 m_vAdjust
= (GtkAdjustment
*) NULL
;
2564 m_oldHorizontalPos
= 0.0;
2565 m_oldVerticalPos
= 0.0;
2568 m_widgetStyle
= (GtkStyle
*) NULL
;
2570 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2572 m_acceptsFocus
= FALSE
;
2575 m_clipPaintRegion
= FALSE
;
2577 m_cursor
= *wxSTANDARD_CURSOR
;
2579 m_delayedForegroundColour
= FALSE
;
2580 m_delayedBackgroundColour
= FALSE
;
2584 m_x11Context
= NULL
;
2587 m_ic
= (GdkIC
*) NULL
;
2588 m_icattr
= (GdkICAttr
*) NULL
;
2593 wxWindowGTK::wxWindowGTK()
2598 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2603 const wxString
&name
)
2607 Create( parent
, id
, pos
, size
, style
, name
);
2610 bool wxWindowGTK::Create( wxWindow
*parent
,
2615 const wxString
&name
)
2617 if (!PreCreation( parent
, pos
, size
) ||
2618 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2620 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2624 m_insertCallback
= wxInsertChildInWindow
;
2626 // always needed for background clearing
2627 m_delayedBackgroundColour
= TRUE
;
2629 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2630 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2632 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2634 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2635 scroll_class
->scrollbar_spacing
= 0;
2637 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2639 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2640 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2642 m_wxwindow
= gtk_pizza_new();
2644 #ifndef __WXUNIVERSAL__
2645 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2647 if (HasFlag(wxRAISED_BORDER
))
2649 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2651 else if (HasFlag(wxSUNKEN_BORDER
))
2653 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2655 else if (HasFlag(wxSIMPLE_BORDER
))
2657 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2661 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2663 #endif // __WXUNIVERSAL__
2665 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2667 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2668 m_acceptsFocus
= TRUE
;
2670 // I _really_ don't want scrollbars in the beginning
2671 m_vAdjust
->lower
= 0.0;
2672 m_vAdjust
->upper
= 1.0;
2673 m_vAdjust
->value
= 0.0;
2674 m_vAdjust
->step_increment
= 1.0;
2675 m_vAdjust
->page_increment
= 1.0;
2676 m_vAdjust
->page_size
= 5.0;
2677 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2678 m_hAdjust
->lower
= 0.0;
2679 m_hAdjust
->upper
= 1.0;
2680 m_hAdjust
->value
= 0.0;
2681 m_hAdjust
->step_increment
= 1.0;
2682 m_hAdjust
->page_increment
= 1.0;
2683 m_hAdjust
->page_size
= 5.0;
2684 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2686 // these handlers block mouse events to any window during scrolling such as
2687 // motion events and prevent GTK and wxWindows from fighting over where the
2690 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2691 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2693 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2694 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2696 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2697 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2699 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2700 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2702 // these handlers get notified when screen updates are required either when
2703 // scrolling or when the window size (and therefore scrollbar configuration)
2706 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2707 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2708 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2709 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2712 // Create input method handler
2713 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2715 // Cannot handle drawing preedited text yet
2716 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2718 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2719 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2722 gtk_widget_show( m_wxwindow
);
2725 m_parent
->DoAddChild( this );
2727 m_focusWidget
= m_wxwindow
;
2736 wxWindowGTK::~wxWindowGTK()
2738 if (g_focusWindow
== this)
2739 g_focusWindow
= NULL
;
2741 if (g_activeFrame
== this)
2742 g_activeFrame
= NULL
;
2744 if ( g_delayedFocus
== this )
2745 g_delayedFocus
= NULL
;
2747 m_isBeingDeleted
= TRUE
;
2756 m_parent
->RemoveChild( this );
2760 gdk_ic_destroy (m_ic
);
2762 gdk_ic_attr_destroy (m_icattr
);
2767 #if DISABLE_STYLE_IF_BROKEN_THEME
2768 // don't delete if it's a pixmap theme style
2769 if (!m_widgetStyle
->engine_data
)
2770 gtk_style_unref( m_widgetStyle
);
2772 m_widgetStyle
= (GtkStyle
*) NULL
;
2777 gtk_widget_destroy( m_wxwindow
);
2778 m_wxwindow
= (GtkWidget
*) NULL
;
2783 gtk_widget_destroy( m_widget
);
2784 m_widget
= (GtkWidget
*) NULL
;
2788 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2790 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2792 // This turns -1 into 30 so that a minimal window is
2793 // visible even although -1,-1 has been given as the
2794 // size of the window. the same trick is used in other
2795 // ports and should make debugging easier.
2796 m_width
= WidthDefault(size
.x
) ;
2797 m_height
= HeightDefault(size
.y
);
2802 // some reasonable defaults
2807 m_x
= (gdk_screen_width () - m_width
) / 2;
2808 if (m_x
< 10) m_x
= 10;
2812 m_y
= (gdk_screen_height () - m_height
) / 2;
2813 if (m_y
< 10) m_y
= 10;
2820 void wxWindowGTK::PostCreation()
2822 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2828 // these get reported to wxWindows -> wxPaintEvent
2830 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2832 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2833 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2836 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2837 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2839 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2841 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2842 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2845 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE ) );
2849 // Create input method handler
2850 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2852 // Cannot handle drawing preedited text yet
2853 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2855 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2856 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2860 // these are called when the "sunken" or "raised" borders are drawn
2861 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2862 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2865 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2866 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2872 if (m_focusWidget
== NULL
)
2873 m_focusWidget
= m_widget
;
2875 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2876 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2878 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2879 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2881 // connect to the various key and mouse handlers
2883 GtkWidget
*connect_widget
= GetConnectWidget();
2885 ConnectWidget( connect_widget
);
2887 /* We cannot set colours, fonts and cursors before the widget has
2888 been realized, so we do this directly after realization */
2889 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2890 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2894 // Catch native resize events
2895 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2896 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2898 // Initialize XIM support
2899 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2900 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2902 // And resize XIM window
2903 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2904 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2907 if (!GTK_IS_COMBO(m_widget
))
2909 // This is needed if we want to add our windows into native
2910 // GTK control, such as the toolbar. With this callback, the
2911 // toolbar gets to know the correct size (the one set by the
2912 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2913 // when moving to GTK 2.0.
2914 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2915 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2921 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2923 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2924 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2926 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2927 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2929 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2930 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2932 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2933 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2935 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2936 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2938 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2939 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2941 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2942 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2944 // This keeps crashing on me. RR.
2946 // gtk_signal_connect( GTK_OBJECT(widget), "destroy",
2947 // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this );
2950 bool wxWindowGTK::Destroy()
2952 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2956 return wxWindowBase::Destroy();
2959 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2961 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2964 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2966 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2967 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2970 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2973 if (m_resizing
) return; /* I don't like recursions */
2976 int currentX
, currentY
;
2977 GetPosition(¤tX
, ¤tY
);
2982 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2984 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2986 /* don't set the size for children of wxNotebook, just take the values. */
2994 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2995 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2997 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2998 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
3002 m_x
= x
+ pizza
->xoffset
;
3003 m_y
= y
+ pizza
->yoffset
;
3005 if (width
!= -1) m_width
= width
;
3006 if (height
!= -1) m_height
= height
;
3008 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
3010 if (width
== -1) m_width
= 80;
3013 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
3015 if (height
== -1) m_height
= 26;
3018 int minWidth
= GetMinWidth(),
3019 minHeight
= GetMinHeight(),
3020 maxWidth
= GetMaxWidth(),
3021 maxHeight
= GetMaxHeight();
3023 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3024 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3025 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3026 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3029 int bottom_border
= 0;
3032 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3034 /* the default button has a border around it */
3040 DoMoveWindow( m_x
-border
,
3043 m_height
+border
+bottom_border
);
3048 /* Sometimes the client area changes size without the
3049 whole windows's size changing, but if the whole
3050 windows's size doesn't change, no wxSizeEvent will
3051 normally be sent. Here we add an extra test if
3052 the client test has been changed and this will
3054 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3058 wxPrintf( "OnSize sent from " );
3059 if (GetClassInfo() && GetClassInfo()->GetClassName())
3060 wxPrintf( GetClassInfo()->GetClassName() );
3061 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3064 if (!m_nativeSizeEvent
)
3066 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3067 event
.SetEventObject( this );
3068 GetEventHandler()->ProcessEvent( event
);
3074 void wxWindowGTK::OnInternalIdle()
3076 // Update invalidated regions.
3079 // Synthetize activate events.
3080 if ( g_sendActivateEvent
!= -1 )
3082 bool activate
= g_sendActivateEvent
!= 0;
3085 g_sendActivateEvent
= -1;
3087 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
3090 if ( g_activeFrameLostFocus
)
3092 if ( g_activeFrame
)
3094 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
3095 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
3096 event
.SetEventObject(g_activeFrame
);
3097 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
3098 g_activeFrame
= NULL
;
3100 g_activeFrameLostFocus
= FALSE
;
3103 wxCursor cursor
= m_cursor
;
3104 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3108 /* I now set the cursor anew in every OnInternalIdle call
3109 as setting the cursor in a parent window also effects the
3110 windows above so that checking for the current cursor is
3115 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3117 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3119 if (!g_globalCursor
.Ok())
3120 cursor
= *wxSTANDARD_CURSOR
;
3122 window
= m_widget
->window
;
3123 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3124 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3130 GdkWindow
*window
= m_widget
->window
;
3131 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3132 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3140 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3142 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3144 if (width
) (*width
) = m_width
;
3145 if (height
) (*height
) = m_height
;
3148 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3150 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3154 SetSize( width
, height
);
3161 #ifndef __WXUNIVERSAL__
3162 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3164 /* when using GTK 1.2 we set the shadow border size to 2 */
3168 if (HasFlag(wxSIMPLE_BORDER
))
3170 /* when using GTK 1.2 we set the simple border size to 1 */
3174 #endif // __WXUNIVERSAL__
3178 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3180 GtkRequisition vscroll_req
;
3181 vscroll_req
.width
= 2;
3182 vscroll_req
.height
= 2;
3183 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3184 (scroll_window
->vscrollbar
, &vscroll_req
);
3186 GtkRequisition hscroll_req
;
3187 hscroll_req
.width
= 2;
3188 hscroll_req
.height
= 2;
3189 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3190 (scroll_window
->hscrollbar
, &hscroll_req
);
3192 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3194 if (scroll_window
->vscrollbar_visible
)
3196 dw
+= vscroll_req
.width
;
3197 dw
+= scroll_class
->scrollbar_spacing
;
3200 if (scroll_window
->hscrollbar_visible
)
3202 dh
+= hscroll_req
.height
;
3203 dh
+= scroll_class
->scrollbar_spacing
;
3207 SetSize( width
+dw
, height
+dh
);
3211 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3213 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3217 if (width
) (*width
) = m_width
;
3218 if (height
) (*height
) = m_height
;
3225 #ifndef __WXUNIVERSAL__
3226 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3228 /* when using GTK 1.2 we set the shadow border size to 2 */
3232 if (HasFlag(wxSIMPLE_BORDER
))
3234 /* when using GTK 1.2 we set the simple border size to 1 */
3238 #endif // __WXUNIVERSAL__
3242 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3244 GtkRequisition vscroll_req
;
3245 vscroll_req
.width
= 2;
3246 vscroll_req
.height
= 2;
3247 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3248 (scroll_window
->vscrollbar
, &vscroll_req
);
3250 GtkRequisition hscroll_req
;
3251 hscroll_req
.width
= 2;
3252 hscroll_req
.height
= 2;
3253 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3254 (scroll_window
->hscrollbar
, &hscroll_req
);
3256 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3258 if (scroll_window
->vscrollbar_visible
)
3260 dw
+= vscroll_req
.width
;
3261 dw
+= scroll_class
->scrollbar_spacing
;
3264 if (scroll_window
->hscrollbar_visible
)
3266 dh
+= hscroll_req
.height
;
3267 dh
+= scroll_class
->scrollbar_spacing
;
3271 if (width
) (*width
) = m_width
- dw
;
3272 if (height
) (*height
) = m_height
- dh
;
3276 printf( "GetClientSize, name %s ", GetName().c_str() );
3277 if (width) printf( " width = %d", (*width) );
3278 if (height) printf( " height = %d", (*height) );
3283 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3285 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3289 if (m_parent
&& m_parent
->m_wxwindow
)
3291 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3292 dx
= pizza
->xoffset
;
3293 dy
= pizza
->yoffset
;
3296 if (x
) (*x
) = m_x
- dx
;
3297 if (y
) (*y
) = m_y
- dy
;
3300 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3302 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3304 if (!m_widget
->window
) return;
3306 GdkWindow
*source
= (GdkWindow
*) NULL
;
3308 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3310 source
= m_widget
->window
;
3314 gdk_window_get_origin( source
, &org_x
, &org_y
);
3318 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3320 org_x
+= m_widget
->allocation
.x
;
3321 org_y
+= m_widget
->allocation
.y
;
3329 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3331 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3333 if (!m_widget
->window
) return;
3335 GdkWindow
*source
= (GdkWindow
*) NULL
;
3337 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3339 source
= m_widget
->window
;
3343 gdk_window_get_origin( source
, &org_x
, &org_y
);
3347 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3349 org_x
+= m_widget
->allocation
.x
;
3350 org_y
+= m_widget
->allocation
.y
;
3358 bool wxWindowGTK::Show( bool show
)
3360 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3362 if (!wxWindowBase::Show(show
))
3369 gtk_widget_show( m_widget
);
3371 gtk_widget_hide( m_widget
);
3373 wxShowEvent
eventShow(GetId(), show
);
3374 eventShow
.m_eventObject
= this;
3376 GetEventHandler()->ProcessEvent(eventShow
);
3381 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3383 win
->OnParentEnable(enable
);
3385 // Recurse, so that children have the opportunity to Do The Right Thing
3386 // and reset colours that have been messed up by a parent's (really ancestor's)
3388 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3390 node
= node
->GetNext() )
3392 wxWindow
*child
= node
->GetData();
3393 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3394 wxWindowNotifyEnable(child
, enable
);
3398 bool wxWindowGTK::Enable( bool enable
)
3400 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3402 if (!wxWindowBase::Enable(enable
))
3408 gtk_widget_set_sensitive( m_widget
, enable
);
3410 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3412 wxWindowNotifyEnable(this, enable
);
3417 int wxWindowGTK::GetCharHeight() const
3419 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3421 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3424 PangoContext
*context
= NULL
;
3426 context
= gtk_widget_get_pango_context( m_widget
);
3431 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3432 PangoLayout
*layout
= pango_layout_new(context
);
3433 pango_layout_set_font_description(layout
, desc
);
3434 pango_layout_set_text(layout
, "H", 1);
3435 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3437 PangoRectangle rect
;
3438 pango_layout_line_get_extents(line
, NULL
, &rect
);
3440 g_object_unref( G_OBJECT( layout
) );
3442 return (int) (rect
.height
/ PANGO_SCALE
);
3444 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3446 return font
->ascent
+ font
->descent
;
3450 int wxWindowGTK::GetCharWidth() const
3452 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3454 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3457 PangoContext
*context
= NULL
;
3459 context
= gtk_widget_get_pango_context( m_widget
);
3464 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3465 PangoLayout
*layout
= pango_layout_new(context
);
3466 pango_layout_set_font_description(layout
, desc
);
3467 pango_layout_set_text(layout
, "H", 1);
3468 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3470 PangoRectangle rect
;
3471 pango_layout_line_get_extents(line
, NULL
, &rect
);
3473 g_object_unref( G_OBJECT( layout
) );
3475 return (int) (rect
.width
/ PANGO_SCALE
);
3477 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3479 return gdk_string_width( font
, "H" );
3483 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3487 int *externalLeading
,
3488 const wxFont
*theFont
) const
3490 wxFont fontToUse
= m_font
;
3491 if (theFont
) fontToUse
= *theFont
;
3493 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3495 if (string
.IsEmpty())
3503 PangoContext
*context
= NULL
;
3505 context
= gtk_widget_get_pango_context( m_widget
);
3514 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3515 PangoLayout
*layout
= pango_layout_new(context
);
3516 pango_layout_set_font_description(layout
, desc
);
3519 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3520 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3522 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3523 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3524 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3527 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3529 PangoRectangle rect
;
3530 pango_layout_line_get_extents(line
, NULL
, &rect
);
3532 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3533 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3536 // Do something about metrics here
3539 if (externalLeading
) (*externalLeading
) = 0; // ??
3541 g_object_unref( G_OBJECT( layout
) );
3543 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3544 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3545 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3546 if (descent
) (*descent
) = font
->descent
;
3547 if (externalLeading
) (*externalLeading
) = 0; // ??
3551 void wxWindowGTK::SetFocus()
3553 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3557 // don't do anything if we already have focus
3563 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3565 gtk_widget_grab_focus (m_wxwindow
);
3570 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3572 if (!GTK_WIDGET_REALIZED(m_widget
))
3574 // we can't set the focus to the widget now so we remember that
3575 // it should be focused and will do it later, during the idle
3576 // time, as soon as we can
3577 wxLogTrace(TRACE_FOCUS
,
3578 _T("Delaying setting focus to %s(%s)"),
3579 GetClassInfo()->GetClassName(), GetLabel().c_str());
3581 g_delayedFocus
= this;
3585 wxLogTrace(TRACE_FOCUS
,
3586 _T("Setting focus to %s(%s)"),
3587 GetClassInfo()->GetClassName(), GetLabel().c_str());
3589 gtk_widget_grab_focus (m_widget
);
3592 else if (GTK_IS_CONTAINER(m_widget
))
3594 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3598 wxLogTrace(TRACE_FOCUS
,
3599 _T("Can't set focus to %s(%s)"),
3600 GetClassInfo()->GetClassName(), GetLabel().c_str());
3605 bool wxWindowGTK::AcceptsFocus() const
3607 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3610 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3612 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3614 wxWindowGTK
*oldParent
= m_parent
,
3615 *newParent
= (wxWindowGTK
*)newParentBase
;
3617 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3619 if ( !wxWindowBase::Reparent(newParent
) )
3622 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3624 /* prevent GTK from deleting the widget arbitrarily */
3625 gtk_widget_ref( m_widget
);
3629 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3632 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3636 /* insert GTK representation */
3637 (*(newParent
->m_insertCallback
))(newParent
, this);
3640 /* reverse: prevent GTK from deleting the widget arbitrarily */
3641 gtk_widget_unref( m_widget
);
3646 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3648 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3650 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3652 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3657 /* insert GTK representation */
3658 (*m_insertCallback
)(this, child
);
3661 void wxWindowGTK::Raise()
3663 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3665 if (!m_widget
->window
) return;
3667 gdk_window_raise( m_widget
->window
);
3670 void wxWindowGTK::Lower()
3672 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3674 if (!m_widget
->window
) return;
3676 gdk_window_lower( m_widget
->window
);
3679 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3681 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3683 if (cursor
== m_cursor
)
3687 wxapp_install_idle_handler();
3689 if (cursor
== wxNullCursor
)
3690 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3692 return wxWindowBase::SetCursor( cursor
);
3695 void wxWindowGTK::WarpPointer( int x
, int y
)
3697 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3699 // We provide this function ourselves as it is
3700 // missing in GDK (top of this file).
3702 GdkWindow
*window
= (GdkWindow
*) NULL
;
3704 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3706 window
= GetConnectWidget()->window
;
3709 gdk_window_warp_pointer( window
, x
, y
);
3713 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3715 if (!m_widget
) return;
3716 if (!m_widget
->window
) return;
3720 wxapp_install_idle_handler();
3722 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3726 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3727 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3731 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3732 m_clearRegion
.Clear();
3733 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3741 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3742 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3746 GdkRectangle gdk_rect
;
3747 gdk_rect
.x
= rect
->x
;
3748 gdk_rect
.y
= rect
->y
;
3749 gdk_rect
.width
= rect
->width
;
3750 gdk_rect
.height
= rect
->height
;
3751 gtk_widget_draw( m_widget
, &gdk_rect
);
3758 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3759 m_updateRegion
.Clear();
3760 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3764 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3772 GdkRectangle gdk_rect
;
3773 gdk_rect
.x
= rect
->x
;
3774 gdk_rect
.y
= rect
->y
;
3775 gdk_rect
.width
= rect
->width
;
3776 gdk_rect
.height
= rect
->height
;
3777 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3781 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3787 void wxWindowGTK::Update()
3792 void wxWindowGTK::GtkUpdate()
3795 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3796 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3798 if (!m_updateRegion
.IsEmpty())
3799 GtkSendPaintEvents();
3803 void wxWindowGTK::GtkSendPaintEvents()
3808 m_clearRegion
.Clear();
3810 m_updateRegion
.Clear();
3814 // Clip to paint region in wxClientDC
3815 m_clipPaintRegion
= TRUE
;
3818 // widget to draw on
3819 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3821 // later for GTK 2.0, too.
3822 if (GetThemeEnabled())
3824 // find ancestor from which to steal background
3825 wxWindow
*parent
= GetParent();
3826 while (parent
&& !parent
->IsTopLevel())
3827 parent
= parent
->GetParent();
3829 parent
= (wxWindow
*)this;
3831 wxRegionIterator
upd( m_updateRegion
);
3835 rect
.x
= upd
.GetX();
3836 rect
.y
= upd
.GetY();
3837 rect
.width
= upd
.GetWidth();
3838 rect
.height
= upd
.GetHeight();
3840 gtk_paint_flat_box( parent
->m_widget
->style
,
3857 wxWindowDC
dc( (wxWindow
*)this );
3858 dc
.SetClippingRegion( m_updateRegion
);
3860 wxEraseEvent
erase_event( GetId(), &dc
);
3861 erase_event
.SetEventObject( this );
3863 GetEventHandler()->ProcessEvent(erase_event
);
3866 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3868 wxWindowDC
dc( (wxWindow
*)this );
3869 if (m_clearRegion
.IsEmpty())
3870 dc
.SetClippingRegion( m_updateRegion
);
3872 dc
.SetClippingRegion( m_clearRegion
);
3874 wxEraseEvent
erase_event( GetId(), &dc
);
3875 erase_event
.SetEventObject( this );
3877 if (!GetEventHandler()->ProcessEvent(erase_event
))
3881 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3882 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3884 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3886 wxRegionIterator
upd( m_clearRegion
);
3889 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3890 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3894 m_clearRegion
.Clear();
3898 wxNcPaintEvent
nc_paint_event( GetId() );
3899 nc_paint_event
.SetEventObject( this );
3900 GetEventHandler()->ProcessEvent( nc_paint_event
);
3902 wxPaintEvent
paint_event( GetId() );
3903 paint_event
.SetEventObject( this );
3904 GetEventHandler()->ProcessEvent( paint_event
);
3906 m_clipPaintRegion
= FALSE
;
3908 #ifndef __WXUNIVERSAL__
3910 // The following code will result in all window-less widgets
3911 // being redrawn because the wxWindows class is allowed to
3912 // paint over the window-less widgets.
3914 GList
*children
= pizza
->children
;
3917 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3918 children
= children
->next
;
3920 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3921 GTK_WIDGET_DRAWABLE (child
->widget
))
3923 // Get intersection of widget area and update region
3924 wxRegion
region( m_updateRegion
);
3926 GdkEventExpose gdk_event
;
3927 gdk_event
.type
= GDK_EXPOSE
;
3928 gdk_event
.window
= pizza
->bin_window
;
3929 gdk_event
.count
= 0;
3931 wxRegionIterator
upd( m_updateRegion
);
3935 rect
.x
= upd
.GetX();
3936 rect
.y
= upd
.GetY();
3937 rect
.width
= upd
.GetWidth();
3938 rect
.height
= upd
.GetHeight();
3940 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3942 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3952 m_updateRegion
.Clear();
3955 void wxWindowGTK::Clear()
3957 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3960 if (m_wxwindow
&& m_wxwindow
->window
)
3962 m_clearRegion
.Clear();
3963 wxSize
size( GetClientSize() );
3964 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3966 // Better do this in idle?
3973 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3975 wxWindowBase::DoSetToolTip(tip
);
3978 m_tooltip
->Apply( (wxWindow
*)this );
3981 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3983 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3985 #endif // wxUSE_TOOLTIPS
3987 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3989 GdkWindow
*window
= (GdkWindow
*) NULL
;
3991 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3993 window
= GetConnectWidget()->window
;
3997 // We need the pixel value e.g. for background clearing.
3998 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
4002 // wxMSW doesn't clear the window here, either.
4003 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
4009 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4011 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4013 if (!wxWindowBase::SetBackgroundColour(colour
))
4016 GdkWindow
*window
= (GdkWindow
*) NULL
;
4018 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4020 window
= GetConnectWidget()->window
;
4024 // indicate that a new style has been set
4025 // but it couldn't get applied as the
4026 // widget hasn't been realized yet.
4027 m_delayedBackgroundColour
= TRUE
;
4032 GtkSetBackgroundColour( colour
);
4038 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
4040 GdkWindow
*window
= (GdkWindow
*) NULL
;
4042 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4044 window
= GetConnectWidget()->window
;
4051 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4053 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4055 if (!wxWindowBase::SetForegroundColour(colour
))
4057 // don't leave if the GTK widget has just
4059 if (!m_delayedForegroundColour
) return FALSE
;
4062 GdkWindow
*window
= (GdkWindow
*) NULL
;
4064 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4066 window
= GetConnectWidget()->window
;
4070 // indicate that a new style has been set
4071 // but it couldn't get applied as the
4072 // widget hasn't been realized yet.
4073 m_delayedForegroundColour
= TRUE
;
4077 GtkSetForegroundColour( colour
);
4084 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4086 return gtk_widget_get_pango_context( m_widget
);
4089 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4092 m_x11Context
= pango_x_get_context( gdk_display
);
4094 return m_x11Context
;
4098 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4102 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4104 // FIXME: no more klass in 2.0
4106 remake
->klass
= m_widgetStyle
->klass
;
4109 gtk_style_unref( m_widgetStyle
);
4110 m_widgetStyle
= remake
;
4114 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4117 def
= gtk_widget_get_default_style();
4119 m_widgetStyle
= gtk_style_copy( def
);
4121 // FIXME: no more klass in 2.0
4123 m_widgetStyle
->klass
= def
->klass
;
4127 return m_widgetStyle
;
4130 void wxWindowGTK::SetWidgetStyle()
4132 #if DISABLE_STYLE_IF_BROKEN_THEME
4133 if (m_widget
->style
->engine_data
)
4135 static bool s_warningPrinted
= FALSE
;
4136 if (!s_warningPrinted
)
4138 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
4139 s_warningPrinted
= TRUE
;
4141 m_widgetStyle
= m_widget
->style
;
4146 GtkStyle
*style
= GetWidgetStyle();
4148 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
4151 pango_font_description_free( style
->font_desc
);
4152 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4154 gdk_font_unref( style
->font
);
4155 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4159 if (m_foregroundColour
.Ok())
4161 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4162 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4164 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4165 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4166 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4170 // Try to restore the gtk default style. This is still a little
4171 // oversimplified for what is probably really needed here for controls
4172 // other than buttons, but is better than not being able to (re)set a
4173 // control's foreground colour to *wxBLACK -- RL
4174 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4177 def
= gtk_widget_get_default_style();
4179 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4180 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4181 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4185 if (m_backgroundColour
.Ok())
4187 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4188 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4190 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4191 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4192 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4193 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4194 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4195 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4196 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4197 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4201 // Try to restore the gtk default style. This is still a little
4202 // oversimplified for what is probably really needed here for controls
4203 // other than buttons, but is better than not being able to (re)set a
4204 // control's background colour to default grey and means resetting a
4205 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4207 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4210 def
= gtk_widget_get_default_style();
4212 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4213 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4214 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4215 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4216 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4217 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4218 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4219 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4224 void wxWindowGTK::ApplyWidgetStyle()
4228 //-----------------------------------------------------------------------------
4229 // Pop-up menu stuff
4230 //-----------------------------------------------------------------------------
4232 #if wxUSE_MENUS_NATIVE
4235 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4237 *is_waiting
= FALSE
;
4240 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4242 menu
->SetInvokingWindow( win
);
4243 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
4246 wxMenuItem
*menuitem
= node
->GetData();
4247 if (menuitem
->IsSubMenu())
4249 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4252 node
= node
->GetNext();
4256 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
4257 // wxPopupMenuPositionCallback()
4259 // should be safe even in the MT case as the user can hardly popup 2 menus
4260 // simultaneously, can he?
4261 static gint gs_pop_x
= 0;
4262 static gint gs_pop_y
= 0;
4264 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4267 gboolean
* WXUNUSED(whatever
),
4269 gpointer
WXUNUSED(user_data
) )
4271 // ensure that the menu appears entirely on screen
4273 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4275 wxSize sizeScreen
= wxGetDisplaySize();
4277 gint xmax
= sizeScreen
.x
- req
.width
,
4278 ymax
= sizeScreen
.y
- req
.height
;
4280 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
4281 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
4284 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4286 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4288 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
4290 SetInvokingWindow( menu
, this );
4296 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
4298 bool is_waiting
= TRUE
;
4300 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4302 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4303 (gpointer
)&is_waiting
);
4306 GTK_MENU(menu
->m_menu
),
4307 (GtkWidget
*) NULL
, // parent menu shell
4308 (GtkWidget
*) NULL
, // parent menu item
4309 wxPopupMenuPositionCallback
, // function to position it
4310 NULL
, // client data
4311 0, // button used to activate it
4312 gs_timeLastClick
// the time of activation
4317 while (gtk_events_pending())
4318 gtk_main_iteration();
4324 #endif // wxUSE_MENUS_NATIVE
4326 #if wxUSE_DRAG_AND_DROP
4328 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4330 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4332 GtkWidget
*dnd_widget
= GetConnectWidget();
4334 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4336 if (m_dropTarget
) delete m_dropTarget
;
4337 m_dropTarget
= dropTarget
;
4339 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4342 #endif // wxUSE_DRAG_AND_DROP
4344 GtkWidget
* wxWindowGTK::GetConnectWidget()
4346 GtkWidget
*connect_widget
= m_widget
;
4347 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4349 return connect_widget
;
4352 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4355 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4357 return (window
== m_widget
->window
);
4360 bool wxWindowGTK::SetFont( const wxFont
&font
)
4362 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4364 if (!wxWindowBase::SetFont(font
))
4369 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4370 if ( sysbg
== m_backgroundColour
)
4372 m_backgroundColour
= wxNullColour
;
4374 m_backgroundColour
= sysbg
;
4384 void wxWindowGTK::DoCaptureMouse()
4386 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4388 GdkWindow
*window
= (GdkWindow
*) NULL
;
4390 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4392 window
= GetConnectWidget()->window
;
4394 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4396 wxCursor
* cursor
= & m_cursor
;
4398 cursor
= wxSTANDARD_CURSOR
;
4400 gdk_pointer_grab( window
, FALSE
,
4402 (GDK_BUTTON_PRESS_MASK
|
4403 GDK_BUTTON_RELEASE_MASK
|
4404 GDK_POINTER_MOTION_HINT_MASK
|
4405 GDK_POINTER_MOTION_MASK
),
4407 cursor
->GetCursor(),
4408 (guint32
)GDK_CURRENT_TIME
);
4409 g_captureWindow
= this;
4410 g_captureWindowHasMouse
= TRUE
;
4413 void wxWindowGTK::DoReleaseMouse()
4415 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4417 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4419 g_captureWindow
= (wxWindowGTK
*) NULL
;
4421 GdkWindow
*window
= (GdkWindow
*) NULL
;
4423 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4425 window
= GetConnectWidget()->window
;
4430 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4434 wxWindow
*wxWindowBase::GetCapture()
4436 return (wxWindow
*)g_captureWindow
;
4439 bool wxWindowGTK::IsRetained() const
4444 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4445 int range
, bool refresh
)
4447 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4449 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4451 m_hasScrolling
= TRUE
;
4453 if (orient
== wxHORIZONTAL
)
4455 float fpos
= (float)pos
;
4456 float frange
= (float)range
;
4457 float fthumb
= (float)thumbVisible
;
4458 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4459 if (fpos
< 0.0) fpos
= 0.0;
4461 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4462 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4464 SetScrollPos( orient
, pos
, refresh
);
4468 m_oldHorizontalPos
= fpos
;
4470 m_hAdjust
->lower
= 0.0;
4471 m_hAdjust
->upper
= frange
;
4472 m_hAdjust
->value
= fpos
;
4473 m_hAdjust
->step_increment
= 1.0;
4474 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4475 m_hAdjust
->page_size
= fthumb
;
4479 float fpos
= (float)pos
;
4480 float frange
= (float)range
;
4481 float fthumb
= (float)thumbVisible
;
4482 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4483 if (fpos
< 0.0) fpos
= 0.0;
4485 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4486 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4488 SetScrollPos( orient
, pos
, refresh
);
4492 m_oldVerticalPos
= fpos
;
4494 m_vAdjust
->lower
= 0.0;
4495 m_vAdjust
->upper
= frange
;
4496 m_vAdjust
->value
= fpos
;
4497 m_vAdjust
->step_increment
= 1.0;
4498 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4499 m_vAdjust
->page_size
= fthumb
;
4502 if (orient
== wxHORIZONTAL
)
4503 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4505 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4508 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4510 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4512 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4514 if (orient
== wxHORIZONTAL
)
4516 float fpos
= (float)pos
;
4517 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4518 if (fpos
< 0.0) fpos
= 0.0;
4519 m_oldHorizontalPos
= fpos
;
4521 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4522 m_hAdjust
->value
= fpos
;
4526 float fpos
= (float)pos
;
4527 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4528 if (fpos
< 0.0) fpos
= 0.0;
4529 m_oldVerticalPos
= fpos
;
4531 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4532 m_vAdjust
->value
= fpos
;
4535 if (m_wxwindow
->window
)
4537 if (orient
== wxHORIZONTAL
)
4539 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4540 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4542 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4544 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4545 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4549 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4550 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4552 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4554 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4555 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4560 int wxWindowGTK::GetScrollThumb( int orient
) const
4562 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4564 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4566 if (orient
== wxHORIZONTAL
)
4567 return (int)(m_hAdjust
->page_size
+0.5);
4569 return (int)(m_vAdjust
->page_size
+0.5);
4572 int wxWindowGTK::GetScrollPos( int orient
) const
4574 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4576 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4578 if (orient
== wxHORIZONTAL
)
4579 return (int)(m_hAdjust
->value
+0.5);
4581 return (int)(m_vAdjust
->value
+0.5);
4584 int wxWindowGTK::GetScrollRange( int orient
) const
4586 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4588 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4590 if (orient
== wxHORIZONTAL
)
4591 return (int)(m_hAdjust
->upper
+0.5);
4593 return (int)(m_vAdjust
->upper
+0.5);
4596 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4598 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4600 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4602 // No scrolling requested.
4603 if ((dx
== 0) && (dy
== 0)) return;
4606 if (!m_updateRegion
.IsEmpty())
4608 m_updateRegion
.Offset( dx
, dy
);
4612 GetClientSize( &cw
, &ch
);
4613 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4616 if (!m_clearRegion
.IsEmpty())
4618 m_clearRegion
.Offset( dx
, dy
);
4622 GetClientSize( &cw
, &ch
);
4623 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4627 m_clipPaintRegion
= TRUE
;
4629 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4631 m_clipPaintRegion
= FALSE
;
4635 // Find the wxWindow at the current mouse position, also returning the mouse
4637 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4639 pt
= wxGetMousePosition();
4640 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4644 // Get the current mouse position.
4645 wxPoint
wxGetMousePosition()
4647 /* This crashes when used within wxHelpContext,
4648 so we have to use the X-specific implementation below.
4650 GdkModifierType *mask;
4651 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4653 return wxPoint(x, y);
4657 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4659 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4660 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4661 Window rootReturn
, childReturn
;
4662 int rootX
, rootY
, winX
, winY
;
4663 unsigned int maskReturn
;
4665 XQueryPointer (display
,
4669 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4670 return wxPoint(rootX
, rootY
);
4674 // ----------------------------------------------------------------------------
4676 // ----------------------------------------------------------------------------
4678 class wxWinModule
: public wxModule
4685 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4688 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4690 bool wxWinModule::OnInit()
4692 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4693 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4698 void wxWinModule::OnExit()
4701 gdk_gc_unref( g_eraseGC
);