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 static void gtk_window_destroy_callback( GtkWidget
* widget
, wxWindow
*win
)
2019 wxWindowDestroyEvent
event(win
);
2020 win
->GetEventHandler()->ProcessEvent(event
);
2023 //-----------------------------------------------------------------------------
2024 // "realize" from m_widget
2025 //-----------------------------------------------------------------------------
2027 /* We cannot set colours and fonts before the widget has
2028 been realized, so we do this directly after realization. */
2031 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2036 wxapp_install_idle_handler();
2038 if (win
->m_delayedBackgroundColour
)
2039 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2041 if (win
->m_delayedForegroundColour
)
2042 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2044 wxWindowCreateEvent
event( win
);
2045 event
.SetEventObject( win
);
2046 win
->GetEventHandler()->ProcessEvent( event
);
2051 //-----------------------------------------------------------------------------
2053 //-----------------------------------------------------------------------------
2056 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2057 GtkAllocation
*WXUNUSED(alloc
),
2061 wxapp_install_idle_handler();
2063 if (!win
->m_hasScrolling
) return;
2065 int client_width
= 0;
2066 int client_height
= 0;
2067 win
->GetClientSize( &client_width
, &client_height
);
2068 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2071 win
->m_oldClientWidth
= client_width
;
2072 win
->m_oldClientHeight
= client_height
;
2074 if (!win
->m_nativeSizeEvent
)
2076 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2077 event
.SetEventObject( win
);
2078 win
->GetEventHandler()->ProcessEvent( event
);
2084 #define WXUNUSED_UNLESS_XIM(param) param
2086 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2089 /* Resize XIM window */
2092 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2093 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2094 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2097 wxapp_install_idle_handler();
2103 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2107 gdk_window_get_size (widget
->window
, &width
, &height
);
2108 win
->m_icattr
->preedit_area
.width
= width
;
2109 win
->m_icattr
->preedit_area
.height
= height
;
2110 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2115 //-----------------------------------------------------------------------------
2116 // "realize" from m_wxwindow
2117 //-----------------------------------------------------------------------------
2119 /* Initialize XIM support */
2122 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2123 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2126 wxapp_install_idle_handler();
2129 if (win
->m_ic
) return FALSE
;
2130 if (!widget
) return FALSE
;
2131 if (!gdk_im_ready()) return FALSE
;
2133 win
->m_icattr
= gdk_ic_attr_new();
2134 if (!win
->m_icattr
) return FALSE
;
2138 GdkColormap
*colormap
;
2139 GdkICAttr
*attr
= win
->m_icattr
;
2140 unsigned attrmask
= GDK_IC_ALL_REQ
;
2142 GdkIMStyle supported_style
= (GdkIMStyle
)
2143 (GDK_IM_PREEDIT_NONE
|
2144 GDK_IM_PREEDIT_NOTHING
|
2145 GDK_IM_PREEDIT_POSITION
|
2146 GDK_IM_STATUS_NONE
|
2147 GDK_IM_STATUS_NOTHING
);
2149 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2150 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2152 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2153 attr
->client_window
= widget
->window
;
2155 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2156 gtk_widget_get_default_colormap ())
2158 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2159 attr
->preedit_colormap
= colormap
;
2162 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2163 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2164 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2165 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2167 switch (style
& GDK_IM_PREEDIT_MASK
)
2169 case GDK_IM_PREEDIT_POSITION
:
2170 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2172 g_warning ("over-the-spot style requires fontset");
2176 gdk_window_get_size (widget
->window
, &width
, &height
);
2178 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2179 attr
->spot_location
.x
= 0;
2180 attr
->spot_location
.y
= height
;
2181 attr
->preedit_area
.x
= 0;
2182 attr
->preedit_area
.y
= 0;
2183 attr
->preedit_area
.width
= width
;
2184 attr
->preedit_area
.height
= height
;
2185 attr
->preedit_fontset
= widget
->style
->font
;
2190 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2192 if (win
->m_ic
== NULL
)
2193 g_warning ("Can't create input context.");
2196 mask
= gdk_window_get_events (widget
->window
);
2197 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2198 gdk_window_set_events (widget
->window
, mask
);
2200 if (GTK_WIDGET_HAS_FOCUS(widget
))
2201 gdk_im_begin (win
->m_ic
, widget
->window
);
2208 //-----------------------------------------------------------------------------
2209 // InsertChild for wxWindowGTK.
2210 //-----------------------------------------------------------------------------
2212 /* Callback for wxWindowGTK. This very strange beast has to be used because
2213 * C++ has no virtual methods in a constructor. We have to emulate a
2214 * virtual function here as wxNotebook requires a different way to insert
2215 * a child in it. I had opted for creating a wxNotebookPage window class
2216 * which would have made this superfluous (such in the MDI window system),
2217 * but no-one was listening to me... */
2219 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2221 /* the window might have been scrolled already, do we
2222 have to adapt the position */
2223 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2224 child
->m_x
+= pizza
->xoffset
;
2225 child
->m_y
+= pizza
->yoffset
;
2227 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2228 GTK_WIDGET(child
->m_widget
),
2235 //-----------------------------------------------------------------------------
2237 //-----------------------------------------------------------------------------
2239 wxWindow
*wxGetActiveWindow()
2241 return wxWindow::FindFocus();
2244 //-----------------------------------------------------------------------------
2246 //-----------------------------------------------------------------------------
2248 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2250 #ifdef __WXUNIVERSAL__
2251 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2253 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2254 #endif // __WXUNIVERSAL__/__WXGTK__
2256 void wxWindowGTK::Init()
2262 m_widget
= (GtkWidget
*) NULL
;
2263 m_wxwindow
= (GtkWidget
*) NULL
;
2264 m_focusWidget
= (GtkWidget
*) NULL
;
2274 m_needParent
= TRUE
;
2275 m_isBeingDeleted
= FALSE
;
2278 m_nativeSizeEvent
= FALSE
;
2280 m_hasScrolling
= FALSE
;
2281 m_isScrolling
= FALSE
;
2283 m_hAdjust
= (GtkAdjustment
*) NULL
;
2284 m_vAdjust
= (GtkAdjustment
*) NULL
;
2285 m_oldHorizontalPos
= 0.0;
2286 m_oldVerticalPos
= 0.0;
2289 m_widgetStyle
= (GtkStyle
*) NULL
;
2291 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2293 m_acceptsFocus
= FALSE
;
2296 m_clipPaintRegion
= FALSE
;
2298 m_cursor
= *wxSTANDARD_CURSOR
;
2300 m_delayedForegroundColour
= FALSE
;
2301 m_delayedBackgroundColour
= FALSE
;
2304 m_ic
= (GdkIC
*) NULL
;
2305 m_icattr
= (GdkICAttr
*) NULL
;
2309 wxWindowGTK::wxWindowGTK()
2314 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2319 const wxString
&name
)
2323 Create( parent
, id
, pos
, size
, style
, name
);
2326 bool wxWindowGTK::Create( wxWindow
*parent
,
2331 const wxString
&name
)
2333 if (!PreCreation( parent
, pos
, size
) ||
2334 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2336 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2340 m_insertCallback
= wxInsertChildInWindow
;
2342 // always needed for background clearing
2343 m_delayedBackgroundColour
= TRUE
;
2345 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2346 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2348 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2350 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2351 scroll_class
->scrollbar_spacing
= 0;
2353 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2355 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2356 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2358 m_wxwindow
= gtk_pizza_new();
2360 #ifndef __WXUNIVERSAL__
2361 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2363 if (HasFlag(wxRAISED_BORDER
))
2365 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2367 else if (HasFlag(wxSUNKEN_BORDER
))
2369 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2371 else if (HasFlag(wxSIMPLE_BORDER
))
2373 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2377 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2379 #endif // __WXUNIVERSAL__
2381 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2383 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2384 m_acceptsFocus
= TRUE
;
2386 // I _really_ don't want scrollbars in the beginning
2387 m_vAdjust
->lower
= 0.0;
2388 m_vAdjust
->upper
= 1.0;
2389 m_vAdjust
->value
= 0.0;
2390 m_vAdjust
->step_increment
= 1.0;
2391 m_vAdjust
->page_increment
= 1.0;
2392 m_vAdjust
->page_size
= 5.0;
2393 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2394 m_hAdjust
->lower
= 0.0;
2395 m_hAdjust
->upper
= 1.0;
2396 m_hAdjust
->value
= 0.0;
2397 m_hAdjust
->step_increment
= 1.0;
2398 m_hAdjust
->page_increment
= 1.0;
2399 m_hAdjust
->page_size
= 5.0;
2400 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2402 // these handlers block mouse events to any window during scrolling such as
2403 // motion events and prevent GTK and wxWindows from fighting over where the
2406 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2407 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2409 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2410 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2412 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2413 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2415 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2416 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2418 // these handlers get notified when screen updates are required either when
2419 // scrolling or when the window size (and therefore scrollbar configuration)
2422 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2423 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2424 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2425 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2427 gtk_widget_show( m_wxwindow
);
2430 m_parent
->DoAddChild( this );
2432 m_focusWidget
= m_wxwindow
;
2441 wxWindowGTK::~wxWindowGTK()
2443 if (g_focusWindow
== this)
2444 g_focusWindow
= NULL
;
2446 if (g_activeFrame
== this)
2447 g_activeFrame
= NULL
;
2449 if ( g_delayedFocus
== this )
2450 g_delayedFocus
= NULL
;
2452 m_isBeingDeleted
= TRUE
;
2461 m_parent
->RemoveChild( this );
2465 gdk_ic_destroy (m_ic
);
2467 gdk_ic_attr_destroy (m_icattr
);
2472 #if DISABLE_STYLE_IF_BROKEN_THEME
2473 // don't delete if it's a pixmap theme style
2474 if (!m_widgetStyle
->engine_data
)
2475 gtk_style_unref( m_widgetStyle
);
2477 m_widgetStyle
= (GtkStyle
*) NULL
;
2482 gtk_widget_destroy( m_wxwindow
);
2483 m_wxwindow
= (GtkWidget
*) NULL
;
2488 gtk_widget_destroy( m_widget
);
2489 m_widget
= (GtkWidget
*) NULL
;
2493 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2495 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2497 /* this turns -1 into 20 so that a minimal window is
2498 visible even although -1,-1 has been given as the
2499 size of the window. the same trick is used in other
2500 ports and should make debugging easier */
2501 m_width
= WidthDefault(size
.x
);
2502 m_height
= HeightDefault(size
.y
);
2507 /* some reasonable defaults */
2512 m_x
= (gdk_screen_width () - m_width
) / 2;
2513 if (m_x
< 10) m_x
= 10;
2517 m_y
= (gdk_screen_height () - m_height
) / 2;
2518 if (m_y
< 10) m_y
= 10;
2525 void wxWindowGTK::PostCreation()
2527 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2533 // these get reported to wxWindows -> wxPaintEvent
2535 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2537 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2538 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2541 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2542 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2544 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2546 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2547 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2550 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2554 // these are called when the "sunken" or "raised" borders are drawn
2555 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2556 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2559 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2560 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2566 if (m_focusWidget
== NULL
)
2567 m_focusWidget
= m_widget
;
2569 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2570 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2572 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2573 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2575 // connect to the various key and mouse handlers
2577 GtkWidget
*connect_widget
= GetConnectWidget();
2579 ConnectWidget( connect_widget
);
2581 /* We cannot set colours, fonts and cursors before the widget has
2582 been realized, so we do this directly after realization */
2583 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2584 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2588 // Catch native resize events
2589 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2590 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2592 // Initialize XIM support
2593 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2594 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2596 // And resize XIM window
2597 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2598 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2601 if (!GTK_IS_COMBO(m_widget
))
2603 // This is needed if we want to add our windows into native
2604 // GTK control, such as the toolbar. With this callback, the
2605 // toolbar gets to know the correct size (the one set by the
2606 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2607 // when moving to GTK 2.0.
2608 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2609 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2615 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2617 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2618 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2620 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2621 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2623 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2624 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2626 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2627 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2629 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2630 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2632 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2633 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2635 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2636 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2638 // This keeps crashing on me. RR.
2640 // gtk_signal_connect( GTK_OBJECT(widget), "destroy",
2641 // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this );
2644 bool wxWindowGTK::Destroy()
2646 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2650 return wxWindowBase::Destroy();
2653 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2655 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2658 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2660 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2661 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2664 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2667 if (m_resizing
) return; /* I don't like recursions */
2670 int currentX
, currentY
;
2671 GetPosition(¤tX
, ¤tY
);
2676 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2678 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2680 /* don't set the size for children of wxNotebook, just take the values. */
2688 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2689 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2691 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2692 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2693 if (width
!= -1) m_width
= width
;
2694 if (height
!= -1) m_height
= height
;
2698 m_x
= x
+ pizza
->xoffset
;
2699 m_y
= y
+ pizza
->yoffset
;
2704 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2706 if (width
== -1) m_width
= 80;
2709 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2711 if (height
== -1) m_height
= 26;
2714 int minWidth
= GetMinWidth(),
2715 minHeight
= GetMinHeight(),
2716 maxWidth
= GetMaxWidth(),
2717 maxHeight
= GetMaxHeight();
2719 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2720 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2721 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2722 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2725 int bottom_border
= 0;
2728 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2730 /* the default button has a border around it */
2736 DoMoveWindow( m_x
-border
,
2739 m_height
+border
+bottom_border
);
2744 /* Sometimes the client area changes size without the
2745 whole windows's size changing, but if the whole
2746 windows's size doesn't change, no wxSizeEvent will
2747 normally be sent. Here we add an extra test if
2748 the client test has been changed and this will
2750 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2754 wxPrintf( "OnSize sent from " );
2755 if (GetClassInfo() && GetClassInfo()->GetClassName())
2756 wxPrintf( GetClassInfo()->GetClassName() );
2757 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2760 if (!m_nativeSizeEvent
)
2762 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2763 event
.SetEventObject( this );
2764 GetEventHandler()->ProcessEvent( event
);
2770 void wxWindowGTK::OnInternalIdle()
2772 // Update invalidated regions.
2775 // Synthetize activate events.
2776 if ( g_sendActivateEvent
!= -1 )
2778 bool activate
= g_sendActivateEvent
!= 0;
2781 g_sendActivateEvent
= -1;
2783 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2786 if ( g_activeFrameLostFocus
)
2788 if ( g_activeFrame
)
2790 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2791 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2792 event
.SetEventObject(g_activeFrame
);
2793 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2794 g_activeFrame
= NULL
;
2796 g_activeFrameLostFocus
= FALSE
;
2799 wxCursor cursor
= m_cursor
;
2800 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2804 /* I now set the cursor anew in every OnInternalIdle call
2805 as setting the cursor in a parent window also effects the
2806 windows above so that checking for the current cursor is
2811 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2813 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2815 if (!g_globalCursor
.Ok())
2816 cursor
= *wxSTANDARD_CURSOR
;
2818 window
= m_widget
->window
;
2819 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2820 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2826 GdkWindow
*window
= m_widget
->window
;
2827 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2828 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2836 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2838 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2840 if (width
) (*width
) = m_width
;
2841 if (height
) (*height
) = m_height
;
2844 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2846 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2850 SetSize( width
, height
);
2857 #ifndef __WXUNIVERSAL__
2858 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2860 /* when using GTK 1.2 we set the shadow border size to 2 */
2864 if (HasFlag(wxSIMPLE_BORDER
))
2866 /* when using GTK 1.2 we set the simple border size to 1 */
2870 #endif // __WXUNIVERSAL__
2874 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2876 GtkRequisition vscroll_req
;
2877 vscroll_req
.width
= 2;
2878 vscroll_req
.height
= 2;
2879 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2880 (scroll_window
->vscrollbar
, &vscroll_req
);
2882 GtkRequisition hscroll_req
;
2883 hscroll_req
.width
= 2;
2884 hscroll_req
.height
= 2;
2885 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2886 (scroll_window
->hscrollbar
, &hscroll_req
);
2888 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2890 if (scroll_window
->vscrollbar_visible
)
2892 dw
+= vscroll_req
.width
;
2893 dw
+= scroll_class
->scrollbar_spacing
;
2896 if (scroll_window
->hscrollbar_visible
)
2898 dh
+= hscroll_req
.height
;
2899 dh
+= scroll_class
->scrollbar_spacing
;
2903 SetSize( width
+dw
, height
+dh
);
2907 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2909 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2913 if (width
) (*width
) = m_width
;
2914 if (height
) (*height
) = m_height
;
2921 #ifndef __WXUNIVERSAL__
2922 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2924 /* when using GTK 1.2 we set the shadow border size to 2 */
2928 if (HasFlag(wxSIMPLE_BORDER
))
2930 /* when using GTK 1.2 we set the simple border size to 1 */
2934 #endif // __WXUNIVERSAL__
2938 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2940 GtkRequisition vscroll_req
;
2941 vscroll_req
.width
= 2;
2942 vscroll_req
.height
= 2;
2943 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2944 (scroll_window
->vscrollbar
, &vscroll_req
);
2946 GtkRequisition hscroll_req
;
2947 hscroll_req
.width
= 2;
2948 hscroll_req
.height
= 2;
2949 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2950 (scroll_window
->hscrollbar
, &hscroll_req
);
2952 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2954 if (scroll_window
->vscrollbar_visible
)
2956 dw
+= vscroll_req
.width
;
2957 dw
+= scroll_class
->scrollbar_spacing
;
2960 if (scroll_window
->hscrollbar_visible
)
2962 dh
+= hscroll_req
.height
;
2963 dh
+= scroll_class
->scrollbar_spacing
;
2967 if (width
) (*width
) = m_width
- dw
;
2968 if (height
) (*height
) = m_height
- dh
;
2972 printf( "GetClientSize, name %s ", GetName().c_str() );
2973 if (width) printf( " width = %d", (*width) );
2974 if (height) printf( " height = %d", (*height) );
2979 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2981 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2985 if (m_parent
&& m_parent
->m_wxwindow
)
2987 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2988 dx
= pizza
->xoffset
;
2989 dy
= pizza
->yoffset
;
2992 if (x
) (*x
) = m_x
- dx
;
2993 if (y
) (*y
) = m_y
- dy
;
2996 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2998 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3000 if (!m_widget
->window
) return;
3002 GdkWindow
*source
= (GdkWindow
*) NULL
;
3004 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3006 source
= m_widget
->window
;
3010 gdk_window_get_origin( source
, &org_x
, &org_y
);
3014 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3016 org_x
+= m_widget
->allocation
.x
;
3017 org_y
+= m_widget
->allocation
.y
;
3025 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3027 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3029 if (!m_widget
->window
) return;
3031 GdkWindow
*source
= (GdkWindow
*) NULL
;
3033 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3035 source
= m_widget
->window
;
3039 gdk_window_get_origin( source
, &org_x
, &org_y
);
3043 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3045 org_x
+= m_widget
->allocation
.x
;
3046 org_y
+= m_widget
->allocation
.y
;
3054 bool wxWindowGTK::Show( bool show
)
3056 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3058 if (!wxWindowBase::Show(show
))
3065 gtk_widget_show( m_widget
);
3067 gtk_widget_hide( m_widget
);
3072 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3074 win
->OnParentEnable(enable
);
3076 // Recurse, so that children have the opportunity to Do The Right Thing
3077 // and reset colours that have been messed up by a parent's (really ancestor's)
3079 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3081 node
= node
->GetNext() )
3083 wxWindow
*child
= node
->GetData();
3084 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3085 wxWindowNotifyEnable(child
, enable
);
3089 bool wxWindowGTK::Enable( bool enable
)
3091 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3093 if (!wxWindowBase::Enable(enable
))
3099 gtk_widget_set_sensitive( m_widget
, enable
);
3101 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3103 wxWindowNotifyEnable(this, enable
);
3108 int wxWindowGTK::GetCharHeight() const
3110 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3112 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3114 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3116 return font
->ascent
+ font
->descent
;
3119 int wxWindowGTK::GetCharWidth() const
3121 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3123 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3125 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3127 return gdk_string_width( font
, "H" );
3130 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3134 int *externalLeading
,
3135 const wxFont
*theFont
) const
3137 wxFont fontToUse
= m_font
;
3138 if (theFont
) fontToUse
= *theFont
;
3140 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3142 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3143 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3144 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3145 if (descent
) (*descent
) = font
->descent
;
3146 if (externalLeading
) (*externalLeading
) = 0; // ??
3149 void wxWindowGTK::SetFocus()
3151 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3155 // don't do anything if we already have focus
3161 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3163 gtk_widget_grab_focus (m_wxwindow
);
3168 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3170 if (!GTK_WIDGET_REALIZED(m_widget
))
3172 // we can't set the focus to the widget now so we remember that
3173 // it should be focused and will do it later, during the idle
3174 // time, as soon as we can
3175 wxLogTrace(TRACE_FOCUS
,
3176 _T("Delaying setting focus to %s(%s)"),
3177 GetClassInfo()->GetClassName(), GetLabel().c_str());
3179 g_delayedFocus
= this;
3183 wxLogTrace(TRACE_FOCUS
,
3184 _T("Setting focus to %s(%s)"),
3185 GetClassInfo()->GetClassName(), GetLabel().c_str());
3187 gtk_widget_grab_focus (m_widget
);
3190 else if (GTK_IS_CONTAINER(m_widget
))
3192 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3196 wxLogTrace(TRACE_FOCUS
,
3197 _T("Can't set focus to %s(%s)"),
3198 GetClassInfo()->GetClassName(), GetLabel().c_str());
3203 bool wxWindowGTK::AcceptsFocus() const
3205 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3208 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3210 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3212 wxWindowGTK
*oldParent
= m_parent
,
3213 *newParent
= (wxWindowGTK
*)newParentBase
;
3215 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3217 if ( !wxWindowBase::Reparent(newParent
) )
3220 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3222 /* prevent GTK from deleting the widget arbitrarily */
3223 gtk_widget_ref( m_widget
);
3227 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3230 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3234 /* insert GTK representation */
3235 (*(newParent
->m_insertCallback
))(newParent
, this);
3238 /* reverse: prevent GTK from deleting the widget arbitrarily */
3239 gtk_widget_unref( m_widget
);
3244 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3246 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3248 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3250 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3255 /* insert GTK representation */
3256 (*m_insertCallback
)(this, child
);
3259 void wxWindowGTK::Raise()
3261 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3263 if (!m_widget
->window
) return;
3265 gdk_window_raise( m_widget
->window
);
3268 void wxWindowGTK::Lower()
3270 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3272 if (!m_widget
->window
) return;
3274 gdk_window_lower( m_widget
->window
);
3277 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3279 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3281 if (cursor
== m_cursor
)
3285 wxapp_install_idle_handler();
3287 if (cursor
== wxNullCursor
)
3288 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3290 return wxWindowBase::SetCursor( cursor
);
3293 void wxWindowGTK::WarpPointer( int x
, int y
)
3295 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3297 // We provide this function ourselves as it is
3298 // missing in GDK (top of this file).
3300 GdkWindow
*window
= (GdkWindow
*) NULL
;
3302 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3304 window
= GetConnectWidget()->window
;
3307 gdk_window_warp_pointer( window
, x
, y
);
3310 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3312 if (!m_widget
) return;
3313 if (!m_widget
->window
) return;
3317 wxapp_install_idle_handler();
3319 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3323 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3324 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3328 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3329 m_clearRegion
.Clear();
3330 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3338 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3339 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3343 GdkRectangle gdk_rect
;
3344 gdk_rect
.x
= rect
->x
;
3345 gdk_rect
.y
= rect
->y
;
3346 gdk_rect
.width
= rect
->width
;
3347 gdk_rect
.height
= rect
->height
;
3348 gtk_widget_draw( m_widget
, &gdk_rect
);
3355 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3356 m_updateRegion
.Clear();
3357 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3361 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3369 GdkRectangle gdk_rect
;
3370 gdk_rect
.x
= rect
->x
;
3371 gdk_rect
.y
= rect
->y
;
3372 gdk_rect
.width
= rect
->width
;
3373 gdk_rect
.height
= rect
->height
;
3374 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3378 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3384 void wxWindowGTK::Update()
3389 void wxWindowGTK::GtkUpdate()
3392 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3393 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3396 if (!m_updateRegion
.IsEmpty())
3397 GtkSendPaintEvents();
3400 void wxWindowGTK::GtkSendPaintEvents()
3404 m_clearRegion
.Clear();
3405 m_updateRegion
.Clear();
3409 // widget to draw on
3410 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3412 // Clip to paint region in wxClientDC
3413 m_clipPaintRegion
= TRUE
;
3415 if (GetThemeEnabled())
3417 // find ancestor from which to steal background
3418 wxWindow
*parent
= GetParent();
3419 while (parent
&& !parent
->IsTopLevel())
3420 parent
= parent
->GetParent();
3422 parent
= (wxWindow
*)this;
3424 wxRegionIterator
upd( m_updateRegion
);
3428 rect
.x
= upd
.GetX();
3429 rect
.y
= upd
.GetY();
3430 rect
.width
= upd
.GetWidth();
3431 rect
.height
= upd
.GetHeight();
3433 gtk_paint_flat_box( parent
->m_widget
->style
,
3446 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3448 wxWindowDC
dc( (wxWindow
*)this );
3449 dc
.SetClippingRegion( m_clearRegion
);
3451 wxEraseEvent
erase_event( GetId(), &dc
);
3452 erase_event
.SetEventObject( this );
3454 if (!GetEventHandler()->ProcessEvent(erase_event
))
3458 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3459 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3461 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3463 wxRegionIterator
upd( m_clearRegion
);
3466 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3467 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3471 m_clearRegion
.Clear();
3474 wxNcPaintEvent
nc_paint_event( GetId() );
3475 nc_paint_event
.SetEventObject( this );
3476 GetEventHandler()->ProcessEvent( nc_paint_event
);
3478 wxPaintEvent
paint_event( GetId() );
3479 paint_event
.SetEventObject( this );
3480 GetEventHandler()->ProcessEvent( paint_event
);
3482 m_clipPaintRegion
= FALSE
;
3484 #ifndef __WXUNIVERSAL__
3486 // The following code will result in all window-less widgets
3487 // being redrawn because the wxWindows class is allowed to
3488 // paint over the window-less widgets.
3490 GList
*children
= pizza
->children
;
3493 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3494 children
= children
->next
;
3496 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3497 GTK_WIDGET_DRAWABLE (child
->widget
))
3499 // Get intersection of widget area and update region
3500 wxRegion
region( m_updateRegion
);
3502 GdkEventExpose gdk_event
;
3503 gdk_event
.type
= GDK_EXPOSE
;
3504 gdk_event
.window
= pizza
->bin_window
;
3505 gdk_event
.count
= 0;
3507 wxRegionIterator
upd( m_updateRegion
);
3511 rect
.x
= upd
.GetX();
3512 rect
.y
= upd
.GetY();
3513 rect
.width
= upd
.GetWidth();
3514 rect
.height
= upd
.GetHeight();
3516 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3518 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3528 m_updateRegion
.Clear();
3531 void wxWindowGTK::Clear()
3533 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3535 if (m_wxwindow
&& m_wxwindow
->window
)
3537 m_clearRegion
.Clear();
3538 wxSize
size( GetClientSize() );
3539 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3541 // Better do this in idle?
3547 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3549 wxWindowBase::DoSetToolTip(tip
);
3552 m_tooltip
->Apply( (wxWindow
*)this );
3555 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3557 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3559 #endif // wxUSE_TOOLTIPS
3561 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3563 GdkWindow
*window
= (GdkWindow
*) NULL
;
3565 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3567 window
= GetConnectWidget()->window
;
3571 // We need the pixel value e.g. for background clearing.
3572 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3576 // wxMSW doesn't clear the window here, either.
3577 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3583 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3585 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3587 if (!wxWindowBase::SetBackgroundColour(colour
))
3590 GdkWindow
*window
= (GdkWindow
*) NULL
;
3592 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3594 window
= GetConnectWidget()->window
;
3598 // indicate that a new style has been set
3599 // but it couldn't get applied as the
3600 // widget hasn't been realized yet.
3601 m_delayedBackgroundColour
= TRUE
;
3606 GtkSetBackgroundColour( colour
);
3612 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3614 GdkWindow
*window
= (GdkWindow
*) NULL
;
3616 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3618 window
= GetConnectWidget()->window
;
3625 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3627 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3629 if (!wxWindowBase::SetForegroundColour(colour
))
3631 // don't leave if the GTK widget has just
3633 if (!m_delayedForegroundColour
) return FALSE
;
3636 GdkWindow
*window
= (GdkWindow
*) NULL
;
3638 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3640 window
= GetConnectWidget()->window
;
3644 // indicate that a new style has been set
3645 // but it couldn't get applied as the
3646 // widget hasn't been realized yet.
3647 m_delayedForegroundColour
= TRUE
;
3651 GtkSetForegroundColour( colour
);
3657 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3661 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3663 // FIXME: no more klass in 2.0
3665 remake
->klass
= m_widgetStyle
->klass
;
3668 gtk_style_unref( m_widgetStyle
);
3669 m_widgetStyle
= remake
;
3673 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3676 def
= gtk_widget_get_default_style();
3678 m_widgetStyle
= gtk_style_copy( def
);
3680 // FIXME: no more klass in 2.0
3682 m_widgetStyle
->klass
= def
->klass
;
3686 return m_widgetStyle
;
3689 void wxWindowGTK::SetWidgetStyle()
3691 #if DISABLE_STYLE_IF_BROKEN_THEME
3692 if (m_widget
->style
->engine_data
)
3694 static bool s_warningPrinted
= FALSE
;
3695 if (!s_warningPrinted
)
3697 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3698 s_warningPrinted
= TRUE
;
3700 m_widgetStyle
= m_widget
->style
;
3705 GtkStyle
*style
= GetWidgetStyle();
3707 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3709 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3712 if (m_foregroundColour
.Ok())
3714 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3715 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3717 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3718 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3719 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3723 // Try to restore the gtk default style. This is still a little
3724 // oversimplified for what is probably really needed here for controls
3725 // other than buttons, but is better than not being able to (re)set a
3726 // control's foreground colour to *wxBLACK -- RL
3727 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3730 def
= gtk_widget_get_default_style();
3732 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3733 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3734 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3738 if (m_backgroundColour
.Ok())
3740 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3741 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3743 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3744 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3745 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3746 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3747 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3748 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3749 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3750 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3754 // Try to restore the gtk default style. This is still a little
3755 // oversimplified for what is probably really needed here for controls
3756 // other than buttons, but is better than not being able to (re)set a
3757 // control's background colour to default grey and means resetting a
3758 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3760 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3763 def
= gtk_widget_get_default_style();
3765 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3766 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3767 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3768 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3769 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3770 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3771 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3772 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3777 void wxWindowGTK::ApplyWidgetStyle()
3781 //-----------------------------------------------------------------------------
3782 // Pop-up menu stuff
3783 //-----------------------------------------------------------------------------
3785 #if wxUSE_MENUS_NATIVE
3788 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3790 *is_waiting
= FALSE
;
3793 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3795 menu
->SetInvokingWindow( win
);
3796 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3799 wxMenuItem
*menuitem
= node
->GetData();
3800 if (menuitem
->IsSubMenu())
3802 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3805 node
= node
->GetNext();
3809 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3810 // wxPopupMenuPositionCallback()
3812 // should be safe even in the MT case as the user can hardly popup 2 menus
3813 // simultaneously, can he?
3814 static gint gs_pop_x
= 0;
3815 static gint gs_pop_y
= 0;
3817 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3820 gboolean
* WXUNUSED(whatever
),
3822 gpointer
WXUNUSED(user_data
) )
3824 // ensure that the menu appears entirely on screen
3826 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3828 wxSize sizeScreen
= wxGetDisplaySize();
3830 gint xmax
= sizeScreen
.x
- req
.width
,
3831 ymax
= sizeScreen
.y
- req
.height
;
3833 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3834 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3837 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3839 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3841 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3843 SetInvokingWindow( menu
, this );
3849 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3851 bool is_waiting
= TRUE
;
3853 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3855 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3856 (gpointer
)&is_waiting
);
3859 GTK_MENU(menu
->m_menu
),
3860 (GtkWidget
*) NULL
, // parent menu shell
3861 (GtkWidget
*) NULL
, // parent menu item
3862 wxPopupMenuPositionCallback
, // function to position it
3863 NULL
, // client data
3864 0, // button used to activate it
3865 gs_timeLastClick
// the time of activation
3870 while (gtk_events_pending())
3871 gtk_main_iteration();
3877 #endif // wxUSE_MENUS_NATIVE
3879 #if wxUSE_DRAG_AND_DROP
3881 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3883 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3885 GtkWidget
*dnd_widget
= GetConnectWidget();
3887 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3889 if (m_dropTarget
) delete m_dropTarget
;
3890 m_dropTarget
= dropTarget
;
3892 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3895 #endif // wxUSE_DRAG_AND_DROP
3897 GtkWidget
* wxWindowGTK::GetConnectWidget()
3899 GtkWidget
*connect_widget
= m_widget
;
3900 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3902 return connect_widget
;
3905 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3908 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3910 return (window
== m_widget
->window
);
3913 bool wxWindowGTK::SetFont( const wxFont
&font
)
3915 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3917 if (!wxWindowBase::SetFont(font
))
3922 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3923 if ( sysbg
== m_backgroundColour
)
3925 m_backgroundColour
= wxNullColour
;
3927 m_backgroundColour
= sysbg
;
3937 void wxWindowGTK::DoCaptureMouse()
3939 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3941 GdkWindow
*window
= (GdkWindow
*) NULL
;
3943 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3945 window
= GetConnectWidget()->window
;
3947 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3949 wxCursor
* cursor
= & m_cursor
;
3951 cursor
= wxSTANDARD_CURSOR
;
3953 gdk_pointer_grab( window
, FALSE
,
3955 (GDK_BUTTON_PRESS_MASK
|
3956 GDK_BUTTON_RELEASE_MASK
|
3957 GDK_POINTER_MOTION_HINT_MASK
|
3958 GDK_POINTER_MOTION_MASK
),
3960 cursor
->GetCursor(),
3961 (guint32
)GDK_CURRENT_TIME
);
3962 g_captureWindow
= this;
3963 g_captureWindowHasMouse
= TRUE
;
3966 void wxWindowGTK::DoReleaseMouse()
3968 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3970 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3972 g_captureWindow
= (wxWindowGTK
*) NULL
;
3974 GdkWindow
*window
= (GdkWindow
*) NULL
;
3976 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3978 window
= GetConnectWidget()->window
;
3983 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3987 wxWindow
*wxWindowBase::GetCapture()
3989 return (wxWindow
*)g_captureWindow
;
3992 bool wxWindowGTK::IsRetained() const
3997 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3998 int range
, bool refresh
)
4000 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4002 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4004 m_hasScrolling
= TRUE
;
4006 if (orient
== wxHORIZONTAL
)
4008 float fpos
= (float)pos
;
4009 float frange
= (float)range
;
4010 float fthumb
= (float)thumbVisible
;
4011 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4012 if (fpos
< 0.0) fpos
= 0.0;
4014 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4015 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4017 SetScrollPos( orient
, pos
, refresh
);
4021 m_oldHorizontalPos
= fpos
;
4023 m_hAdjust
->lower
= 0.0;
4024 m_hAdjust
->upper
= frange
;
4025 m_hAdjust
->value
= fpos
;
4026 m_hAdjust
->step_increment
= 1.0;
4027 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4028 m_hAdjust
->page_size
= fthumb
;
4032 float fpos
= (float)pos
;
4033 float frange
= (float)range
;
4034 float fthumb
= (float)thumbVisible
;
4035 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4036 if (fpos
< 0.0) fpos
= 0.0;
4038 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4039 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4041 SetScrollPos( orient
, pos
, refresh
);
4045 m_oldVerticalPos
= fpos
;
4047 m_vAdjust
->lower
= 0.0;
4048 m_vAdjust
->upper
= frange
;
4049 m_vAdjust
->value
= fpos
;
4050 m_vAdjust
->step_increment
= 1.0;
4051 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4052 m_vAdjust
->page_size
= fthumb
;
4055 if (orient
== wxHORIZONTAL
)
4056 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4058 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4061 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4063 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4065 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4067 if (orient
== wxHORIZONTAL
)
4069 float fpos
= (float)pos
;
4070 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4071 if (fpos
< 0.0) fpos
= 0.0;
4072 m_oldHorizontalPos
= fpos
;
4074 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4075 m_hAdjust
->value
= fpos
;
4079 float fpos
= (float)pos
;
4080 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4081 if (fpos
< 0.0) fpos
= 0.0;
4082 m_oldVerticalPos
= fpos
;
4084 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4085 m_vAdjust
->value
= fpos
;
4088 if (m_wxwindow
->window
)
4090 if (orient
== wxHORIZONTAL
)
4092 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4093 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4095 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4097 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4098 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4102 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4103 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4105 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4107 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4108 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4113 int wxWindowGTK::GetScrollThumb( int orient
) const
4115 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4117 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4119 if (orient
== wxHORIZONTAL
)
4120 return (int)(m_hAdjust
->page_size
+0.5);
4122 return (int)(m_vAdjust
->page_size
+0.5);
4125 int wxWindowGTK::GetScrollPos( int orient
) const
4127 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4129 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4131 if (orient
== wxHORIZONTAL
)
4132 return (int)(m_hAdjust
->value
+0.5);
4134 return (int)(m_vAdjust
->value
+0.5);
4137 int wxWindowGTK::GetScrollRange( int orient
) const
4139 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4141 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4143 if (orient
== wxHORIZONTAL
)
4144 return (int)(m_hAdjust
->upper
+0.5);
4146 return (int)(m_vAdjust
->upper
+0.5);
4149 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4151 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4153 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4155 // No scrolling requested.
4156 if ((dx
== 0) && (dy
== 0)) return;
4159 if (!m_updateRegion
.IsEmpty())
4161 m_updateRegion
.Offset( dx
, dy
);
4165 GetClientSize( &cw
, &ch
);
4166 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4169 if (!m_clearRegion
.IsEmpty())
4171 m_clearRegion
.Offset( dx
, dy
);
4175 GetClientSize( &cw
, &ch
);
4176 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4178 m_clipPaintRegion
= TRUE
;
4180 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4182 m_clipPaintRegion
= FALSE
;
4185 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4187 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4188 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4195 // Find the wxWindow at the current mouse position, also returning the mouse
4197 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4199 pt
= wxGetMousePosition();
4200 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4204 // Get the current mouse position.
4205 wxPoint
wxGetMousePosition()
4207 /* This crashes when used within wxHelpContext,
4208 so we have to use the X-specific implementation below.
4210 GdkModifierType *mask;
4211 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4213 return wxPoint(x, y);
4217 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4219 return wxPoint(-999, -999);
4221 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4222 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4223 Window rootReturn
, childReturn
;
4224 int rootX
, rootY
, winX
, winY
;
4225 unsigned int maskReturn
;
4227 XQueryPointer (display
,
4231 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4232 return wxPoint(rootX
, rootY
);
4236 // ----------------------------------------------------------------------------
4238 // ----------------------------------------------------------------------------
4240 class wxWinModule
: public wxModule
4247 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4250 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4252 bool wxWinModule::OnInit()
4254 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4255 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4260 void wxWinModule::OnExit()
4263 gdk_gc_unref( g_eraseGC
);