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
)
1071 wxKeyEvent
event( wxEVT_CHAR_HOOK
);
1072 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1074 // unknown key pressed, ignore (the event would be useless anyhow)
1078 // Implement wxFrame::OnCharHook by checking ancestor.
1079 wxWindow
*parent
= win
;
1080 while (parent
&& !parent
->IsTopLevel())
1081 parent
= parent
->GetParent();
1084 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1088 event
.SetEventType(wxEVT_KEY_DOWN
);
1089 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1095 wxWindowGTK
*ancestor
= win
;
1098 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1101 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1102 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1105 if (ancestor
->IsTopLevel())
1107 ancestor
= ancestor
->GetParent();
1110 #endif // wxUSE_ACCEL
1112 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1113 will only be sent if it is not in an accelerator table. */
1116 KeySym keysym
= gdk_event
->keyval
;
1117 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1120 if ( gdk_event
->length
== 1 )
1122 key_code
= (unsigned char)gdk_event
->string
[0];
1124 else if ( wxIsAsciiKeysym(keysym
) )
1127 key_code
= (unsigned char)keysym
;
1133 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1135 // reuse the same event object, just change its type and use the
1136 // translated keycode instead of the raw one
1137 event
.SetEventType(wxEVT_CHAR
);
1138 event
.m_keyCode
= key_code
;
1140 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
);
1175 #if 0 // (GTK_MINOR_VERSION > 0)
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
)
1307 if (win
->m_wxwindow
)
1309 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1310 x
+= pizza
->xoffset
;
1311 y
+= pizza
->yoffset
;
1314 wxNode
*node
= win
->GetChildren().First();
1317 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1319 node
= node
->Next();
1320 if (!child
->IsShown())
1323 if (child
->IsTransparentForMouse())
1325 // wxStaticBox is transparent in the box itself
1326 int xx1
= child
->m_x
;
1327 int yy1
= child
->m_y
;
1328 int xx2
= child
->m_x
+ child
->m_width
;
1329 int yy2
= child
->m_x
+ child
->m_height
;
1332 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1334 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1336 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1338 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1349 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1350 (child
->m_x
<= x
) &&
1351 (child
->m_y
<= y
) &&
1352 (child
->m_x
+child
->m_width
>= x
) &&
1353 (child
->m_y
+child
->m_height
>= y
))
1366 //-----------------------------------------------------------------------------
1367 // "button_press_event"
1368 //-----------------------------------------------------------------------------
1370 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1371 GdkEventButton
*gdk_event
,
1377 wxapp_install_idle_handler();
1380 wxPrintf( wxT("1) OnButtonPress from ") );
1381 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1382 wxPrintf( win->GetClassInfo()->GetClassName() );
1383 wxPrintf( wxT(".\n") );
1385 if (!win
->m_hasVMT
) return FALSE
;
1386 if (g_blockEventsOnDrag
) return TRUE
;
1387 if (g_blockEventsOnScroll
) return TRUE
;
1389 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1391 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1393 gtk_widget_grab_focus( win
->m_wxwindow
);
1395 wxPrintf( wxT("GrabFocus from ") );
1396 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1397 wxPrintf( win->GetClassInfo()->GetClassName() );
1398 wxPrintf( wxT(".\n") );
1402 wxEventType event_type
= wxEVT_NULL
;
1404 if (gdk_event
->button
== 1)
1406 switch (gdk_event
->type
)
1408 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1409 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1413 else if (gdk_event
->button
== 2)
1415 switch (gdk_event
->type
)
1417 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1418 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1422 else if (gdk_event
->button
== 3)
1424 switch (gdk_event
->type
)
1426 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1427 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1432 if ( event_type
== wxEVT_NULL
)
1434 // unknown mouse button or click type
1438 wxMouseEvent
event( event_type
);
1439 InitMouseEvent( win
, event
, gdk_event
);
1441 AdjustEventButtonState(event
);
1443 // wxListBox actually get mouse events from the item, so we need to give it
1444 // a chance to correct this
1445 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1447 // find the correct window to send the event too: it may be a different one
1448 // from the one which got it at GTK+ level because some control don't have
1449 // their own X window and thus cannot get any events.
1450 if ( !g_captureWindow
)
1451 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1453 event
.SetEventObject( win
);
1455 gs_timeLastClick
= gdk_event
->time
;
1458 wxPrintf( wxT("2) OnButtonPress from ") );
1459 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1460 wxPrintf( win->GetClassInfo()->GetClassName() );
1461 wxPrintf( wxT(".\n") );
1464 if (win
->GetEventHandler()->ProcessEvent( event
))
1466 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1473 //-----------------------------------------------------------------------------
1474 // "button_release_event"
1475 //-----------------------------------------------------------------------------
1477 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1482 wxapp_install_idle_handler();
1484 if (!win
->m_hasVMT
) return FALSE
;
1485 if (g_blockEventsOnDrag
) return FALSE
;
1486 if (g_blockEventsOnScroll
) return FALSE
;
1488 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1491 printf( "OnButtonRelease from " );
1492 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1493 printf( win->GetClassInfo()->GetClassName() );
1497 wxEventType event_type
= wxEVT_NULL
;
1499 switch (gdk_event
->button
)
1501 case 1: event_type
= wxEVT_LEFT_UP
; break;
1502 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1503 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1504 default: return FALSE
;
1507 wxMouseEvent
event( event_type
);
1508 InitMouseEvent( win
, event
, gdk_event
);
1510 AdjustEventButtonState(event
);
1512 // same wxListBox hack as above
1513 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1515 if ( !g_captureWindow
)
1516 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1518 event
.SetEventObject( win
);
1520 if (win
->GetEventHandler()->ProcessEvent( event
))
1522 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1529 //-----------------------------------------------------------------------------
1530 // "motion_notify_event"
1531 //-----------------------------------------------------------------------------
1533 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1534 GdkEventMotion
*gdk_event
,
1540 wxapp_install_idle_handler();
1542 if (!win
->m_hasVMT
) return FALSE
;
1543 if (g_blockEventsOnDrag
) return FALSE
;
1544 if (g_blockEventsOnScroll
) return FALSE
;
1546 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1548 if (gdk_event
->is_hint
)
1552 GdkModifierType state
;
1553 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1559 printf( "OnMotion from " );
1560 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1561 printf( win->GetClassInfo()->GetClassName() );
1565 wxMouseEvent
event( wxEVT_MOTION
);
1566 InitMouseEvent(win
, event
, gdk_event
);
1568 if ( g_captureWindow
)
1570 // synthetize a mouse enter or leave event if needed
1571 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1572 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1573 if ( hasMouse
!= g_captureWindowHasMouse
)
1575 // the mouse changed window
1576 g_captureWindowHasMouse
= hasMouse
;
1578 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1579 : wxEVT_LEAVE_WINDOW
);
1580 InitMouseEvent(win
, event
, gdk_event
);
1581 event
.SetEventObject(win
);
1582 win
->GetEventHandler()->ProcessEvent(event
);
1587 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1590 event
.SetEventObject( win
);
1592 if (win
->GetEventHandler()->ProcessEvent( event
))
1594 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1601 //-----------------------------------------------------------------------------
1603 //-----------------------------------------------------------------------------
1605 // send the wxChildFocusEvent and wxFocusEvent, common code of
1606 // gtk_window_focus_in_callback() and SetFocus()
1607 static bool DoSendFocusEvents(wxWindow
*win
)
1609 // Notify the parent keeping track of focus for the kbd navigation
1610 // purposes that we got it.
1611 wxChildFocusEvent
eventChildFocus(win
);
1612 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1614 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1615 eventFocus
.SetEventObject(win
);
1617 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1620 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1621 GdkEvent
*WXUNUSED(event
),
1627 wxapp_install_idle_handler();
1629 if (!win
->m_hasVMT
) return FALSE
;
1630 if (g_blockEventsOnDrag
) return FALSE
;
1632 switch ( g_sendActivateEvent
)
1635 // we've got focus from outside, synthetize wxActivateEvent
1636 g_sendActivateEvent
= 1;
1640 // another our window just lost focus, it was already ours before
1641 // - don't send any wxActivateEvent
1642 g_sendActivateEvent
= -1;
1647 g_focusWindow
= win
;
1649 wxLogTrace(TRACE_FOCUS
,
1650 _T("%s: focus in"), win
->GetName().c_str());
1654 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1658 // caret needs to be informed about focus change
1659 wxCaret
*caret
= win
->GetCaret();
1662 caret
->OnSetFocus();
1664 #endif // wxUSE_CARET
1666 g_activeFrameLostFocus
= FALSE
;
1668 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1669 if ( active
!= g_activeFrame
)
1671 if ( g_activeFrame
)
1673 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1674 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1675 event
.SetEventObject(g_activeFrame
);
1676 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1679 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1680 g_activeFrame
= active
;
1681 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1682 event
.SetEventObject(g_activeFrame
);
1683 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1685 // Don't send focus events in addition to activate
1686 // if (win == g_activeFrame)
1690 // does the window itself think that it has the focus?
1691 if ( !win
->m_hasFocus
)
1693 // not yet, notify it
1694 win
->m_hasFocus
= TRUE
;
1696 if ( DoSendFocusEvents(win
) )
1698 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1706 //-----------------------------------------------------------------------------
1707 // "focus_out_event"
1708 //-----------------------------------------------------------------------------
1710 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1715 wxapp_install_idle_handler();
1717 if (!win
->m_hasVMT
) return FALSE
;
1718 if (g_blockEventsOnDrag
) return FALSE
;
1720 wxLogTrace( TRACE_FOCUS
,
1721 _T("%s: focus out"), win
->GetName().c_str() );
1723 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1725 // VZ: commenting this out because it does happen (although not easy
1726 // to reproduce, I only see it when using wxMiniFrame and not
1727 // always) and makes using Mahogany quite annoying
1729 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1730 wxT("unfocusing window that hasn't gained focus properly") )
1733 g_activeFrameLostFocus
= TRUE
;
1736 // if the focus goes out of our app alltogether, OnIdle() will send
1737 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1738 // g_sendActivateEvent to -1
1739 g_sendActivateEvent
= 0;
1741 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1745 g_focusWindow
= (wxWindowGTK
*)NULL
;
1753 // caret needs to be informed about focus change
1754 wxCaret
*caret
= win
->GetCaret();
1757 caret
->OnKillFocus();
1759 #endif // wxUSE_CARET
1761 // don't send the window a kill focus event if it thinks that it doesn't
1762 // have focus already
1763 if ( win
->m_hasFocus
)
1765 win
->m_hasFocus
= FALSE
;
1767 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1768 event
.SetEventObject( win
);
1770 if (win
->GetEventHandler()->ProcessEvent( event
))
1772 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1780 //-----------------------------------------------------------------------------
1781 // "enter_notify_event"
1782 //-----------------------------------------------------------------------------
1784 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1789 wxapp_install_idle_handler();
1791 if (!win
->m_hasVMT
) return FALSE
;
1792 if (g_blockEventsOnDrag
) return FALSE
;
1794 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1796 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1797 event
.SetTimestamp( gdk_event
->time
);
1798 event
.SetEventObject( win
);
1802 GdkModifierType state
= (GdkModifierType
)0;
1804 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1806 InitMouseEvent(win
, event
, gdk_event
);
1807 wxPoint pt
= win
->GetClientAreaOrigin();
1808 event
.m_x
= x
+ pt
.x
;
1809 event
.m_y
= y
+ pt
.y
;
1811 if (win
->GetEventHandler()->ProcessEvent( event
))
1813 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1820 //-----------------------------------------------------------------------------
1821 // "leave_notify_event"
1822 //-----------------------------------------------------------------------------
1824 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1829 wxapp_install_idle_handler();
1831 if (!win
->m_hasVMT
) return FALSE
;
1832 if (g_blockEventsOnDrag
) return FALSE
;
1834 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1836 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1837 event
.SetTimestamp( gdk_event
->time
);
1838 event
.SetEventObject( win
);
1842 GdkModifierType state
= (GdkModifierType
)0;
1844 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1846 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1847 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1848 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1849 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1850 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1851 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1852 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1854 wxPoint pt
= win
->GetClientAreaOrigin();
1855 event
.m_x
= x
+ pt
.x
;
1856 event
.m_y
= y
+ pt
.y
;
1858 if (win
->GetEventHandler()->ProcessEvent( event
))
1860 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1867 //-----------------------------------------------------------------------------
1868 // "value_changed" from m_vAdjust
1869 //-----------------------------------------------------------------------------
1871 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1878 wxapp_install_idle_handler();
1880 if (g_blockEventsOnDrag
) return;
1882 if (!win
->m_hasVMT
) return;
1884 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1885 if (fabs(diff
) < 0.2) return;
1887 win
->m_oldVerticalPos
= adjust
->value
;
1889 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1890 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
1892 int value
= (int)(adjust
->value
+0.5);
1894 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1895 event
.SetEventObject( win
);
1896 win
->GetEventHandler()->ProcessEvent( event
);
1899 //-----------------------------------------------------------------------------
1900 // "value_changed" from m_hAdjust
1901 //-----------------------------------------------------------------------------
1903 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1910 wxapp_install_idle_handler();
1912 if (g_blockEventsOnDrag
) return;
1913 if (!win
->m_hasVMT
) return;
1915 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1916 if (fabs(diff
) < 0.2) return;
1918 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1919 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
1921 win
->m_oldHorizontalPos
= adjust
->value
;
1923 int value
= (int)(adjust
->value
+0.5);
1925 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1926 event
.SetEventObject( win
);
1927 win
->GetEventHandler()->ProcessEvent( event
);
1930 //-----------------------------------------------------------------------------
1931 // "button_press_event" from scrollbar
1932 //-----------------------------------------------------------------------------
1934 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1935 GdkEventButton
*gdk_event
,
1941 wxapp_install_idle_handler();
1944 g_blockEventsOnScroll
= TRUE
;
1946 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1948 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1954 //-----------------------------------------------------------------------------
1955 // "button_release_event" from scrollbar
1956 //-----------------------------------------------------------------------------
1958 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1959 GdkEventButton
*WXUNUSED(gdk_event
),
1964 // don't test here as we can release the mouse while being over
1965 // a different window than the slider
1967 // if (gdk_event->window != widget->slider) return FALSE;
1969 g_blockEventsOnScroll
= FALSE
;
1971 if (win
->m_isScrolling
)
1973 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1977 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1978 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1980 value
= (int)(win
->m_hAdjust
->value
+0.5);
1983 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
1985 value
= (int)(win
->m_vAdjust
->value
+0.5);
1989 wxScrollWinEvent
event( command
, value
, dir
);
1990 event
.SetEventObject( win
);
1991 win
->GetEventHandler()->ProcessEvent( event
);
1994 win
->m_isScrolling
= FALSE
;
1999 // ----------------------------------------------------------------------------
2000 // this wxWindowBase function is implemented here (in platform-specific file)
2001 // because it is static and so couldn't be made virtual
2002 // ----------------------------------------------------------------------------
2004 wxWindow
*wxWindowBase::FindFocus()
2006 // the cast is necessary when we compile in wxUniversal mode
2007 return (wxWindow
*)g_focusWindow
;
2010 //-----------------------------------------------------------------------------
2012 //-----------------------------------------------------------------------------
2014 static void gtk_window_destroy_callback( GtkWidget
* widget
, wxWindow
*win
)
2016 wxWindowDestroyEvent
event(win
);
2017 win
->GetEventHandler()->ProcessEvent(event
);
2020 //-----------------------------------------------------------------------------
2021 // "realize" from m_widget
2022 //-----------------------------------------------------------------------------
2024 /* We cannot set colours and fonts before the widget has
2025 been realized, so we do this directly after realization. */
2028 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2033 wxapp_install_idle_handler();
2035 if (win
->m_delayedBackgroundColour
)
2036 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2038 if (win
->m_delayedForegroundColour
)
2039 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2041 wxWindowCreateEvent
event( win
);
2042 event
.SetEventObject( win
);
2043 win
->GetEventHandler()->ProcessEvent( event
);
2048 //-----------------------------------------------------------------------------
2050 //-----------------------------------------------------------------------------
2053 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2054 GtkAllocation
*WXUNUSED(alloc
),
2058 wxapp_install_idle_handler();
2060 if (!win
->m_hasScrolling
) return;
2062 int client_width
= 0;
2063 int client_height
= 0;
2064 win
->GetClientSize( &client_width
, &client_height
);
2065 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2068 win
->m_oldClientWidth
= client_width
;
2069 win
->m_oldClientHeight
= client_height
;
2071 if (!win
->m_nativeSizeEvent
)
2073 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2074 event
.SetEventObject( win
);
2075 win
->GetEventHandler()->ProcessEvent( event
);
2081 #define WXUNUSED_UNLESS_XIM(param) param
2083 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2086 /* Resize XIM window */
2089 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2090 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2091 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2094 wxapp_install_idle_handler();
2100 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2104 gdk_window_get_size (widget
->window
, &width
, &height
);
2105 win
->m_icattr
->preedit_area
.width
= width
;
2106 win
->m_icattr
->preedit_area
.height
= height
;
2107 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2112 //-----------------------------------------------------------------------------
2113 // "realize" from m_wxwindow
2114 //-----------------------------------------------------------------------------
2116 /* Initialize XIM support */
2119 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2120 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2123 wxapp_install_idle_handler();
2126 if (win
->m_ic
) return FALSE
;
2127 if (!widget
) return FALSE
;
2128 if (!gdk_im_ready()) return FALSE
;
2130 win
->m_icattr
= gdk_ic_attr_new();
2131 if (!win
->m_icattr
) return FALSE
;
2135 GdkColormap
*colormap
;
2136 GdkICAttr
*attr
= win
->m_icattr
;
2137 unsigned attrmask
= GDK_IC_ALL_REQ
;
2139 GdkIMStyle supported_style
= (GdkIMStyle
)
2140 (GDK_IM_PREEDIT_NONE
|
2141 GDK_IM_PREEDIT_NOTHING
|
2142 GDK_IM_PREEDIT_POSITION
|
2143 GDK_IM_STATUS_NONE
|
2144 GDK_IM_STATUS_NOTHING
);
2146 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2147 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2149 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2150 attr
->client_window
= widget
->window
;
2152 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2153 gtk_widget_get_default_colormap ())
2155 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2156 attr
->preedit_colormap
= colormap
;
2159 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2160 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2161 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2162 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2164 switch (style
& GDK_IM_PREEDIT_MASK
)
2166 case GDK_IM_PREEDIT_POSITION
:
2167 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2169 g_warning ("over-the-spot style requires fontset");
2173 gdk_window_get_size (widget
->window
, &width
, &height
);
2175 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2176 attr
->spot_location
.x
= 0;
2177 attr
->spot_location
.y
= height
;
2178 attr
->preedit_area
.x
= 0;
2179 attr
->preedit_area
.y
= 0;
2180 attr
->preedit_area
.width
= width
;
2181 attr
->preedit_area
.height
= height
;
2182 attr
->preedit_fontset
= widget
->style
->font
;
2187 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2189 if (win
->m_ic
== NULL
)
2190 g_warning ("Can't create input context.");
2193 mask
= gdk_window_get_events (widget
->window
);
2194 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2195 gdk_window_set_events (widget
->window
, mask
);
2197 if (GTK_WIDGET_HAS_FOCUS(widget
))
2198 gdk_im_begin (win
->m_ic
, widget
->window
);
2205 //-----------------------------------------------------------------------------
2206 // InsertChild for wxWindowGTK.
2207 //-----------------------------------------------------------------------------
2209 /* Callback for wxWindowGTK. This very strange beast has to be used because
2210 * C++ has no virtual methods in a constructor. We have to emulate a
2211 * virtual function here as wxNotebook requires a different way to insert
2212 * a child in it. I had opted for creating a wxNotebookPage window class
2213 * which would have made this superfluous (such in the MDI window system),
2214 * but no-one was listening to me... */
2216 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2218 /* the window might have been scrolled already, do we
2219 have to adapt the position */
2220 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2221 child
->m_x
+= pizza
->xoffset
;
2222 child
->m_y
+= pizza
->yoffset
;
2224 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2225 GTK_WIDGET(child
->m_widget
),
2232 //-----------------------------------------------------------------------------
2234 //-----------------------------------------------------------------------------
2236 wxWindow
*wxGetActiveWindow()
2238 return wxWindow::FindFocus();
2241 //-----------------------------------------------------------------------------
2243 //-----------------------------------------------------------------------------
2245 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2247 #ifdef __WXUNIVERSAL__
2248 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2250 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2251 #endif // __WXUNIVERSAL__/__WXGTK__
2253 void wxWindowGTK::Init()
2259 m_widget
= (GtkWidget
*) NULL
;
2260 m_wxwindow
= (GtkWidget
*) NULL
;
2261 m_focusWidget
= (GtkWidget
*) NULL
;
2271 m_needParent
= TRUE
;
2272 m_isBeingDeleted
= FALSE
;
2275 m_nativeSizeEvent
= FALSE
;
2277 m_hasScrolling
= FALSE
;
2278 m_isScrolling
= FALSE
;
2280 m_hAdjust
= (GtkAdjustment
*) NULL
;
2281 m_vAdjust
= (GtkAdjustment
*) NULL
;
2282 m_oldHorizontalPos
= 0.0;
2283 m_oldVerticalPos
= 0.0;
2286 m_widgetStyle
= (GtkStyle
*) NULL
;
2288 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2290 m_acceptsFocus
= FALSE
;
2293 m_clipPaintRegion
= FALSE
;
2295 m_cursor
= *wxSTANDARD_CURSOR
;
2297 m_delayedForegroundColour
= FALSE
;
2298 m_delayedBackgroundColour
= FALSE
;
2301 m_ic
= (GdkIC
*) NULL
;
2302 m_icattr
= (GdkICAttr
*) NULL
;
2306 wxWindowGTK::wxWindowGTK()
2311 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2316 const wxString
&name
)
2320 Create( parent
, id
, pos
, size
, style
, name
);
2323 bool wxWindowGTK::Create( wxWindow
*parent
,
2328 const wxString
&name
)
2330 if (!PreCreation( parent
, pos
, size
) ||
2331 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2333 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2337 m_insertCallback
= wxInsertChildInWindow
;
2339 // always needed for background clearing
2340 m_delayedBackgroundColour
= TRUE
;
2342 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2343 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2345 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2347 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2348 scroll_class
->scrollbar_spacing
= 0;
2350 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2352 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2353 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2355 m_wxwindow
= gtk_pizza_new();
2357 #ifndef __WXUNIVERSAL__
2358 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2360 if (HasFlag(wxRAISED_BORDER
))
2362 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2364 else if (HasFlag(wxSUNKEN_BORDER
))
2366 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2368 else if (HasFlag(wxSIMPLE_BORDER
))
2370 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2374 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2376 #endif // __WXUNIVERSAL__
2378 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2380 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2381 m_acceptsFocus
= TRUE
;
2383 // I _really_ don't want scrollbars in the beginning
2384 m_vAdjust
->lower
= 0.0;
2385 m_vAdjust
->upper
= 1.0;
2386 m_vAdjust
->value
= 0.0;
2387 m_vAdjust
->step_increment
= 1.0;
2388 m_vAdjust
->page_increment
= 1.0;
2389 m_vAdjust
->page_size
= 5.0;
2390 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2391 m_hAdjust
->lower
= 0.0;
2392 m_hAdjust
->upper
= 1.0;
2393 m_hAdjust
->value
= 0.0;
2394 m_hAdjust
->step_increment
= 1.0;
2395 m_hAdjust
->page_increment
= 1.0;
2396 m_hAdjust
->page_size
= 5.0;
2397 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2399 // these handlers block mouse events to any window during scrolling such as
2400 // motion events and prevent GTK and wxWindows from fighting over where the
2403 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2404 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2406 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2407 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2409 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2410 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2412 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2413 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2415 // these handlers get notified when screen updates are required either when
2416 // scrolling or when the window size (and therefore scrollbar configuration)
2419 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2420 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2421 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2422 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2424 gtk_widget_show( m_wxwindow
);
2427 m_parent
->DoAddChild( this );
2429 m_focusWidget
= m_wxwindow
;
2438 wxWindowGTK::~wxWindowGTK()
2440 if (g_focusWindow
== this)
2441 g_focusWindow
= NULL
;
2443 if (g_activeFrame
== this)
2444 g_activeFrame
= NULL
;
2446 if ( g_delayedFocus
== this )
2447 g_delayedFocus
= NULL
;
2449 m_isBeingDeleted
= TRUE
;
2458 m_parent
->RemoveChild( this );
2462 gdk_ic_destroy (m_ic
);
2464 gdk_ic_attr_destroy (m_icattr
);
2469 #if DISABLE_STYLE_IF_BROKEN_THEME
2470 // don't delete if it's a pixmap theme style
2471 if (!m_widgetStyle
->engine_data
)
2472 gtk_style_unref( m_widgetStyle
);
2474 m_widgetStyle
= (GtkStyle
*) NULL
;
2479 gtk_widget_destroy( m_wxwindow
);
2480 m_wxwindow
= (GtkWidget
*) NULL
;
2485 gtk_widget_destroy( m_widget
);
2486 m_widget
= (GtkWidget
*) NULL
;
2490 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2492 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2494 /* this turns -1 into 20 so that a minimal window is
2495 visible even although -1,-1 has been given as the
2496 size of the window. the same trick is used in other
2497 ports and should make debugging easier */
2498 m_width
= WidthDefault(size
.x
);
2499 m_height
= HeightDefault(size
.y
);
2504 /* some reasonable defaults */
2509 m_x
= (gdk_screen_width () - m_width
) / 2;
2510 if (m_x
< 10) m_x
= 10;
2514 m_y
= (gdk_screen_height () - m_height
) / 2;
2515 if (m_y
< 10) m_y
= 10;
2522 void wxWindowGTK::PostCreation()
2524 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2530 // these get reported to wxWindows -> wxPaintEvent
2532 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2534 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2535 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2538 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2539 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2541 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2543 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2544 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2547 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2551 // these are called when the "sunken" or "raised" borders are drawn
2552 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2553 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2556 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2557 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2563 if (m_focusWidget
== NULL
)
2564 m_focusWidget
= m_widget
;
2566 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2567 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2569 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2570 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2572 // connect to the various key and mouse handlers
2574 GtkWidget
*connect_widget
= GetConnectWidget();
2576 ConnectWidget( connect_widget
);
2578 /* We cannot set colours, fonts and cursors before the widget has
2579 been realized, so we do this directly after realization */
2580 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2581 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2585 // Catch native resize events
2586 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2587 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2589 // Initialize XIM support
2590 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2591 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2593 // And resize XIM window
2594 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2595 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2598 if (!GTK_IS_COMBO(m_widget
))
2600 // This is needed if we want to add our windows into native
2601 // GTK control, such as the toolbar. With this callback, the
2602 // toolbar gets to know the correct size (the one set by the
2603 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2604 // when moving to GTK 2.0.
2605 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2606 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2612 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2614 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2615 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2617 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2618 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2620 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2621 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2623 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2624 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2626 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2627 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2629 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2630 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2632 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2633 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2635 gtk_signal_connect( GTK_OBJECT(widget
), "destroy",
2636 GTK_SIGNAL_FUNC(gtk_window_destroy_callback
), (gpointer
)this );
2639 bool wxWindowGTK::Destroy()
2641 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2645 return wxWindowBase::Destroy();
2648 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2650 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2653 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2655 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2656 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2659 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2662 if (m_resizing
) return; /* I don't like recursions */
2665 int currentX
, currentY
;
2666 GetPosition(¤tX
, ¤tY
);
2671 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2673 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2675 /* don't set the size for children of wxNotebook, just take the values. */
2683 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2684 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2686 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2687 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2688 if (width
!= -1) m_width
= width
;
2689 if (height
!= -1) m_height
= height
;
2693 m_x
= x
+ pizza
->xoffset
;
2694 m_y
= y
+ pizza
->yoffset
;
2699 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2701 if (width
== -1) m_width
= 80;
2704 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2706 if (height
== -1) m_height
= 26;
2709 int minWidth
= GetMinWidth(),
2710 minHeight
= GetMinHeight(),
2711 maxWidth
= GetMaxWidth(),
2712 maxHeight
= GetMaxHeight();
2714 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2715 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2716 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2717 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2720 int bottom_border
= 0;
2723 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2725 /* the default button has a border around it */
2731 DoMoveWindow( m_x
-border
,
2734 m_height
+border
+bottom_border
);
2739 /* Sometimes the client area changes size without the
2740 whole windows's size changing, but if the whole
2741 windows's size doesn't change, no wxSizeEvent will
2742 normally be sent. Here we add an extra test if
2743 the client test has been changed and this will
2745 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2749 wxPrintf( "OnSize sent from " );
2750 if (GetClassInfo() && GetClassInfo()->GetClassName())
2751 wxPrintf( GetClassInfo()->GetClassName() );
2752 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2755 if (!m_nativeSizeEvent
)
2757 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2758 event
.SetEventObject( this );
2759 GetEventHandler()->ProcessEvent( event
);
2765 void wxWindowGTK::OnInternalIdle()
2767 // Update invalidated regions.
2770 // Synthetize activate events.
2771 if ( g_sendActivateEvent
!= -1 )
2773 bool activate
= g_sendActivateEvent
!= 0;
2776 g_sendActivateEvent
= -1;
2778 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2781 if ( g_activeFrameLostFocus
)
2783 if ( g_activeFrame
)
2785 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2786 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2787 event
.SetEventObject(g_activeFrame
);
2788 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2789 g_activeFrame
= NULL
;
2791 g_activeFrameLostFocus
= FALSE
;
2794 wxCursor cursor
= m_cursor
;
2795 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2799 /* I now set the cursor anew in every OnInternalIdle call
2800 as setting the cursor in a parent window also effects the
2801 windows above so that checking for the current cursor is
2806 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2808 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2810 if (!g_globalCursor
.Ok())
2811 cursor
= *wxSTANDARD_CURSOR
;
2813 window
= m_widget
->window
;
2814 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2815 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2821 GdkWindow
*window
= m_widget
->window
;
2822 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2823 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2831 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2833 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2835 if (width
) (*width
) = m_width
;
2836 if (height
) (*height
) = m_height
;
2839 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2841 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2845 SetSize( width
, height
);
2852 #ifndef __WXUNIVERSAL__
2853 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2855 /* when using GTK 1.2 we set the shadow border size to 2 */
2859 if (HasFlag(wxSIMPLE_BORDER
))
2861 /* when using GTK 1.2 we set the simple border size to 1 */
2865 #endif // __WXUNIVERSAL__
2869 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2871 GtkRequisition vscroll_req
;
2872 vscroll_req
.width
= 2;
2873 vscroll_req
.height
= 2;
2874 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2875 (scroll_window
->vscrollbar
, &vscroll_req
);
2877 GtkRequisition hscroll_req
;
2878 hscroll_req
.width
= 2;
2879 hscroll_req
.height
= 2;
2880 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2881 (scroll_window
->hscrollbar
, &hscroll_req
);
2883 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2885 if (scroll_window
->vscrollbar_visible
)
2887 dw
+= vscroll_req
.width
;
2888 dw
+= scroll_class
->scrollbar_spacing
;
2891 if (scroll_window
->hscrollbar_visible
)
2893 dh
+= hscroll_req
.height
;
2894 dh
+= scroll_class
->scrollbar_spacing
;
2898 SetSize( width
+dw
, height
+dh
);
2902 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2904 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2908 if (width
) (*width
) = m_width
;
2909 if (height
) (*height
) = m_height
;
2916 #ifndef __WXUNIVERSAL__
2917 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2919 /* when using GTK 1.2 we set the shadow border size to 2 */
2923 if (HasFlag(wxSIMPLE_BORDER
))
2925 /* when using GTK 1.2 we set the simple border size to 1 */
2929 #endif // __WXUNIVERSAL__
2933 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2935 GtkRequisition vscroll_req
;
2936 vscroll_req
.width
= 2;
2937 vscroll_req
.height
= 2;
2938 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2939 (scroll_window
->vscrollbar
, &vscroll_req
);
2941 GtkRequisition hscroll_req
;
2942 hscroll_req
.width
= 2;
2943 hscroll_req
.height
= 2;
2944 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2945 (scroll_window
->hscrollbar
, &hscroll_req
);
2947 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2949 if (scroll_window
->vscrollbar_visible
)
2951 dw
+= vscroll_req
.width
;
2952 dw
+= scroll_class
->scrollbar_spacing
;
2955 if (scroll_window
->hscrollbar_visible
)
2957 dh
+= hscroll_req
.height
;
2958 dh
+= scroll_class
->scrollbar_spacing
;
2962 if (width
) (*width
) = m_width
- dw
;
2963 if (height
) (*height
) = m_height
- dh
;
2967 printf( "GetClientSize, name %s ", GetName().c_str() );
2968 if (width) printf( " width = %d", (*width) );
2969 if (height) printf( " height = %d", (*height) );
2974 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2976 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2980 if (m_parent
&& m_parent
->m_wxwindow
)
2982 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2983 dx
= pizza
->xoffset
;
2984 dy
= pizza
->yoffset
;
2987 if (x
) (*x
) = m_x
- dx
;
2988 if (y
) (*y
) = m_y
- dy
;
2991 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2993 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2995 if (!m_widget
->window
) return;
2997 GdkWindow
*source
= (GdkWindow
*) NULL
;
2999 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3001 source
= m_widget
->window
;
3005 gdk_window_get_origin( source
, &org_x
, &org_y
);
3009 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3011 org_x
+= m_widget
->allocation
.x
;
3012 org_y
+= m_widget
->allocation
.y
;
3020 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3022 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3024 if (!m_widget
->window
) return;
3026 GdkWindow
*source
= (GdkWindow
*) NULL
;
3028 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3030 source
= m_widget
->window
;
3034 gdk_window_get_origin( source
, &org_x
, &org_y
);
3038 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3040 org_x
+= m_widget
->allocation
.x
;
3041 org_y
+= m_widget
->allocation
.y
;
3049 bool wxWindowGTK::Show( bool show
)
3051 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3053 if (!wxWindowBase::Show(show
))
3060 gtk_widget_show( m_widget
);
3062 gtk_widget_hide( m_widget
);
3067 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3069 win
->OnParentEnable(enable
);
3071 // Recurse, so that children have the opportunity to Do The Right Thing
3072 // and reset colours that have been messed up by a parent's (really ancestor's)
3074 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3076 node
= node
->GetNext() )
3078 wxWindow
*child
= node
->GetData();
3079 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3080 wxWindowNotifyEnable(child
, enable
);
3084 bool wxWindowGTK::Enable( bool enable
)
3086 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3088 if (!wxWindowBase::Enable(enable
))
3094 gtk_widget_set_sensitive( m_widget
, enable
);
3096 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3098 wxWindowNotifyEnable(this, enable
);
3103 int wxWindowGTK::GetCharHeight() const
3105 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3107 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3109 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3111 return font
->ascent
+ font
->descent
;
3114 int wxWindowGTK::GetCharWidth() const
3116 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3118 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3120 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3122 return gdk_string_width( font
, "H" );
3125 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3129 int *externalLeading
,
3130 const wxFont
*theFont
) const
3132 wxFont fontToUse
= m_font
;
3133 if (theFont
) fontToUse
= *theFont
;
3135 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3137 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3138 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3139 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3140 if (descent
) (*descent
) = font
->descent
;
3141 if (externalLeading
) (*externalLeading
) = 0; // ??
3144 void wxWindowGTK::SetFocus()
3146 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3150 // don't do anything if we already have focus
3156 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3158 gtk_widget_grab_focus (m_wxwindow
);
3163 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3165 if (!GTK_WIDGET_REALIZED(m_widget
))
3167 // we can't set the focus to the widget now so we remember that
3168 // it should be focused and will do it later, during the idle
3169 // time, as soon as we can
3170 wxLogTrace(TRACE_FOCUS
,
3171 _T("Delaying setting focus to %s(%s)"),
3172 GetClassInfo()->GetClassName(), GetLabel().c_str());
3174 g_delayedFocus
= this;
3178 wxLogTrace(TRACE_FOCUS
,
3179 _T("Setting focus to %s(%s)"),
3180 GetClassInfo()->GetClassName(), GetLabel().c_str());
3182 gtk_widget_grab_focus (m_widget
);
3185 else if (GTK_IS_CONTAINER(m_widget
))
3187 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3191 wxLogTrace(TRACE_FOCUS
,
3192 _T("Can't set focus to %s(%s)"),
3193 GetClassInfo()->GetClassName(), GetLabel().c_str());
3198 bool wxWindowGTK::AcceptsFocus() const
3200 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3203 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3205 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3207 wxWindowGTK
*oldParent
= m_parent
,
3208 *newParent
= (wxWindowGTK
*)newParentBase
;
3210 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3212 if ( !wxWindowBase::Reparent(newParent
) )
3215 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3217 /* prevent GTK from deleting the widget arbitrarily */
3218 gtk_widget_ref( m_widget
);
3222 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3225 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3229 /* insert GTK representation */
3230 (*(newParent
->m_insertCallback
))(newParent
, this);
3233 /* reverse: prevent GTK from deleting the widget arbitrarily */
3234 gtk_widget_unref( m_widget
);
3239 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3241 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3243 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3245 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3250 /* insert GTK representation */
3251 (*m_insertCallback
)(this, child
);
3254 void wxWindowGTK::Raise()
3256 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3258 if (!m_widget
->window
) return;
3260 gdk_window_raise( m_widget
->window
);
3263 void wxWindowGTK::Lower()
3265 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3267 if (!m_widget
->window
) return;
3269 gdk_window_lower( m_widget
->window
);
3272 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3274 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3276 if (cursor
== m_cursor
)
3280 wxapp_install_idle_handler();
3282 if (cursor
== wxNullCursor
)
3283 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3285 return wxWindowBase::SetCursor( cursor
);
3288 void wxWindowGTK::WarpPointer( int x
, int y
)
3290 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3292 // We provide this function ourselves as it is
3293 // missing in GDK (top of this file).
3295 GdkWindow
*window
= (GdkWindow
*) NULL
;
3297 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3299 window
= GetConnectWidget()->window
;
3302 gdk_window_warp_pointer( window
, x
, y
);
3305 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3307 if (!m_widget
) return;
3308 if (!m_widget
->window
) return;
3312 wxapp_install_idle_handler();
3314 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3318 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3319 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3323 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3324 m_clearRegion
.Clear();
3325 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3333 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3334 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3338 GdkRectangle gdk_rect
;
3339 gdk_rect
.x
= rect
->x
;
3340 gdk_rect
.y
= rect
->y
;
3341 gdk_rect
.width
= rect
->width
;
3342 gdk_rect
.height
= rect
->height
;
3343 gtk_widget_draw( m_widget
, &gdk_rect
);
3350 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3351 m_updateRegion
.Clear();
3352 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3356 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3364 GdkRectangle gdk_rect
;
3365 gdk_rect
.x
= rect
->x
;
3366 gdk_rect
.y
= rect
->y
;
3367 gdk_rect
.width
= rect
->width
;
3368 gdk_rect
.height
= rect
->height
;
3369 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3373 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3379 void wxWindowGTK::Update()
3384 void wxWindowGTK::GtkUpdate()
3387 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3388 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3391 if (!m_updateRegion
.IsEmpty())
3392 GtkSendPaintEvents();
3395 void wxWindowGTK::GtkSendPaintEvents()
3399 m_clearRegion
.Clear();
3400 m_updateRegion
.Clear();
3404 // widget to draw on
3405 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3407 // Clip to paint region in wxClientDC
3408 m_clipPaintRegion
= TRUE
;
3410 if (GetThemeEnabled())
3412 // find ancestor from which to steal background
3413 wxWindow
*parent
= GetParent();
3414 while (parent
&& !parent
->IsTopLevel())
3415 parent
= parent
->GetParent();
3417 parent
= (wxWindow
*)this;
3419 wxRegionIterator
upd( m_updateRegion
);
3423 rect
.x
= upd
.GetX();
3424 rect
.y
= upd
.GetY();
3425 rect
.width
= upd
.GetWidth();
3426 rect
.height
= upd
.GetHeight();
3428 gtk_paint_flat_box( parent
->m_widget
->style
,
3441 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3443 wxWindowDC
dc( (wxWindow
*)this );
3444 dc
.SetClippingRegion( m_clearRegion
);
3446 wxEraseEvent
erase_event( GetId(), &dc
);
3447 erase_event
.SetEventObject( this );
3449 if (!GetEventHandler()->ProcessEvent(erase_event
))
3453 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3454 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3456 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3458 wxRegionIterator
upd( m_clearRegion
);
3461 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3462 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3466 m_clearRegion
.Clear();
3469 wxNcPaintEvent
nc_paint_event( GetId() );
3470 nc_paint_event
.SetEventObject( this );
3471 GetEventHandler()->ProcessEvent( nc_paint_event
);
3473 wxPaintEvent
paint_event( GetId() );
3474 paint_event
.SetEventObject( this );
3475 GetEventHandler()->ProcessEvent( paint_event
);
3477 m_clipPaintRegion
= FALSE
;
3479 #ifndef __WXUNIVERSAL__
3481 // The following code will result in all window-less widgets
3482 // being redrawn because the wxWindows class is allowed to
3483 // paint over the window-less widgets.
3485 GList
*children
= pizza
->children
;
3488 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3489 children
= children
->next
;
3491 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3492 GTK_WIDGET_DRAWABLE (child
->widget
))
3494 // Get intersection of widget area and update region
3495 wxRegion
region( m_updateRegion
);
3497 GdkEventExpose gdk_event
;
3498 gdk_event
.type
= GDK_EXPOSE
;
3499 gdk_event
.window
= pizza
->bin_window
;
3500 gdk_event
.count
= 0;
3502 wxRegionIterator
upd( m_updateRegion
);
3506 rect
.x
= upd
.GetX();
3507 rect
.y
= upd
.GetY();
3508 rect
.width
= upd
.GetWidth();
3509 rect
.height
= upd
.GetHeight();
3511 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3513 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3523 m_updateRegion
.Clear();
3526 void wxWindowGTK::Clear()
3528 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3530 if (m_wxwindow
&& m_wxwindow
->window
)
3532 m_clearRegion
.Clear();
3533 wxSize
size( GetClientSize() );
3534 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3536 // Better do this in idle?
3542 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3544 wxWindowBase::DoSetToolTip(tip
);
3547 m_tooltip
->Apply( (wxWindow
*)this );
3550 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3552 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3554 #endif // wxUSE_TOOLTIPS
3556 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3558 GdkWindow
*window
= (GdkWindow
*) NULL
;
3560 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3562 window
= GetConnectWidget()->window
;
3566 // We need the pixel value e.g. for background clearing.
3567 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3571 // wxMSW doesn't clear the window here, either.
3572 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3578 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3580 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3582 if (!wxWindowBase::SetBackgroundColour(colour
))
3585 GdkWindow
*window
= (GdkWindow
*) NULL
;
3587 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3589 window
= GetConnectWidget()->window
;
3593 // indicate that a new style has been set
3594 // but it couldn't get applied as the
3595 // widget hasn't been realized yet.
3596 m_delayedBackgroundColour
= TRUE
;
3601 GtkSetBackgroundColour( colour
);
3607 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3609 GdkWindow
*window
= (GdkWindow
*) NULL
;
3611 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3613 window
= GetConnectWidget()->window
;
3620 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3622 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3624 if (!wxWindowBase::SetForegroundColour(colour
))
3626 // don't leave if the GTK widget has just
3628 if (!m_delayedForegroundColour
) return FALSE
;
3631 GdkWindow
*window
= (GdkWindow
*) NULL
;
3633 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3635 window
= GetConnectWidget()->window
;
3639 // indicate that a new style has been set
3640 // but it couldn't get applied as the
3641 // widget hasn't been realized yet.
3642 m_delayedForegroundColour
= TRUE
;
3646 GtkSetForegroundColour( colour
);
3652 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3656 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3658 // FIXME: no more klass in 2.0
3660 remake
->klass
= m_widgetStyle
->klass
;
3663 gtk_style_unref( m_widgetStyle
);
3664 m_widgetStyle
= remake
;
3668 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3671 def
= gtk_widget_get_default_style();
3673 m_widgetStyle
= gtk_style_copy( def
);
3675 // FIXME: no more klass in 2.0
3677 m_widgetStyle
->klass
= def
->klass
;
3681 return m_widgetStyle
;
3684 void wxWindowGTK::SetWidgetStyle()
3686 #if DISABLE_STYLE_IF_BROKEN_THEME
3687 if (m_widget
->style
->engine_data
)
3689 static bool s_warningPrinted
= FALSE
;
3690 if (!s_warningPrinted
)
3692 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3693 s_warningPrinted
= TRUE
;
3695 m_widgetStyle
= m_widget
->style
;
3700 GtkStyle
*style
= GetWidgetStyle();
3702 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3704 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3707 if (m_foregroundColour
.Ok())
3709 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3710 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3712 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3713 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3714 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3718 // Try to restore the gtk default style. This is still a little
3719 // oversimplified for what is probably really needed here for controls
3720 // other than buttons, but is better than not being able to (re)set a
3721 // control's foreground colour to *wxBLACK -- RL
3722 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3725 def
= gtk_widget_get_default_style();
3727 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3728 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3729 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3733 if (m_backgroundColour
.Ok())
3735 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3736 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3738 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3739 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3740 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3741 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3742 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3743 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3744 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3745 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3749 // Try to restore the gtk default style. This is still a little
3750 // oversimplified for what is probably really needed here for controls
3751 // other than buttons, but is better than not being able to (re)set a
3752 // control's background colour to default grey and means resetting a
3753 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3755 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3758 def
= gtk_widget_get_default_style();
3760 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3761 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3762 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3763 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3764 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3765 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3766 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3767 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3772 void wxWindowGTK::ApplyWidgetStyle()
3776 //-----------------------------------------------------------------------------
3777 // Pop-up menu stuff
3778 //-----------------------------------------------------------------------------
3780 #if wxUSE_MENUS_NATIVE
3783 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3785 *is_waiting
= FALSE
;
3788 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3790 menu
->SetInvokingWindow( win
);
3791 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3794 wxMenuItem
*menuitem
= node
->GetData();
3795 if (menuitem
->IsSubMenu())
3797 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3800 node
= node
->GetNext();
3804 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3805 // wxPopupMenuPositionCallback()
3807 // should be safe even in the MT case as the user can hardly popup 2 menus
3808 // simultaneously, can he?
3809 static gint gs_pop_x
= 0;
3810 static gint gs_pop_y
= 0;
3812 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3815 gboolean
* WXUNUSED(whatever
),
3817 gpointer
WXUNUSED(user_data
) )
3819 // ensure that the menu appears entirely on screen
3821 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3823 wxSize sizeScreen
= wxGetDisplaySize();
3825 gint xmax
= sizeScreen
.x
- req
.width
,
3826 ymax
= sizeScreen
.y
- req
.height
;
3828 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3829 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3832 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3834 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3836 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3838 SetInvokingWindow( menu
, this );
3844 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3846 bool is_waiting
= TRUE
;
3848 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3850 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3851 (gpointer
)&is_waiting
);
3854 GTK_MENU(menu
->m_menu
),
3855 (GtkWidget
*) NULL
, // parent menu shell
3856 (GtkWidget
*) NULL
, // parent menu item
3857 wxPopupMenuPositionCallback
, // function to position it
3858 NULL
, // client data
3859 0, // button used to activate it
3860 gs_timeLastClick
// the time of activation
3865 while (gtk_events_pending())
3866 gtk_main_iteration();
3872 #endif // wxUSE_MENUS_NATIVE
3874 #if wxUSE_DRAG_AND_DROP
3876 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3878 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3880 GtkWidget
*dnd_widget
= GetConnectWidget();
3882 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3884 if (m_dropTarget
) delete m_dropTarget
;
3885 m_dropTarget
= dropTarget
;
3887 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3890 #endif // wxUSE_DRAG_AND_DROP
3892 GtkWidget
* wxWindowGTK::GetConnectWidget()
3894 GtkWidget
*connect_widget
= m_widget
;
3895 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3897 return connect_widget
;
3900 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3903 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3905 return (window
== m_widget
->window
);
3908 bool wxWindowGTK::SetFont( const wxFont
&font
)
3910 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3912 if (!wxWindowBase::SetFont(font
))
3917 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3918 if ( sysbg
== m_backgroundColour
)
3920 m_backgroundColour
= wxNullColour
;
3922 m_backgroundColour
= sysbg
;
3932 void wxWindowGTK::DoCaptureMouse()
3934 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3936 GdkWindow
*window
= (GdkWindow
*) NULL
;
3938 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3940 window
= GetConnectWidget()->window
;
3942 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3944 wxCursor
* cursor
= & m_cursor
;
3946 cursor
= wxSTANDARD_CURSOR
;
3948 gdk_pointer_grab( window
, FALSE
,
3950 (GDK_BUTTON_PRESS_MASK
|
3951 GDK_BUTTON_RELEASE_MASK
|
3952 GDK_POINTER_MOTION_HINT_MASK
|
3953 GDK_POINTER_MOTION_MASK
),
3955 cursor
->GetCursor(),
3956 (guint32
)GDK_CURRENT_TIME
);
3957 g_captureWindow
= this;
3958 g_captureWindowHasMouse
= TRUE
;
3961 void wxWindowGTK::DoReleaseMouse()
3963 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3965 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3967 g_captureWindow
= (wxWindowGTK
*) NULL
;
3969 GdkWindow
*window
= (GdkWindow
*) NULL
;
3971 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3973 window
= GetConnectWidget()->window
;
3978 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3982 wxWindow
*wxWindowBase::GetCapture()
3984 return (wxWindow
*)g_captureWindow
;
3987 bool wxWindowGTK::IsRetained() const
3992 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3993 int range
, bool refresh
)
3995 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3997 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3999 m_hasScrolling
= TRUE
;
4001 if (orient
== wxHORIZONTAL
)
4003 float fpos
= (float)pos
;
4004 float frange
= (float)range
;
4005 float fthumb
= (float)thumbVisible
;
4006 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4007 if (fpos
< 0.0) fpos
= 0.0;
4009 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4010 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4012 SetScrollPos( orient
, pos
, refresh
);
4016 m_oldHorizontalPos
= fpos
;
4018 m_hAdjust
->lower
= 0.0;
4019 m_hAdjust
->upper
= frange
;
4020 m_hAdjust
->value
= fpos
;
4021 m_hAdjust
->step_increment
= 1.0;
4022 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4023 m_hAdjust
->page_size
= fthumb
;
4027 float fpos
= (float)pos
;
4028 float frange
= (float)range
;
4029 float fthumb
= (float)thumbVisible
;
4030 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4031 if (fpos
< 0.0) fpos
= 0.0;
4033 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4034 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4036 SetScrollPos( orient
, pos
, refresh
);
4040 m_oldVerticalPos
= fpos
;
4042 m_vAdjust
->lower
= 0.0;
4043 m_vAdjust
->upper
= frange
;
4044 m_vAdjust
->value
= fpos
;
4045 m_vAdjust
->step_increment
= 1.0;
4046 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4047 m_vAdjust
->page_size
= fthumb
;
4050 if (orient
== wxHORIZONTAL
)
4051 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4053 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4056 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4058 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4060 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4062 if (orient
== wxHORIZONTAL
)
4064 float fpos
= (float)pos
;
4065 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4066 if (fpos
< 0.0) fpos
= 0.0;
4067 m_oldHorizontalPos
= fpos
;
4069 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4070 m_hAdjust
->value
= fpos
;
4074 float fpos
= (float)pos
;
4075 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4076 if (fpos
< 0.0) fpos
= 0.0;
4077 m_oldVerticalPos
= fpos
;
4079 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4080 m_vAdjust
->value
= fpos
;
4083 if (m_wxwindow
->window
)
4085 if (orient
== wxHORIZONTAL
)
4087 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4088 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4090 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4092 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4093 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4097 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4098 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4100 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4102 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4103 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4108 int wxWindowGTK::GetScrollThumb( int orient
) const
4110 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4112 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4114 if (orient
== wxHORIZONTAL
)
4115 return (int)(m_hAdjust
->page_size
+0.5);
4117 return (int)(m_vAdjust
->page_size
+0.5);
4120 int wxWindowGTK::GetScrollPos( int orient
) const
4122 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4124 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4126 if (orient
== wxHORIZONTAL
)
4127 return (int)(m_hAdjust
->value
+0.5);
4129 return (int)(m_vAdjust
->value
+0.5);
4132 int wxWindowGTK::GetScrollRange( int orient
) const
4134 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4136 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4138 if (orient
== wxHORIZONTAL
)
4139 return (int)(m_hAdjust
->upper
+0.5);
4141 return (int)(m_vAdjust
->upper
+0.5);
4144 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4146 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4148 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4150 // No scrolling requested.
4151 if ((dx
== 0) && (dy
== 0)) return;
4154 if (!m_updateRegion
.IsEmpty())
4156 m_updateRegion
.Offset( dx
, dy
);
4160 GetClientSize( &cw
, &ch
);
4161 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4164 if (!m_clearRegion
.IsEmpty())
4166 m_clearRegion
.Offset( dx
, dy
);
4170 GetClientSize( &cw
, &ch
);
4171 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4173 m_clipPaintRegion
= TRUE
;
4175 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4177 m_clipPaintRegion
= FALSE
;
4180 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4182 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4183 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4190 // Find the wxWindow at the current mouse position, also returning the mouse
4192 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4194 pt
= wxGetMousePosition();
4195 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4199 // Get the current mouse position.
4200 wxPoint
wxGetMousePosition()
4202 /* This crashes when used within wxHelpContext,
4203 so we have to use the X-specific implementation below.
4205 GdkModifierType *mask;
4206 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4208 return wxPoint(x, y);
4212 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4214 return wxPoint(-999, -999);
4216 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4217 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4218 Window rootReturn
, childReturn
;
4219 int rootX
, rootY
, winX
, winY
;
4220 unsigned int maskReturn
;
4222 XQueryPointer (display
,
4226 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4227 return wxPoint(rootX
, rootY
);
4231 // ----------------------------------------------------------------------------
4233 // ----------------------------------------------------------------------------
4235 class wxWinModule
: public wxModule
4242 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4245 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4247 bool wxWinModule::OnInit()
4249 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4250 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4255 void wxWinModule::OnExit()
4258 gdk_gc_unref( g_eraseGC
);