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"
53 #include "wx/thread.h"
58 #include "wx/gtk/private.h"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
69 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
71 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
81 extern GtkContainerClass
*pizza_parent_class
;
84 //-----------------------------------------------------------------------------
85 // documentation on internals
86 //-----------------------------------------------------------------------------
89 I have been asked several times about writing some documentation about
90 the GTK port of wxWindows, especially its internal structures. Obviously,
91 you cannot understand wxGTK without knowing a little about the GTK, but
92 some more information about what the wxWindow, which is the base class
93 for all other window classes, does seems required as well.
97 What does wxWindow do? It contains the common interface for the following
98 jobs of its descendants:
100 1) Define the rudimentary behaviour common to all window classes, such as
101 resizing, intercepting user input (so as to make it possible to use these
102 events for special purposes in a derived class), window names etc.
104 2) Provide the possibility to contain and manage children, if the derived
105 class is allowed to contain children, which holds true for those window
106 classes which do not display a native GTK widget. To name them, these
107 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
108 work classes are a special case and are handled a bit differently from
109 the rest. The same holds true for the wxNotebook class.
111 3) Provide the possibility to draw into a client area of a window. This,
112 too, only holds true for classes that do not display a native GTK widget
115 4) Provide the entire mechanism for scrolling widgets. This actual inter-
116 face for this is usually in wxScrolledWindow, but the GTK implementation
119 5) A multitude of helper or extra methods for special purposes, such as
120 Drag'n'Drop, managing validators etc.
122 6) Display a border (sunken, raised, simple or none).
124 Normally one might expect, that one wxWindows window would always correspond
125 to one GTK widget. Under GTK, there is no such allround widget that has all
126 the functionality. Moreover, the GTK defines a client area as a different
127 widget from the actual widget you are handling. Last but not least some
128 special classes (e.g. wxFrame) handle different categories of widgets and
129 still have the possibility to draw something in the client area.
130 It was therefore required to write a special purpose GTK widget, that would
131 represent a client area in the sense of wxWindows capable to do the jobs
132 2), 3) and 4). I have written this class and it resides in win_gtk.c of
135 All windows must have a widget, with which they interact with other under-
136 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
137 thw wxWindow class has a member variable called m_widget which holds a
138 pointer to this widget. When the window class represents a GTK native widget,
139 this is (in most cases) the only GTK widget the class manages. E.g. the
140 wxStatitText class handles only a GtkLabel widget a pointer to which you
141 can find in m_widget (defined in wxWindow)
143 When the class has a client area for drawing into and for containing children
144 it has to handle the client area widget (of the type GtkPizza, defined in
145 win_gtk.c), but there could be any number of widgets, handled by a class
146 The common rule for all windows is only, that the widget that interacts with
147 the rest of GTK must be referenced in m_widget and all other widgets must be
148 children of this widget on the GTK level. The top-most widget, which also
149 represents the client area, must be in the m_wxwindow field and must be of
152 As I said, the window classes that display a GTK native widget only have
153 one widget, so in the case of e.g. the wxButton class m_widget holds a
154 pointer to a GtkButton widget. But windows with client areas (for drawing
155 and children) have a m_widget field that is a pointer to a GtkScrolled-
156 Window and a m_wxwindow field that is pointer to a GtkPizza and this
157 one is (in the GTK sense) a child of the GtkScrolledWindow.
159 If the m_wxwindow field is set, then all input to this widget is inter-
160 cepted and sent to the wxWindows class. If not, all input to the widget
161 that gets pointed to by m_widget gets intercepted and sent to the class.
165 The design of scrolling in wxWindows is markedly different from that offered
166 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
167 clicking on a scrollbar belonging to scrolled window will inevitably move
168 the window. In wxWindows, the scrollbar will only emit an event, send this
169 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
170 which actually moves the window and its subchildren. Note that GtkPizza
171 memorizes how much it has been scrolled but that wxWindows forgets this
172 so that the two coordinates systems have to be kept in synch. This is done
173 in various places using the pizza->xoffset and pizza->yoffset values.
177 Singularily the most broken code in GTK is the code that is supposes to
178 inform subwindows (child windows) about new positions. Very often, duplicate
179 events are sent without changes in size or position, equally often no
180 events are sent at all (All this is due to a bug in the GtkContainer code
181 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
182 GTK's own system and it simply waits for size events for toplevel windows
183 and then iterates down the respective size events to all window. This has
184 the disadvantage, that windows might get size events before the GTK widget
185 actually has the reported size. This doesn't normally pose any problem, but
186 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
187 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
188 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
189 window that is used for OpenGl output really has that size (as reported by
194 If someone at some point of time feels the immense desire to have a look at,
195 change or attempt to optimse the Refresh() logic, this person will need an
196 intimate understanding of what a "draw" and what an "expose" events are and
197 what there are used for, in particular when used in connection with GTK's
198 own windowless widgets. Beware.
202 Cursors, too, have been a constant source of pleasure. The main difficulty
203 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
204 for the parent. To prevent this from doing too much harm, I use idle time
205 to set the cursor over and over again, starting from the toplevel windows
206 and ending with the youngest generation (speaking of parent and child windows).
207 Also don't forget that cursors (like much else) are connected to GdkWindows,
208 not GtkWidgets and that the "window" field of a GtkWidget might very well
209 point to the GdkWindow of the parent widget (-> "window less widget") and
210 that the two obviously have very different meanings.
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 extern wxList wxPendingDelete
;
219 extern bool g_blockEventsOnDrag
;
220 extern bool g_blockEventsOnScroll
;
221 extern wxCursor g_globalCursor
;
223 static GdkGC
*g_eraseGC
= NULL
;
225 // mouse capture state: the window which has it and if the mouse is currently
227 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
228 static bool g_captureWindowHasMouse
= FALSE
;
230 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
232 // the last window which had the focus - this is normally never NULL (except
233 // if we never had focus at all) as even when g_focusWindow is NULL it still
234 // keeps its previous value
235 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
237 // the frame that is currently active (i.e. its child has focus). It is
238 // used to generate wxActivateEvents
239 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
240 static bool g_activeFrameLostFocus
= FALSE
;
242 // If a window get the focus set but has not been realized
243 // yet, defer setting the focus to idle time.
244 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
246 // if we detect that the app has got/lost the focus, we set this variable to
247 // either TRUE or FALSE and an activate event will be sent during the next
248 // OnIdle() call and it is reset to -1: this value means that we shouldn't
249 // send any activate events at all
250 static int g_sendActivateEvent
= -1;
252 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
253 the last click here */
254 static guint32 gs_timeLastClick
= 0;
256 extern bool g_mainThreadLocked
;
258 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
263 #define DISABLE_STYLE_IF_BROKEN_THEME 1
269 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
271 # define DEBUG_MAIN_THREAD
274 #define DEBUG_MAIN_THREAD
277 // the trace mask used for the focus debugging messages
278 #define TRACE_FOCUS _T("focus")
280 //-----------------------------------------------------------------------------
281 // missing gdk functions
282 //-----------------------------------------------------------------------------
285 gdk_window_warp_pointer (GdkWindow
*window
,
290 GdkWindowPrivate
*priv
;
294 window
= GDK_ROOT_PARENT();
297 if (!GDK_WINDOW_DESTROYED(window
))
299 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
300 None
, /* not source window -> move from anywhere */
301 GDK_WINDOW_XID(window
), /* dest window */
302 0, 0, 0, 0, /* not source window -> move from anywhere */
306 priv
= (GdkWindowPrivate
*) window
;
308 if (!priv
->destroyed
)
310 XWarpPointer (priv
->xdisplay
,
311 None
, /* not source window -> move from anywhere */
312 priv
->xwindow
, /* dest window */
313 0, 0, 0, 0, /* not source window -> move from anywhere */
319 //-----------------------------------------------------------------------------
321 //-----------------------------------------------------------------------------
323 extern void wxapp_install_idle_handler();
324 extern bool g_isIdle
;
326 //-----------------------------------------------------------------------------
327 // local code (see below)
328 //-----------------------------------------------------------------------------
330 // returns the child of win which currently has focus or NULL if not found
332 // Note: can't be static, needed by textctrl.cpp.
333 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
335 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
337 return (wxWindow
*)NULL
;
339 if ( winFocus
== win
)
340 return (wxWindow
*)win
;
342 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
344 node
= node
->GetNext() )
346 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
351 return (wxWindow
*)NULL
;
354 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
356 // wxUniversal widgets draw the borders and scrollbars themselves
357 #ifndef __WXUNIVERSAL__
364 if (win
->m_hasScrolling
)
366 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
368 GtkRequisition vscroll_req
;
369 vscroll_req
.width
= 2;
370 vscroll_req
.height
= 2;
371 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
372 (scroll_window
->vscrollbar
, &vscroll_req
);
374 GtkRequisition hscroll_req
;
375 hscroll_req
.width
= 2;
376 hscroll_req
.height
= 2;
377 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
378 (scroll_window
->hscrollbar
, &hscroll_req
);
380 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
382 if (scroll_window
->vscrollbar_visible
)
384 dw
+= vscroll_req
.width
;
385 dw
+= scroll_class
->scrollbar_spacing
;
388 if (scroll_window
->hscrollbar_visible
)
390 dh
+= hscroll_req
.height
;
391 dh
+= scroll_class
->scrollbar_spacing
;
397 if (GTK_WIDGET_NO_WINDOW (widget
))
399 dx
+= widget
->allocation
.x
;
400 dy
+= widget
->allocation
.y
;
403 if (win
->HasFlag(wxRAISED_BORDER
))
405 gtk_draw_shadow( widget
->style
,
410 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
414 if (win
->HasFlag(wxSUNKEN_BORDER
))
416 gtk_draw_shadow( widget
->style
,
421 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
425 if (win
->HasFlag(wxSIMPLE_BORDER
))
428 gc
= gdk_gc_new( widget
->window
);
429 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
430 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
432 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
436 #endif // __WXUNIVERSAL__
439 //-----------------------------------------------------------------------------
440 // "expose_event" of m_widget
441 //-----------------------------------------------------------------------------
443 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
445 if (gdk_event
->count
> 0) return FALSE
;
447 draw_frame( widget
, win
);
451 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
457 //-----------------------------------------------------------------------------
458 // "draw" of m_widget
459 //-----------------------------------------------------------------------------
463 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
465 draw_frame( widget
, win
);
470 //-----------------------------------------------------------------------------
471 // "size_request" of m_widget
472 //-----------------------------------------------------------------------------
474 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
477 win
->GetSize( &w
, &h
);
481 requisition
->height
= h
;
482 requisition
->width
= w
;
485 //-----------------------------------------------------------------------------
486 // "expose_event" of m_wxwindow
487 //-----------------------------------------------------------------------------
489 static int gtk_window_expose_callback( GtkWidget
*widget
,
490 GdkEventExpose
*gdk_event
,
496 wxapp_install_idle_handler();
501 wxPrintf( wxT("OnExpose from ") );
502 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
503 wxPrintf( win
->GetClassInfo()->GetClassName() );
504 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
505 (int)gdk_event
->area
.y
,
506 (int)gdk_event
->area
.width
,
507 (int)gdk_event
->area
.height
);
511 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
513 gdk_event
->area
.width
,
514 gdk_event
->area
.height
);
515 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
517 gdk_event
->area
.width
,
518 gdk_event
->area
.height
);
520 // Actual redrawing takes place in idle time.
525 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
532 //-----------------------------------------------------------------------------
533 // "event" of m_wxwindow
534 //-----------------------------------------------------------------------------
536 // GTK thinks it is clever and filters out a certain amount of "unneeded"
537 // expose events. We need them, of course, so we override the main event
538 // procedure in GtkWidget by giving our own handler for all system events.
539 // There, we look for expose events ourselves whereas all other events are
542 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
543 GdkEventExpose
*event
,
546 if (event
->type
== GDK_EXPOSE
)
548 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
555 //-----------------------------------------------------------------------------
556 // "draw" of m_wxwindow
557 //-----------------------------------------------------------------------------
561 // This callback is a complete replacement of the gtk_pizza_draw() function,
562 // which is disabled.
564 static void gtk_window_draw_callback( GtkWidget
*widget
,
571 wxapp_install_idle_handler();
573 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
574 // there are no child windows.
575 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
576 (win
->GetChildren().GetCount() == 0))
584 wxPrintf( wxT("OnDraw from ") );
585 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
586 wxPrintf( win
->GetClassInfo()->GetClassName() );
587 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
594 #ifndef __WXUNIVERSAL__
595 GtkPizza
*pizza
= GTK_PIZZA (widget
);
597 if (win
->GetThemeEnabled())
599 wxWindow
*parent
= win
->GetParent();
600 while (parent
&& !parent
->IsTopLevel())
601 parent
= parent
->GetParent();
605 gtk_paint_flat_box (parent
->m_widget
->style
,
616 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
617 (pizza
->clear_on_draw
))
619 gdk_window_clear_area( pizza
->bin_window
,
620 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
624 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
626 // Actual redrawing takes place in idle time.
630 #ifndef __WXUNIVERSAL__
631 // Redraw child widgets
632 GList
*children
= pizza
->children
;
635 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
636 children
= children
->next
;
638 GdkRectangle child_area
;
639 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
641 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
649 //-----------------------------------------------------------------------------
650 // "key_press_event" from any window
651 //-----------------------------------------------------------------------------
653 // set WXTRACE to this to see the key event codes on the console
654 #define TRACE_KEYS _T("keyevent")
656 // translates an X key symbol to WXK_XXX value
658 // if isChar is true it means that the value returned will be used for EVT_CHAR
659 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
660 // for example, while if it is false it means that the value is going to be
661 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
663 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
669 // Shift, Control and Alt don't generate the CHAR events at all
672 key_code
= isChar
? 0 : WXK_SHIFT
;
676 key_code
= isChar
? 0 : WXK_CONTROL
;
684 key_code
= isChar
? 0 : WXK_ALT
;
687 // neither do the toggle modifies
688 case GDK_Scroll_Lock
:
689 key_code
= isChar
? 0 : WXK_SCROLL
;
693 key_code
= isChar
? 0 : WXK_CAPITAL
;
697 key_code
= isChar
? 0 : WXK_NUMLOCK
;
701 // various other special keys
714 case GDK_ISO_Left_Tab
:
721 key_code
= WXK_RETURN
;
725 key_code
= WXK_CLEAR
;
729 key_code
= WXK_PAUSE
;
733 key_code
= WXK_SELECT
;
737 key_code
= WXK_PRINT
;
741 key_code
= WXK_EXECUTE
;
745 key_code
= WXK_ESCAPE
;
748 // cursor and other extended keyboard keys
750 key_code
= WXK_DELETE
;
766 key_code
= WXK_RIGHT
;
773 case GDK_Prior
: // == GDK_Page_Up
774 key_code
= WXK_PRIOR
;
777 case GDK_Next
: // == GDK_Page_Down
790 key_code
= WXK_INSERT
;
805 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
809 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
813 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
817 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
821 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
825 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
829 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
833 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
837 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
841 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
845 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
849 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
853 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
856 case GDK_KP_Prior
: // == GDK_KP_Page_Up
857 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
860 case GDK_KP_Next
: // == GDK_KP_Page_Down
861 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
865 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
869 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
873 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
877 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
881 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
884 case GDK_KP_Multiply
:
885 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
889 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
892 case GDK_KP_Separator
:
893 // FIXME: what is this?
894 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
897 case GDK_KP_Subtract
:
898 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
902 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
906 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
923 key_code
= WXK_F1
+ keysym
- GDK_F1
;
933 static inline bool wxIsAsciiKeysym(KeySym ks
)
939 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
941 GdkEventKey
*gdk_event
)
943 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
944 // but only event->keyval which is quite useless to us, so remember
945 // the last character from GDK_KEY_PRESS and reuse it as last resort
947 // NB: should be MT-safe as we're always called from the main thread only
952 } s_lastKeyPress
= { 0, 0 };
954 KeySym keysym
= gdk_event
->keyval
;
956 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %d"),
957 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
961 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
965 // do we have the translation or is it a plain ASCII character?
966 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
968 // we should use keysym if it is ASCII as X does some translations
969 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
970 // which we don't want here (but which we do use for OnChar())
971 if ( !wxIsAsciiKeysym(keysym
) )
973 keysym
= (KeySym
)gdk_event
->string
[0];
976 // we want to always get the same key code when the same key is
977 // pressed regardless of the state of the modifies, i.e. on a
978 // standard US keyboard pressing '5' or '%' ('5' key with
979 // Shift) should result in the same key code in OnKeyDown():
980 // '5' (although OnChar() will get either '5' or '%').
982 // to do it we first translate keysym to keycode (== scan code)
983 // and then back but always using the lower register
984 Display
*dpy
= (Display
*)wxGetDisplay();
985 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
987 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
989 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
991 // use the normalized, i.e. lower register, keysym if we've
993 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
995 // as explained above, we want to have lower register key codes
996 // normally but for the letter keys we want to have the upper ones
998 // NB: don't use XConvertCase() here, we want to do it for letters
1000 key_code
= toupper(key_code
);
1002 else // non ASCII key, what to do?
1004 // by default, ignore it
1007 // but if we have cached information from the last KEY_PRESS
1008 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1011 if ( keysym
== s_lastKeyPress
.keysym
)
1013 key_code
= s_lastKeyPress
.keycode
;
1018 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1020 // remember it to be reused for KEY_UP event later
1021 s_lastKeyPress
.keysym
= keysym
;
1022 s_lastKeyPress
.keycode
= key_code
;
1026 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %d"), key_code
);
1028 // sending unknown key events doesn't really make sense
1032 // now fill all the other fields
1035 GdkModifierType state
;
1036 if (gdk_event
->window
)
1037 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1039 event
.SetTimestamp( gdk_event
->time
);
1040 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1041 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1042 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1043 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1044 event
.m_keyCode
= key_code
;
1045 event
.m_scanCode
= gdk_event
->keyval
;
1046 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1047 event
.m_rawFlags
= 0;
1050 event
.SetEventObject( win
);
1055 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1056 GdkEventKey
*gdk_event
,
1062 wxapp_install_idle_handler();
1066 if (g_blockEventsOnDrag
)
1070 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1071 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1073 // unknown key pressed, ignore (the event would be useless anyhow)
1077 // Emit KEY_DOWN event
1078 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1083 wxWindowGTK
*ancestor
= win
;
1086 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1089 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1090 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1093 if (ancestor
->IsTopLevel())
1095 ancestor
= ancestor
->GetParent();
1098 #endif // wxUSE_ACCEL
1100 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1101 // will only be sent if it is not in an accelerator table.
1104 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1105 KeySym keysym
= gdk_event
->keyval
;
1106 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1109 if ( gdk_event
->length
== 1 )
1111 key_code
= (unsigned char)gdk_event
->string
[0];
1113 else if ( wxIsAsciiKeysym(keysym
) )
1116 key_code
= (unsigned char)keysym
;
1122 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1124 event
.m_keyCode
= key_code
;
1126 // Implement OnCharHook by checking ancesteror top level windows
1127 wxWindow
*parent
= win
;
1128 while (parent
&& !parent
->IsTopLevel())
1129 parent
= parent
->GetParent();
1132 event
.SetEventType( wxEVT_CHAR_HOOK
);
1133 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1138 event
.SetEventType(wxEVT_CHAR
);
1139 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1144 // win is a control: tab can be propagated up
1146 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1147 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1148 // have this style, yet choose not to process this particular TAB in which
1149 // case TAB must still work as a navigational character
1151 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1153 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1155 wxNavigationKeyEvent new_event
;
1156 new_event
.SetEventObject( win
->GetParent() );
1157 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1158 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1159 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1160 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1161 new_event
.SetCurrentFocus( win
);
1162 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1165 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1167 (gdk_event
->keyval
== GDK_Escape
) )
1169 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1170 new_event
.SetEventObject( win
);
1171 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1176 // Pressing F10 will activate the menu bar of the top frame
1178 (gdk_event
->keyval
== GDK_F10
) )
1180 wxWindowGTK
*ancestor
= win
;
1183 if (wxIsKindOf(ancestor
,wxFrame
))
1185 wxFrame
*frame
= (wxFrame
*) ancestor
;
1186 wxMenuBar
*menubar
= frame
->GetMenuBar();
1189 wxNode
*node
= menubar
->GetMenus().First();
1192 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1193 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1199 ancestor
= ancestor
->GetParent();
1206 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1213 //-----------------------------------------------------------------------------
1214 // "key_release_event" from any window
1215 //-----------------------------------------------------------------------------
1217 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1218 GdkEventKey
*gdk_event
,
1224 wxapp_install_idle_handler();
1229 if (g_blockEventsOnDrag
)
1232 wxKeyEvent
event( wxEVT_KEY_UP
);
1233 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1235 // unknown key pressed, ignore (the event would be useless anyhow
1239 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1242 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1246 // ============================================================================
1248 // ============================================================================
1250 // ----------------------------------------------------------------------------
1251 // mouse event processing helpers
1252 // ----------------------------------------------------------------------------
1254 // init wxMouseEvent with the info from gdk_event
1255 #define InitMouseEvent(win, event, gdk_event) \
1257 event.SetTimestamp( gdk_event->time ); \
1258 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1259 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1260 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1261 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1262 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1263 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1264 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1266 wxPoint pt = win->GetClientAreaOrigin(); \
1267 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1268 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1271 static void AdjustEventButtonState(wxMouseEvent
& event
)
1273 // GDK reports the old state of the button for a button press event, but
1274 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1275 // for a LEFT_DOWN event, not FALSE, so we will invert
1276 // left/right/middleDown for the corresponding click events
1278 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1279 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1280 (event
.GetEventType() == wxEVT_LEFT_UP
))
1282 event
.m_leftDown
= !event
.m_leftDown
;
1286 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1287 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1288 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1290 event
.m_middleDown
= !event
.m_middleDown
;
1294 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1295 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1296 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1298 event
.m_rightDown
= !event
.m_rightDown
;
1303 // find the window to send the mouse event too
1305 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1310 if (win
->m_wxwindow
)
1312 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1313 xx
+= pizza
->xoffset
;
1314 yy
+= pizza
->yoffset
;
1317 wxNode
*node
= win
->GetChildren().First();
1320 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1322 node
= node
->Next();
1323 if (!child
->IsShown())
1326 if (child
->IsTransparentForMouse())
1328 // wxStaticBox is transparent in the box itself
1329 int xx1
= child
->m_x
;
1330 int yy1
= child
->m_y
;
1331 int xx2
= child
->m_x
+ child
->m_width
;
1332 int yy2
= child
->m_x
+ child
->m_height
;
1335 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1337 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1339 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1341 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1352 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1353 (child
->m_x
<= xx
) &&
1354 (child
->m_y
<= yy
) &&
1355 (child
->m_x
+child
->m_width
>= xx
) &&
1356 (child
->m_y
+child
->m_height
>= yy
))
1369 //-----------------------------------------------------------------------------
1370 // "button_press_event"
1371 //-----------------------------------------------------------------------------
1373 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1374 GdkEventButton
*gdk_event
,
1380 wxapp_install_idle_handler();
1383 wxPrintf( wxT("1) OnButtonPress from ") );
1384 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1385 wxPrintf( win->GetClassInfo()->GetClassName() );
1386 wxPrintf( wxT(".\n") );
1388 if (!win
->m_hasVMT
) return FALSE
;
1389 if (g_blockEventsOnDrag
) return TRUE
;
1390 if (g_blockEventsOnScroll
) return TRUE
;
1392 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1394 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1396 gtk_widget_grab_focus( win
->m_wxwindow
);
1398 wxPrintf( wxT("GrabFocus from ") );
1399 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1400 wxPrintf( win->GetClassInfo()->GetClassName() );
1401 wxPrintf( wxT(".\n") );
1405 wxEventType event_type
= wxEVT_NULL
;
1407 if (gdk_event
->button
== 1)
1409 switch (gdk_event
->type
)
1411 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1412 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1416 else if (gdk_event
->button
== 2)
1418 switch (gdk_event
->type
)
1420 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1421 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1425 else if (gdk_event
->button
== 3)
1427 switch (gdk_event
->type
)
1429 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1430 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1435 if ( event_type
== wxEVT_NULL
)
1437 // unknown mouse button or click type
1441 wxMouseEvent
event( event_type
);
1442 InitMouseEvent( win
, event
, gdk_event
);
1444 AdjustEventButtonState(event
);
1446 // wxListBox actually get mouse events from the item, so we need to give it
1447 // a chance to correct this
1448 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1450 // find the correct window to send the event too: it may be a different one
1451 // from the one which got it at GTK+ level because some control don't have
1452 // their own X window and thus cannot get any events.
1453 if ( !g_captureWindow
)
1454 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1456 event
.SetEventObject( win
);
1458 gs_timeLastClick
= gdk_event
->time
;
1461 wxPrintf( wxT("2) OnButtonPress from ") );
1462 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1463 wxPrintf( win->GetClassInfo()->GetClassName() );
1464 wxPrintf( wxT(".\n") );
1467 if (win
->GetEventHandler()->ProcessEvent( event
))
1469 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1476 //-----------------------------------------------------------------------------
1477 // "button_release_event"
1478 //-----------------------------------------------------------------------------
1480 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1485 wxapp_install_idle_handler();
1487 if (!win
->m_hasVMT
) return FALSE
;
1488 if (g_blockEventsOnDrag
) return FALSE
;
1489 if (g_blockEventsOnScroll
) return FALSE
;
1491 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1494 printf( "OnButtonRelease from " );
1495 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1496 printf( win->GetClassInfo()->GetClassName() );
1500 wxEventType event_type
= wxEVT_NULL
;
1502 switch (gdk_event
->button
)
1504 case 1: event_type
= wxEVT_LEFT_UP
; break;
1505 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1506 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1507 default: return FALSE
;
1510 wxMouseEvent
event( event_type
);
1511 InitMouseEvent( win
, event
, gdk_event
);
1513 AdjustEventButtonState(event
);
1515 // same wxListBox hack as above
1516 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1518 if ( !g_captureWindow
)
1519 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1521 event
.SetEventObject( win
);
1523 if (win
->GetEventHandler()->ProcessEvent( event
))
1525 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1532 //-----------------------------------------------------------------------------
1533 // "motion_notify_event"
1534 //-----------------------------------------------------------------------------
1536 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1537 GdkEventMotion
*gdk_event
,
1543 wxapp_install_idle_handler();
1545 if (!win
->m_hasVMT
) return FALSE
;
1546 if (g_blockEventsOnDrag
) return FALSE
;
1547 if (g_blockEventsOnScroll
) return FALSE
;
1549 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1551 if (gdk_event
->is_hint
)
1555 GdkModifierType state
;
1556 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1562 printf( "OnMotion from " );
1563 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1564 printf( win->GetClassInfo()->GetClassName() );
1568 wxMouseEvent
event( wxEVT_MOTION
);
1569 InitMouseEvent(win
, event
, gdk_event
);
1571 if ( g_captureWindow
)
1573 // synthetize a mouse enter or leave event if needed
1574 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1575 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1576 if ( hasMouse
!= g_captureWindowHasMouse
)
1578 // the mouse changed window
1579 g_captureWindowHasMouse
= hasMouse
;
1581 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1582 : wxEVT_LEAVE_WINDOW
);
1583 InitMouseEvent(win
, event
, gdk_event
);
1584 event
.SetEventObject(win
);
1585 win
->GetEventHandler()->ProcessEvent(event
);
1590 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1593 event
.SetEventObject( win
);
1595 if (win
->GetEventHandler()->ProcessEvent( event
))
1597 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1604 //-----------------------------------------------------------------------------
1606 //-----------------------------------------------------------------------------
1608 // send the wxChildFocusEvent and wxFocusEvent, common code of
1609 // gtk_window_focus_in_callback() and SetFocus()
1610 static bool DoSendFocusEvents(wxWindow
*win
)
1612 // Notify the parent keeping track of focus for the kbd navigation
1613 // purposes that we got it.
1614 wxChildFocusEvent
eventChildFocus(win
);
1615 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1617 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1618 eventFocus
.SetEventObject(win
);
1620 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1623 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1624 GdkEvent
*WXUNUSED(event
),
1630 wxapp_install_idle_handler();
1632 if (!win
->m_hasVMT
) return FALSE
;
1633 if (g_blockEventsOnDrag
) return FALSE
;
1635 switch ( g_sendActivateEvent
)
1638 // we've got focus from outside, synthetize wxActivateEvent
1639 g_sendActivateEvent
= 1;
1643 // another our window just lost focus, it was already ours before
1644 // - don't send any wxActivateEvent
1645 g_sendActivateEvent
= -1;
1650 g_focusWindow
= win
;
1652 wxLogTrace(TRACE_FOCUS
,
1653 _T("%s: focus in"), win
->GetName().c_str());
1657 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1661 // caret needs to be informed about focus change
1662 wxCaret
*caret
= win
->GetCaret();
1665 caret
->OnSetFocus();
1667 #endif // wxUSE_CARET
1669 g_activeFrameLostFocus
= FALSE
;
1671 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1672 if ( active
!= g_activeFrame
)
1674 if ( g_activeFrame
)
1676 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1677 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1678 event
.SetEventObject(g_activeFrame
);
1679 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1682 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1683 g_activeFrame
= active
;
1684 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1685 event
.SetEventObject(g_activeFrame
);
1686 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1688 // Don't send focus events in addition to activate
1689 // if (win == g_activeFrame)
1693 // does the window itself think that it has the focus?
1694 if ( !win
->m_hasFocus
)
1696 // not yet, notify it
1697 win
->m_hasFocus
= TRUE
;
1699 if ( DoSendFocusEvents(win
) )
1701 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1709 //-----------------------------------------------------------------------------
1710 // "focus_out_event"
1711 //-----------------------------------------------------------------------------
1713 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1718 wxapp_install_idle_handler();
1720 if (!win
->m_hasVMT
) return FALSE
;
1721 if (g_blockEventsOnDrag
) return FALSE
;
1723 wxLogTrace( TRACE_FOCUS
,
1724 _T("%s: focus out"), win
->GetName().c_str() );
1726 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1728 // VZ: commenting this out because it does happen (although not easy
1729 // to reproduce, I only see it when using wxMiniFrame and not
1730 // always) and makes using Mahogany quite annoying
1732 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1733 wxT("unfocusing window that hasn't gained focus properly") );
1736 g_activeFrameLostFocus
= TRUE
;
1739 // if the focus goes out of our app alltogether, OnIdle() will send
1740 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1741 // g_sendActivateEvent to -1
1742 g_sendActivateEvent
= 0;
1744 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1748 g_focusWindow
= (wxWindowGTK
*)NULL
;
1756 // caret needs to be informed about focus change
1757 wxCaret
*caret
= win
->GetCaret();
1760 caret
->OnKillFocus();
1762 #endif // wxUSE_CARET
1764 // don't send the window a kill focus event if it thinks that it doesn't
1765 // have focus already
1766 if ( win
->m_hasFocus
)
1768 win
->m_hasFocus
= FALSE
;
1770 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1771 event
.SetEventObject( win
);
1773 if (win
->GetEventHandler()->ProcessEvent( event
))
1775 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1783 //-----------------------------------------------------------------------------
1784 // "enter_notify_event"
1785 //-----------------------------------------------------------------------------
1787 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1792 wxapp_install_idle_handler();
1794 if (!win
->m_hasVMT
) return FALSE
;
1795 if (g_blockEventsOnDrag
) return FALSE
;
1797 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1799 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1800 event
.SetTimestamp( gdk_event
->time
);
1801 event
.SetEventObject( win
);
1805 GdkModifierType state
= (GdkModifierType
)0;
1807 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1809 InitMouseEvent(win
, event
, gdk_event
);
1810 wxPoint pt
= win
->GetClientAreaOrigin();
1811 event
.m_x
= x
+ pt
.x
;
1812 event
.m_y
= y
+ pt
.y
;
1814 if (win
->GetEventHandler()->ProcessEvent( event
))
1816 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1823 //-----------------------------------------------------------------------------
1824 // "leave_notify_event"
1825 //-----------------------------------------------------------------------------
1827 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1832 wxapp_install_idle_handler();
1834 if (!win
->m_hasVMT
) return FALSE
;
1835 if (g_blockEventsOnDrag
) return FALSE
;
1837 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1839 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1840 event
.SetTimestamp( gdk_event
->time
);
1841 event
.SetEventObject( win
);
1845 GdkModifierType state
= (GdkModifierType
)0;
1847 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1849 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1850 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1851 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1852 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1853 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1854 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1855 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1857 wxPoint pt
= win
->GetClientAreaOrigin();
1858 event
.m_x
= x
+ pt
.x
;
1859 event
.m_y
= y
+ pt
.y
;
1861 if (win
->GetEventHandler()->ProcessEvent( event
))
1863 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1870 //-----------------------------------------------------------------------------
1871 // "value_changed" from m_vAdjust
1872 //-----------------------------------------------------------------------------
1874 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1881 wxapp_install_idle_handler();
1883 if (g_blockEventsOnDrag
) return;
1885 if (!win
->m_hasVMT
) return;
1887 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1888 if (fabs(diff
) < 0.2) return;
1890 win
->m_oldVerticalPos
= adjust
->value
;
1892 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1893 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
1895 int value
= (int)(adjust
->value
+0.5);
1897 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1898 event
.SetEventObject( win
);
1899 win
->GetEventHandler()->ProcessEvent( event
);
1902 //-----------------------------------------------------------------------------
1903 // "value_changed" from m_hAdjust
1904 //-----------------------------------------------------------------------------
1906 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1913 wxapp_install_idle_handler();
1915 if (g_blockEventsOnDrag
) return;
1916 if (!win
->m_hasVMT
) return;
1918 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1919 if (fabs(diff
) < 0.2) return;
1921 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1922 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
1924 win
->m_oldHorizontalPos
= adjust
->value
;
1926 int value
= (int)(adjust
->value
+0.5);
1928 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1929 event
.SetEventObject( win
);
1930 win
->GetEventHandler()->ProcessEvent( event
);
1933 //-----------------------------------------------------------------------------
1934 // "button_press_event" from scrollbar
1935 //-----------------------------------------------------------------------------
1937 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1938 GdkEventButton
*gdk_event
,
1944 wxapp_install_idle_handler();
1947 g_blockEventsOnScroll
= TRUE
;
1949 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1951 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1957 //-----------------------------------------------------------------------------
1958 // "button_release_event" from scrollbar
1959 //-----------------------------------------------------------------------------
1961 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1962 GdkEventButton
*WXUNUSED(gdk_event
),
1967 // don't test here as we can release the mouse while being over
1968 // a different window than the slider
1970 // if (gdk_event->window != widget->slider) return FALSE;
1972 g_blockEventsOnScroll
= FALSE
;
1974 if (win
->m_isScrolling
)
1976 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1980 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1981 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1983 value
= (int)(win
->m_hAdjust
->value
+0.5);
1986 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
1988 value
= (int)(win
->m_vAdjust
->value
+0.5);
1992 wxScrollWinEvent
event( command
, value
, dir
);
1993 event
.SetEventObject( win
);
1994 win
->GetEventHandler()->ProcessEvent( event
);
1997 win
->m_isScrolling
= FALSE
;
2002 // ----------------------------------------------------------------------------
2003 // this wxWindowBase function is implemented here (in platform-specific file)
2004 // because it is static and so couldn't be made virtual
2005 // ----------------------------------------------------------------------------
2007 wxWindow
*wxWindowBase::FindFocus()
2009 // the cast is necessary when we compile in wxUniversal mode
2010 return (wxWindow
*)g_focusWindow
;
2013 //-----------------------------------------------------------------------------
2015 //-----------------------------------------------------------------------------
2017 // VZ: Robert commented the code using out so it generates warnings: should
2018 // be either fixed or removed completely
2021 static void gtk_window_destroy_callback( GtkWidget
* widget
, wxWindow
*win
)
2023 wxWindowDestroyEvent
event(win
);
2024 win
->GetEventHandler()->ProcessEvent(event
);
2029 //-----------------------------------------------------------------------------
2030 // "realize" from m_widget
2031 //-----------------------------------------------------------------------------
2033 /* We cannot set colours and fonts before the widget has
2034 been realized, so we do this directly after realization. */
2037 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2042 wxapp_install_idle_handler();
2044 if (win
->m_delayedBackgroundColour
)
2045 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2047 if (win
->m_delayedForegroundColour
)
2048 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2050 wxWindowCreateEvent
event( win
);
2051 event
.SetEventObject( win
);
2052 win
->GetEventHandler()->ProcessEvent( event
);
2057 //-----------------------------------------------------------------------------
2059 //-----------------------------------------------------------------------------
2062 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2063 GtkAllocation
*WXUNUSED(alloc
),
2067 wxapp_install_idle_handler();
2069 if (!win
->m_hasScrolling
) return;
2071 int client_width
= 0;
2072 int client_height
= 0;
2073 win
->GetClientSize( &client_width
, &client_height
);
2074 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2077 win
->m_oldClientWidth
= client_width
;
2078 win
->m_oldClientHeight
= client_height
;
2080 if (!win
->m_nativeSizeEvent
)
2082 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2083 event
.SetEventObject( win
);
2084 win
->GetEventHandler()->ProcessEvent( event
);
2090 #define WXUNUSED_UNLESS_XIM(param) param
2092 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2095 /* Resize XIM window */
2098 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2099 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2100 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2103 wxapp_install_idle_handler();
2109 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2113 gdk_window_get_size (widget
->window
, &width
, &height
);
2114 win
->m_icattr
->preedit_area
.width
= width
;
2115 win
->m_icattr
->preedit_area
.height
= height
;
2116 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2121 //-----------------------------------------------------------------------------
2122 // "realize" from m_wxwindow
2123 //-----------------------------------------------------------------------------
2125 /* Initialize XIM support */
2128 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2129 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2132 wxapp_install_idle_handler();
2135 if (win
->m_ic
) return FALSE
;
2136 if (!widget
) return FALSE
;
2137 if (!gdk_im_ready()) return FALSE
;
2139 win
->m_icattr
= gdk_ic_attr_new();
2140 if (!win
->m_icattr
) return FALSE
;
2144 GdkColormap
*colormap
;
2145 GdkICAttr
*attr
= win
->m_icattr
;
2146 unsigned attrmask
= GDK_IC_ALL_REQ
;
2148 GdkIMStyle supported_style
= (GdkIMStyle
)
2149 (GDK_IM_PREEDIT_NONE
|
2150 GDK_IM_PREEDIT_NOTHING
|
2151 GDK_IM_PREEDIT_POSITION
|
2152 GDK_IM_STATUS_NONE
|
2153 GDK_IM_STATUS_NOTHING
);
2155 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2156 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2158 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2159 attr
->client_window
= widget
->window
;
2161 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2162 gtk_widget_get_default_colormap ())
2164 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2165 attr
->preedit_colormap
= colormap
;
2168 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2169 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2170 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2171 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2173 switch (style
& GDK_IM_PREEDIT_MASK
)
2175 case GDK_IM_PREEDIT_POSITION
:
2176 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2178 g_warning ("over-the-spot style requires fontset");
2182 gdk_window_get_size (widget
->window
, &width
, &height
);
2184 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2185 attr
->spot_location
.x
= 0;
2186 attr
->spot_location
.y
= height
;
2187 attr
->preedit_area
.x
= 0;
2188 attr
->preedit_area
.y
= 0;
2189 attr
->preedit_area
.width
= width
;
2190 attr
->preedit_area
.height
= height
;
2191 attr
->preedit_fontset
= widget
->style
->font
;
2196 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2198 if (win
->m_ic
== NULL
)
2199 g_warning ("Can't create input context.");
2202 mask
= gdk_window_get_events (widget
->window
);
2203 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2204 gdk_window_set_events (widget
->window
, mask
);
2206 if (GTK_WIDGET_HAS_FOCUS(widget
))
2207 gdk_im_begin (win
->m_ic
, widget
->window
);
2214 //-----------------------------------------------------------------------------
2215 // InsertChild for wxWindowGTK.
2216 //-----------------------------------------------------------------------------
2218 /* Callback for wxWindowGTK. This very strange beast has to be used because
2219 * C++ has no virtual methods in a constructor. We have to emulate a
2220 * virtual function here as wxNotebook requires a different way to insert
2221 * a child in it. I had opted for creating a wxNotebookPage window class
2222 * which would have made this superfluous (such in the MDI window system),
2223 * but no-one was listening to me... */
2225 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2227 /* the window might have been scrolled already, do we
2228 have to adapt the position */
2229 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2230 child
->m_x
+= pizza
->xoffset
;
2231 child
->m_y
+= pizza
->yoffset
;
2233 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2234 GTK_WIDGET(child
->m_widget
),
2241 //-----------------------------------------------------------------------------
2243 //-----------------------------------------------------------------------------
2245 wxWindow
*wxGetActiveWindow()
2247 return wxWindow::FindFocus();
2250 //-----------------------------------------------------------------------------
2252 //-----------------------------------------------------------------------------
2254 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2256 #ifdef __WXUNIVERSAL__
2257 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2259 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2260 #endif // __WXUNIVERSAL__/__WXGTK__
2262 void wxWindowGTK::Init()
2268 m_widget
= (GtkWidget
*) NULL
;
2269 m_wxwindow
= (GtkWidget
*) NULL
;
2270 m_focusWidget
= (GtkWidget
*) NULL
;
2280 m_needParent
= TRUE
;
2281 m_isBeingDeleted
= FALSE
;
2284 m_nativeSizeEvent
= FALSE
;
2286 m_hasScrolling
= FALSE
;
2287 m_isScrolling
= FALSE
;
2289 m_hAdjust
= (GtkAdjustment
*) NULL
;
2290 m_vAdjust
= (GtkAdjustment
*) NULL
;
2291 m_oldHorizontalPos
= 0.0;
2292 m_oldVerticalPos
= 0.0;
2295 m_widgetStyle
= (GtkStyle
*) NULL
;
2297 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2299 m_acceptsFocus
= FALSE
;
2302 m_clipPaintRegion
= FALSE
;
2304 m_cursor
= *wxSTANDARD_CURSOR
;
2306 m_delayedForegroundColour
= FALSE
;
2307 m_delayedBackgroundColour
= FALSE
;
2310 m_ic
= (GdkIC
*) NULL
;
2311 m_icattr
= (GdkICAttr
*) NULL
;
2315 wxWindowGTK::wxWindowGTK()
2320 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2325 const wxString
&name
)
2329 Create( parent
, id
, pos
, size
, style
, name
);
2332 bool wxWindowGTK::Create( wxWindow
*parent
,
2337 const wxString
&name
)
2339 if (!PreCreation( parent
, pos
, size
) ||
2340 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2342 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2346 m_insertCallback
= wxInsertChildInWindow
;
2348 // always needed for background clearing
2349 m_delayedBackgroundColour
= TRUE
;
2351 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2352 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2354 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2356 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2357 scroll_class
->scrollbar_spacing
= 0;
2359 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2361 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2362 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2364 m_wxwindow
= gtk_pizza_new();
2366 #ifndef __WXUNIVERSAL__
2367 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2369 if (HasFlag(wxRAISED_BORDER
))
2371 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2373 else if (HasFlag(wxSUNKEN_BORDER
))
2375 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2377 else if (HasFlag(wxSIMPLE_BORDER
))
2379 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2383 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2385 #endif // __WXUNIVERSAL__
2387 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2389 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2390 m_acceptsFocus
= TRUE
;
2392 // I _really_ don't want scrollbars in the beginning
2393 m_vAdjust
->lower
= 0.0;
2394 m_vAdjust
->upper
= 1.0;
2395 m_vAdjust
->value
= 0.0;
2396 m_vAdjust
->step_increment
= 1.0;
2397 m_vAdjust
->page_increment
= 1.0;
2398 m_vAdjust
->page_size
= 5.0;
2399 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2400 m_hAdjust
->lower
= 0.0;
2401 m_hAdjust
->upper
= 1.0;
2402 m_hAdjust
->value
= 0.0;
2403 m_hAdjust
->step_increment
= 1.0;
2404 m_hAdjust
->page_increment
= 1.0;
2405 m_hAdjust
->page_size
= 5.0;
2406 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2408 // these handlers block mouse events to any window during scrolling such as
2409 // motion events and prevent GTK and wxWindows from fighting over where the
2412 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2413 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2415 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2416 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2418 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2419 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2421 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2422 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2424 // these handlers get notified when screen updates are required either when
2425 // scrolling or when the window size (and therefore scrollbar configuration)
2428 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2429 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2430 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2431 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2433 gtk_widget_show( m_wxwindow
);
2436 m_parent
->DoAddChild( this );
2438 m_focusWidget
= m_wxwindow
;
2447 wxWindowGTK::~wxWindowGTK()
2449 if (g_focusWindow
== this)
2450 g_focusWindow
= NULL
;
2452 if (g_activeFrame
== this)
2453 g_activeFrame
= NULL
;
2455 if ( g_delayedFocus
== this )
2456 g_delayedFocus
= NULL
;
2458 m_isBeingDeleted
= TRUE
;
2467 m_parent
->RemoveChild( this );
2471 gdk_ic_destroy (m_ic
);
2473 gdk_ic_attr_destroy (m_icattr
);
2478 #if DISABLE_STYLE_IF_BROKEN_THEME
2479 // don't delete if it's a pixmap theme style
2480 if (!m_widgetStyle
->engine_data
)
2481 gtk_style_unref( m_widgetStyle
);
2483 m_widgetStyle
= (GtkStyle
*) NULL
;
2488 gtk_widget_destroy( m_wxwindow
);
2489 m_wxwindow
= (GtkWidget
*) NULL
;
2494 gtk_widget_destroy( m_widget
);
2495 m_widget
= (GtkWidget
*) NULL
;
2499 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2501 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2503 /* this turns -1 into 20 so that a minimal window is
2504 visible even although -1,-1 has been given as the
2505 size of the window. the same trick is used in other
2506 ports and should make debugging easier */
2507 m_width
= WidthDefault(size
.x
);
2508 m_height
= HeightDefault(size
.y
);
2513 /* some reasonable defaults */
2518 m_x
= (gdk_screen_width () - m_width
) / 2;
2519 if (m_x
< 10) m_x
= 10;
2523 m_y
= (gdk_screen_height () - m_height
) / 2;
2524 if (m_y
< 10) m_y
= 10;
2531 void wxWindowGTK::PostCreation()
2533 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2539 // these get reported to wxWindows -> wxPaintEvent
2541 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2543 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2544 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2547 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2548 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2550 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2552 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2553 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2556 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2560 // these are called when the "sunken" or "raised" borders are drawn
2561 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2562 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2565 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2566 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2572 if (m_focusWidget
== NULL
)
2573 m_focusWidget
= m_widget
;
2575 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2576 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2578 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2579 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2581 // connect to the various key and mouse handlers
2583 GtkWidget
*connect_widget
= GetConnectWidget();
2585 ConnectWidget( connect_widget
);
2587 /* We cannot set colours, fonts and cursors before the widget has
2588 been realized, so we do this directly after realization */
2589 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2590 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2594 // Catch native resize events
2595 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2596 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2598 // Initialize XIM support
2599 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2600 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2602 // And resize XIM window
2603 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2604 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2607 if (!GTK_IS_COMBO(m_widget
))
2609 // This is needed if we want to add our windows into native
2610 // GTK control, such as the toolbar. With this callback, the
2611 // toolbar gets to know the correct size (the one set by the
2612 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2613 // when moving to GTK 2.0.
2614 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2615 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2621 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2623 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2624 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2626 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2627 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2629 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2630 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2632 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2633 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2635 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2636 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2638 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2639 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2641 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2642 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2644 // This keeps crashing on me. RR.
2646 // gtk_signal_connect( GTK_OBJECT(widget), "destroy",
2647 // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this );
2650 bool wxWindowGTK::Destroy()
2652 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2656 return wxWindowBase::Destroy();
2659 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2661 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2664 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2666 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2667 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2670 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2673 if (m_resizing
) return; /* I don't like recursions */
2676 int currentX
, currentY
;
2677 GetPosition(¤tX
, ¤tY
);
2682 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2684 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2686 /* don't set the size for children of wxNotebook, just take the values. */
2694 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2695 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2697 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2698 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2699 if (width
!= -1) m_width
= width
;
2700 if (height
!= -1) m_height
= height
;
2704 m_x
= x
+ pizza
->xoffset
;
2705 m_y
= y
+ pizza
->yoffset
;
2710 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2712 if (width
== -1) m_width
= 80;
2715 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2717 if (height
== -1) m_height
= 26;
2720 int minWidth
= GetMinWidth(),
2721 minHeight
= GetMinHeight(),
2722 maxWidth
= GetMaxWidth(),
2723 maxHeight
= GetMaxHeight();
2725 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2726 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2727 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2728 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2731 int bottom_border
= 0;
2734 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2736 /* the default button has a border around it */
2742 DoMoveWindow( m_x
-border
,
2745 m_height
+border
+bottom_border
);
2750 /* Sometimes the client area changes size without the
2751 whole windows's size changing, but if the whole
2752 windows's size doesn't change, no wxSizeEvent will
2753 normally be sent. Here we add an extra test if
2754 the client test has been changed and this will
2756 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2760 wxPrintf( "OnSize sent from " );
2761 if (GetClassInfo() && GetClassInfo()->GetClassName())
2762 wxPrintf( GetClassInfo()->GetClassName() );
2763 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2766 if (!m_nativeSizeEvent
)
2768 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2769 event
.SetEventObject( this );
2770 GetEventHandler()->ProcessEvent( event
);
2776 void wxWindowGTK::OnInternalIdle()
2778 // Update invalidated regions.
2781 // Synthetize activate events.
2782 if ( g_sendActivateEvent
!= -1 )
2784 bool activate
= g_sendActivateEvent
!= 0;
2787 g_sendActivateEvent
= -1;
2789 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2792 if ( g_activeFrameLostFocus
)
2794 if ( g_activeFrame
)
2796 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2797 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2798 event
.SetEventObject(g_activeFrame
);
2799 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2800 g_activeFrame
= NULL
;
2802 g_activeFrameLostFocus
= FALSE
;
2805 wxCursor cursor
= m_cursor
;
2806 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2810 /* I now set the cursor anew in every OnInternalIdle call
2811 as setting the cursor in a parent window also effects the
2812 windows above so that checking for the current cursor is
2817 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2819 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2821 if (!g_globalCursor
.Ok())
2822 cursor
= *wxSTANDARD_CURSOR
;
2824 window
= m_widget
->window
;
2825 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2826 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2832 GdkWindow
*window
= m_widget
->window
;
2833 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2834 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2842 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2844 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2846 if (width
) (*width
) = m_width
;
2847 if (height
) (*height
) = m_height
;
2850 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2852 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2856 SetSize( width
, height
);
2863 #ifndef __WXUNIVERSAL__
2864 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2866 /* when using GTK 1.2 we set the shadow border size to 2 */
2870 if (HasFlag(wxSIMPLE_BORDER
))
2872 /* when using GTK 1.2 we set the simple border size to 1 */
2876 #endif // __WXUNIVERSAL__
2880 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2882 GtkRequisition vscroll_req
;
2883 vscroll_req
.width
= 2;
2884 vscroll_req
.height
= 2;
2885 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2886 (scroll_window
->vscrollbar
, &vscroll_req
);
2888 GtkRequisition hscroll_req
;
2889 hscroll_req
.width
= 2;
2890 hscroll_req
.height
= 2;
2891 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2892 (scroll_window
->hscrollbar
, &hscroll_req
);
2894 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2896 if (scroll_window
->vscrollbar_visible
)
2898 dw
+= vscroll_req
.width
;
2899 dw
+= scroll_class
->scrollbar_spacing
;
2902 if (scroll_window
->hscrollbar_visible
)
2904 dh
+= hscroll_req
.height
;
2905 dh
+= scroll_class
->scrollbar_spacing
;
2909 SetSize( width
+dw
, height
+dh
);
2913 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2915 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2919 if (width
) (*width
) = m_width
;
2920 if (height
) (*height
) = m_height
;
2927 #ifndef __WXUNIVERSAL__
2928 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2930 /* when using GTK 1.2 we set the shadow border size to 2 */
2934 if (HasFlag(wxSIMPLE_BORDER
))
2936 /* when using GTK 1.2 we set the simple border size to 1 */
2940 #endif // __WXUNIVERSAL__
2944 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2946 GtkRequisition vscroll_req
;
2947 vscroll_req
.width
= 2;
2948 vscroll_req
.height
= 2;
2949 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2950 (scroll_window
->vscrollbar
, &vscroll_req
);
2952 GtkRequisition hscroll_req
;
2953 hscroll_req
.width
= 2;
2954 hscroll_req
.height
= 2;
2955 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2956 (scroll_window
->hscrollbar
, &hscroll_req
);
2958 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2960 if (scroll_window
->vscrollbar_visible
)
2962 dw
+= vscroll_req
.width
;
2963 dw
+= scroll_class
->scrollbar_spacing
;
2966 if (scroll_window
->hscrollbar_visible
)
2968 dh
+= hscroll_req
.height
;
2969 dh
+= scroll_class
->scrollbar_spacing
;
2973 if (width
) (*width
) = m_width
- dw
;
2974 if (height
) (*height
) = m_height
- dh
;
2978 printf( "GetClientSize, name %s ", GetName().c_str() );
2979 if (width) printf( " width = %d", (*width) );
2980 if (height) printf( " height = %d", (*height) );
2985 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2987 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2991 if (m_parent
&& m_parent
->m_wxwindow
)
2993 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2994 dx
= pizza
->xoffset
;
2995 dy
= pizza
->yoffset
;
2998 if (x
) (*x
) = m_x
- dx
;
2999 if (y
) (*y
) = m_y
- dy
;
3002 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3004 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3006 if (!m_widget
->window
) return;
3008 GdkWindow
*source
= (GdkWindow
*) NULL
;
3010 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3012 source
= m_widget
->window
;
3016 gdk_window_get_origin( source
, &org_x
, &org_y
);
3020 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3022 org_x
+= m_widget
->allocation
.x
;
3023 org_y
+= m_widget
->allocation
.y
;
3031 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3033 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3035 if (!m_widget
->window
) return;
3037 GdkWindow
*source
= (GdkWindow
*) NULL
;
3039 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3041 source
= m_widget
->window
;
3045 gdk_window_get_origin( source
, &org_x
, &org_y
);
3049 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3051 org_x
+= m_widget
->allocation
.x
;
3052 org_y
+= m_widget
->allocation
.y
;
3060 bool wxWindowGTK::Show( bool show
)
3062 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3064 if (!wxWindowBase::Show(show
))
3071 gtk_widget_show( m_widget
);
3073 gtk_widget_hide( m_widget
);
3078 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3080 win
->OnParentEnable(enable
);
3082 // Recurse, so that children have the opportunity to Do The Right Thing
3083 // and reset colours that have been messed up by a parent's (really ancestor's)
3085 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3087 node
= node
->GetNext() )
3089 wxWindow
*child
= node
->GetData();
3090 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3091 wxWindowNotifyEnable(child
, enable
);
3095 bool wxWindowGTK::Enable( bool enable
)
3097 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3099 if (!wxWindowBase::Enable(enable
))
3105 gtk_widget_set_sensitive( m_widget
, enable
);
3107 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3109 wxWindowNotifyEnable(this, enable
);
3114 int wxWindowGTK::GetCharHeight() const
3116 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3118 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3120 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3122 return font
->ascent
+ font
->descent
;
3125 int wxWindowGTK::GetCharWidth() const
3127 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3129 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3131 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3133 return gdk_string_width( font
, "H" );
3136 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3140 int *externalLeading
,
3141 const wxFont
*theFont
) const
3143 wxFont fontToUse
= m_font
;
3144 if (theFont
) fontToUse
= *theFont
;
3146 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3148 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3149 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3150 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3151 if (descent
) (*descent
) = font
->descent
;
3152 if (externalLeading
) (*externalLeading
) = 0; // ??
3155 void wxWindowGTK::SetFocus()
3157 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3161 // don't do anything if we already have focus
3167 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3169 gtk_widget_grab_focus (m_wxwindow
);
3174 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3176 if (!GTK_WIDGET_REALIZED(m_widget
))
3178 // we can't set the focus to the widget now so we remember that
3179 // it should be focused and will do it later, during the idle
3180 // time, as soon as we can
3181 wxLogTrace(TRACE_FOCUS
,
3182 _T("Delaying setting focus to %s(%s)"),
3183 GetClassInfo()->GetClassName(), GetLabel().c_str());
3185 g_delayedFocus
= this;
3189 wxLogTrace(TRACE_FOCUS
,
3190 _T("Setting focus to %s(%s)"),
3191 GetClassInfo()->GetClassName(), GetLabel().c_str());
3193 gtk_widget_grab_focus (m_widget
);
3196 else if (GTK_IS_CONTAINER(m_widget
))
3198 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3202 wxLogTrace(TRACE_FOCUS
,
3203 _T("Can't set focus to %s(%s)"),
3204 GetClassInfo()->GetClassName(), GetLabel().c_str());
3209 bool wxWindowGTK::AcceptsFocus() const
3211 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3214 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3216 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3218 wxWindowGTK
*oldParent
= m_parent
,
3219 *newParent
= (wxWindowGTK
*)newParentBase
;
3221 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3223 if ( !wxWindowBase::Reparent(newParent
) )
3226 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3228 /* prevent GTK from deleting the widget arbitrarily */
3229 gtk_widget_ref( m_widget
);
3233 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3236 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3240 /* insert GTK representation */
3241 (*(newParent
->m_insertCallback
))(newParent
, this);
3244 /* reverse: prevent GTK from deleting the widget arbitrarily */
3245 gtk_widget_unref( m_widget
);
3250 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3252 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3254 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3256 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3261 /* insert GTK representation */
3262 (*m_insertCallback
)(this, child
);
3265 void wxWindowGTK::Raise()
3267 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3269 if (!m_widget
->window
) return;
3271 gdk_window_raise( m_widget
->window
);
3274 void wxWindowGTK::Lower()
3276 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3278 if (!m_widget
->window
) return;
3280 gdk_window_lower( m_widget
->window
);
3283 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3285 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3287 if (cursor
== m_cursor
)
3291 wxapp_install_idle_handler();
3293 if (cursor
== wxNullCursor
)
3294 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3296 return wxWindowBase::SetCursor( cursor
);
3299 void wxWindowGTK::WarpPointer( int x
, int y
)
3301 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3303 // We provide this function ourselves as it is
3304 // missing in GDK (top of this file).
3306 GdkWindow
*window
= (GdkWindow
*) NULL
;
3308 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3310 window
= GetConnectWidget()->window
;
3313 gdk_window_warp_pointer( window
, x
, y
);
3316 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3318 if (!m_widget
) return;
3319 if (!m_widget
->window
) return;
3323 wxapp_install_idle_handler();
3325 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3329 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3330 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3334 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3335 m_clearRegion
.Clear();
3336 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3344 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3345 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3349 GdkRectangle gdk_rect
;
3350 gdk_rect
.x
= rect
->x
;
3351 gdk_rect
.y
= rect
->y
;
3352 gdk_rect
.width
= rect
->width
;
3353 gdk_rect
.height
= rect
->height
;
3354 gtk_widget_draw( m_widget
, &gdk_rect
);
3361 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3362 m_updateRegion
.Clear();
3363 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3367 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3375 GdkRectangle gdk_rect
;
3376 gdk_rect
.x
= rect
->x
;
3377 gdk_rect
.y
= rect
->y
;
3378 gdk_rect
.width
= rect
->width
;
3379 gdk_rect
.height
= rect
->height
;
3380 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3384 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3390 void wxWindowGTK::Update()
3395 void wxWindowGTK::GtkUpdate()
3398 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3399 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3402 if (!m_updateRegion
.IsEmpty())
3403 GtkSendPaintEvents();
3406 void wxWindowGTK::GtkSendPaintEvents()
3410 m_clearRegion
.Clear();
3411 m_updateRegion
.Clear();
3415 // widget to draw on
3416 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3418 // Clip to paint region in wxClientDC
3419 m_clipPaintRegion
= TRUE
;
3421 if (GetThemeEnabled())
3423 // find ancestor from which to steal background
3424 wxWindow
*parent
= GetParent();
3425 while (parent
&& !parent
->IsTopLevel())
3426 parent
= parent
->GetParent();
3428 parent
= (wxWindow
*)this;
3430 wxRegionIterator
upd( m_updateRegion
);
3434 rect
.x
= upd
.GetX();
3435 rect
.y
= upd
.GetY();
3436 rect
.width
= upd
.GetWidth();
3437 rect
.height
= upd
.GetHeight();
3439 gtk_paint_flat_box( parent
->m_widget
->style
,
3452 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3454 wxWindowDC
dc( (wxWindow
*)this );
3455 dc
.SetClippingRegion( m_clearRegion
);
3457 wxEraseEvent
erase_event( GetId(), &dc
);
3458 erase_event
.SetEventObject( this );
3460 if (!GetEventHandler()->ProcessEvent(erase_event
))
3464 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3465 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3467 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3469 wxRegionIterator
upd( m_clearRegion
);
3472 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3473 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3477 m_clearRegion
.Clear();
3480 wxNcPaintEvent
nc_paint_event( GetId() );
3481 nc_paint_event
.SetEventObject( this );
3482 GetEventHandler()->ProcessEvent( nc_paint_event
);
3484 wxPaintEvent
paint_event( GetId() );
3485 paint_event
.SetEventObject( this );
3486 GetEventHandler()->ProcessEvent( paint_event
);
3488 m_clipPaintRegion
= FALSE
;
3490 #ifndef __WXUNIVERSAL__
3492 // The following code will result in all window-less widgets
3493 // being redrawn because the wxWindows class is allowed to
3494 // paint over the window-less widgets.
3496 GList
*children
= pizza
->children
;
3499 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3500 children
= children
->next
;
3502 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3503 GTK_WIDGET_DRAWABLE (child
->widget
))
3505 // Get intersection of widget area and update region
3506 wxRegion
region( m_updateRegion
);
3508 GdkEventExpose gdk_event
;
3509 gdk_event
.type
= GDK_EXPOSE
;
3510 gdk_event
.window
= pizza
->bin_window
;
3511 gdk_event
.count
= 0;
3513 wxRegionIterator
upd( m_updateRegion
);
3517 rect
.x
= upd
.GetX();
3518 rect
.y
= upd
.GetY();
3519 rect
.width
= upd
.GetWidth();
3520 rect
.height
= upd
.GetHeight();
3522 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3524 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3534 m_updateRegion
.Clear();
3537 void wxWindowGTK::Clear()
3539 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3541 if (m_wxwindow
&& m_wxwindow
->window
)
3543 m_clearRegion
.Clear();
3544 wxSize
size( GetClientSize() );
3545 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3547 // Better do this in idle?
3553 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3555 wxWindowBase::DoSetToolTip(tip
);
3558 m_tooltip
->Apply( (wxWindow
*)this );
3561 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3563 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3565 #endif // wxUSE_TOOLTIPS
3567 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3569 GdkWindow
*window
= (GdkWindow
*) NULL
;
3571 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3573 window
= GetConnectWidget()->window
;
3577 // We need the pixel value e.g. for background clearing.
3578 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3582 // wxMSW doesn't clear the window here, either.
3583 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3589 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3591 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3593 if (!wxWindowBase::SetBackgroundColour(colour
))
3596 GdkWindow
*window
= (GdkWindow
*) NULL
;
3598 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3600 window
= GetConnectWidget()->window
;
3604 // indicate that a new style has been set
3605 // but it couldn't get applied as the
3606 // widget hasn't been realized yet.
3607 m_delayedBackgroundColour
= TRUE
;
3612 GtkSetBackgroundColour( colour
);
3618 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3620 GdkWindow
*window
= (GdkWindow
*) NULL
;
3622 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3624 window
= GetConnectWidget()->window
;
3631 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3633 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3635 if (!wxWindowBase::SetForegroundColour(colour
))
3637 // don't leave if the GTK widget has just
3639 if (!m_delayedForegroundColour
) return FALSE
;
3642 GdkWindow
*window
= (GdkWindow
*) NULL
;
3644 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3646 window
= GetConnectWidget()->window
;
3650 // indicate that a new style has been set
3651 // but it couldn't get applied as the
3652 // widget hasn't been realized yet.
3653 m_delayedForegroundColour
= TRUE
;
3657 GtkSetForegroundColour( colour
);
3663 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3667 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3669 // FIXME: no more klass in 2.0
3671 remake
->klass
= m_widgetStyle
->klass
;
3674 gtk_style_unref( m_widgetStyle
);
3675 m_widgetStyle
= remake
;
3679 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3682 def
= gtk_widget_get_default_style();
3684 m_widgetStyle
= gtk_style_copy( def
);
3686 // FIXME: no more klass in 2.0
3688 m_widgetStyle
->klass
= def
->klass
;
3692 return m_widgetStyle
;
3695 void wxWindowGTK::SetWidgetStyle()
3697 #if DISABLE_STYLE_IF_BROKEN_THEME
3698 if (m_widget
->style
->engine_data
)
3700 static bool s_warningPrinted
= FALSE
;
3701 if (!s_warningPrinted
)
3703 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3704 s_warningPrinted
= TRUE
;
3706 m_widgetStyle
= m_widget
->style
;
3711 GtkStyle
*style
= GetWidgetStyle();
3713 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3715 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3718 if (m_foregroundColour
.Ok())
3720 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3721 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3723 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3724 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3725 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3729 // Try to restore the gtk default style. This is still a little
3730 // oversimplified for what is probably really needed here for controls
3731 // other than buttons, but is better than not being able to (re)set a
3732 // control's foreground colour to *wxBLACK -- RL
3733 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3736 def
= gtk_widget_get_default_style();
3738 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3739 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3740 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3744 if (m_backgroundColour
.Ok())
3746 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3747 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3749 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3750 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3751 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3752 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3753 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3754 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3755 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3756 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3760 // Try to restore the gtk default style. This is still a little
3761 // oversimplified for what is probably really needed here for controls
3762 // other than buttons, but is better than not being able to (re)set a
3763 // control's background colour to default grey and means resetting a
3764 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3766 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3769 def
= gtk_widget_get_default_style();
3771 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3772 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3773 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3774 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3775 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3776 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3777 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3778 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3783 void wxWindowGTK::ApplyWidgetStyle()
3787 //-----------------------------------------------------------------------------
3788 // Pop-up menu stuff
3789 //-----------------------------------------------------------------------------
3791 #if wxUSE_MENUS_NATIVE
3794 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3796 *is_waiting
= FALSE
;
3799 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3801 menu
->SetInvokingWindow( win
);
3802 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3805 wxMenuItem
*menuitem
= node
->GetData();
3806 if (menuitem
->IsSubMenu())
3808 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3811 node
= node
->GetNext();
3815 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3816 // wxPopupMenuPositionCallback()
3818 // should be safe even in the MT case as the user can hardly popup 2 menus
3819 // simultaneously, can he?
3820 static gint gs_pop_x
= 0;
3821 static gint gs_pop_y
= 0;
3823 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3826 gboolean
* WXUNUSED(whatever
),
3828 gpointer
WXUNUSED(user_data
) )
3830 // ensure that the menu appears entirely on screen
3832 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3834 wxSize sizeScreen
= wxGetDisplaySize();
3836 gint xmax
= sizeScreen
.x
- req
.width
,
3837 ymax
= sizeScreen
.y
- req
.height
;
3839 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3840 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3843 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3845 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3847 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3849 SetInvokingWindow( menu
, this );
3855 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3857 bool is_waiting
= TRUE
;
3859 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3861 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3862 (gpointer
)&is_waiting
);
3865 GTK_MENU(menu
->m_menu
),
3866 (GtkWidget
*) NULL
, // parent menu shell
3867 (GtkWidget
*) NULL
, // parent menu item
3868 wxPopupMenuPositionCallback
, // function to position it
3869 NULL
, // client data
3870 0, // button used to activate it
3871 gs_timeLastClick
// the time of activation
3876 while (gtk_events_pending())
3877 gtk_main_iteration();
3883 #endif // wxUSE_MENUS_NATIVE
3885 #if wxUSE_DRAG_AND_DROP
3887 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3889 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3891 GtkWidget
*dnd_widget
= GetConnectWidget();
3893 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3895 if (m_dropTarget
) delete m_dropTarget
;
3896 m_dropTarget
= dropTarget
;
3898 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3901 #endif // wxUSE_DRAG_AND_DROP
3903 GtkWidget
* wxWindowGTK::GetConnectWidget()
3905 GtkWidget
*connect_widget
= m_widget
;
3906 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3908 return connect_widget
;
3911 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3914 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3916 return (window
== m_widget
->window
);
3919 bool wxWindowGTK::SetFont( const wxFont
&font
)
3921 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3923 if (!wxWindowBase::SetFont(font
))
3928 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3929 if ( sysbg
== m_backgroundColour
)
3931 m_backgroundColour
= wxNullColour
;
3933 m_backgroundColour
= sysbg
;
3943 void wxWindowGTK::DoCaptureMouse()
3945 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3947 GdkWindow
*window
= (GdkWindow
*) NULL
;
3949 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3951 window
= GetConnectWidget()->window
;
3953 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3955 wxCursor
* cursor
= & m_cursor
;
3957 cursor
= wxSTANDARD_CURSOR
;
3959 gdk_pointer_grab( window
, FALSE
,
3961 (GDK_BUTTON_PRESS_MASK
|
3962 GDK_BUTTON_RELEASE_MASK
|
3963 GDK_POINTER_MOTION_HINT_MASK
|
3964 GDK_POINTER_MOTION_MASK
),
3966 cursor
->GetCursor(),
3967 (guint32
)GDK_CURRENT_TIME
);
3968 g_captureWindow
= this;
3969 g_captureWindowHasMouse
= TRUE
;
3972 void wxWindowGTK::DoReleaseMouse()
3974 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3976 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3978 g_captureWindow
= (wxWindowGTK
*) NULL
;
3980 GdkWindow
*window
= (GdkWindow
*) NULL
;
3982 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3984 window
= GetConnectWidget()->window
;
3989 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3993 wxWindow
*wxWindowBase::GetCapture()
3995 return (wxWindow
*)g_captureWindow
;
3998 bool wxWindowGTK::IsRetained() const
4003 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4004 int range
, bool refresh
)
4006 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4008 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4010 m_hasScrolling
= TRUE
;
4012 if (orient
== wxHORIZONTAL
)
4014 float fpos
= (float)pos
;
4015 float frange
= (float)range
;
4016 float fthumb
= (float)thumbVisible
;
4017 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4018 if (fpos
< 0.0) fpos
= 0.0;
4020 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4021 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4023 SetScrollPos( orient
, pos
, refresh
);
4027 m_oldHorizontalPos
= fpos
;
4029 m_hAdjust
->lower
= 0.0;
4030 m_hAdjust
->upper
= frange
;
4031 m_hAdjust
->value
= fpos
;
4032 m_hAdjust
->step_increment
= 1.0;
4033 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4034 m_hAdjust
->page_size
= fthumb
;
4038 float fpos
= (float)pos
;
4039 float frange
= (float)range
;
4040 float fthumb
= (float)thumbVisible
;
4041 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4042 if (fpos
< 0.0) fpos
= 0.0;
4044 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4045 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4047 SetScrollPos( orient
, pos
, refresh
);
4051 m_oldVerticalPos
= fpos
;
4053 m_vAdjust
->lower
= 0.0;
4054 m_vAdjust
->upper
= frange
;
4055 m_vAdjust
->value
= fpos
;
4056 m_vAdjust
->step_increment
= 1.0;
4057 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4058 m_vAdjust
->page_size
= fthumb
;
4061 if (orient
== wxHORIZONTAL
)
4062 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4064 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4067 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4069 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4071 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4073 if (orient
== wxHORIZONTAL
)
4075 float fpos
= (float)pos
;
4076 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4077 if (fpos
< 0.0) fpos
= 0.0;
4078 m_oldHorizontalPos
= fpos
;
4080 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4081 m_hAdjust
->value
= fpos
;
4085 float fpos
= (float)pos
;
4086 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4087 if (fpos
< 0.0) fpos
= 0.0;
4088 m_oldVerticalPos
= fpos
;
4090 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4091 m_vAdjust
->value
= fpos
;
4094 if (m_wxwindow
->window
)
4096 if (orient
== wxHORIZONTAL
)
4098 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4099 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4101 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4103 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4104 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4108 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4109 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4111 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4113 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4114 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4119 int wxWindowGTK::GetScrollThumb( int orient
) const
4121 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4123 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4125 if (orient
== wxHORIZONTAL
)
4126 return (int)(m_hAdjust
->page_size
+0.5);
4128 return (int)(m_vAdjust
->page_size
+0.5);
4131 int wxWindowGTK::GetScrollPos( int orient
) const
4133 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4135 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4137 if (orient
== wxHORIZONTAL
)
4138 return (int)(m_hAdjust
->value
+0.5);
4140 return (int)(m_vAdjust
->value
+0.5);
4143 int wxWindowGTK::GetScrollRange( int orient
) const
4145 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4147 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4149 if (orient
== wxHORIZONTAL
)
4150 return (int)(m_hAdjust
->upper
+0.5);
4152 return (int)(m_vAdjust
->upper
+0.5);
4155 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4157 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4159 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4161 // No scrolling requested.
4162 if ((dx
== 0) && (dy
== 0)) return;
4165 if (!m_updateRegion
.IsEmpty())
4167 m_updateRegion
.Offset( dx
, dy
);
4171 GetClientSize( &cw
, &ch
);
4172 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4175 if (!m_clearRegion
.IsEmpty())
4177 m_clearRegion
.Offset( dx
, dy
);
4181 GetClientSize( &cw
, &ch
);
4182 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4184 m_clipPaintRegion
= TRUE
;
4186 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4188 m_clipPaintRegion
= FALSE
;
4191 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4193 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4194 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4201 // Find the wxWindow at the current mouse position, also returning the mouse
4203 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4205 pt
= wxGetMousePosition();
4206 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4210 // Get the current mouse position.
4211 wxPoint
wxGetMousePosition()
4213 /* This crashes when used within wxHelpContext,
4214 so we have to use the X-specific implementation below.
4216 GdkModifierType *mask;
4217 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4219 return wxPoint(x, y);
4223 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4225 return wxPoint(-999, -999);
4227 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4228 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4229 Window rootReturn
, childReturn
;
4230 int rootX
, rootY
, winX
, winY
;
4231 unsigned int maskReturn
;
4233 XQueryPointer (display
,
4237 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4238 return wxPoint(rootX
, rootY
);
4242 // ----------------------------------------------------------------------------
4244 // ----------------------------------------------------------------------------
4246 class wxWinModule
: public wxModule
4253 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4256 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4258 bool wxWinModule::OnInit()
4260 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4261 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4266 void wxWinModule::OnExit()
4269 gdk_gc_unref( g_eraseGC
);