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
)
1069 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1070 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1072 // unknown key pressed, ignore (the event would be useless anyhow)
1076 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1081 wxWindowGTK
*ancestor
= win
;
1084 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1087 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1088 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1091 if (ancestor
->IsTopLevel())
1093 ancestor
= ancestor
->GetParent();
1096 #endif // wxUSE_ACCEL
1098 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1099 will only be sent if it is not in an accelerator table. */
1102 KeySym keysym
= gdk_event
->keyval
;
1103 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1106 if ( gdk_event
->length
== 1 )
1108 key_code
= (unsigned char)gdk_event
->string
[0];
1110 else if ( wxIsAsciiKeysym(keysym
) )
1113 key_code
= (unsigned char)keysym
;
1119 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1121 // reuse the same event object, just change its type and use the
1122 // translated keycode instead of the raw one
1123 event
.SetEventType(wxEVT_CHAR
);
1124 event
.m_keyCode
= key_code
;
1126 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1130 /* win is a control: tab can be propagated up */
1132 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1133 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1134 // have this style, yet choose not to process this particular TAB in which
1135 // case TAB must still work as a navigational character
1137 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1139 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1141 wxNavigationKeyEvent new_event
;
1142 new_event
.SetEventObject( win
->GetParent() );
1143 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1144 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1145 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1146 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1147 new_event
.SetCurrentFocus( win
);
1148 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1151 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1153 (gdk_event
->keyval
== GDK_Escape
) )
1155 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1156 new_event
.SetEventObject( win
);
1157 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1161 #if 0 // (GTK_MINOR_VERSION > 0)
1162 /* Pressing F10 will activate the menu bar of the top frame. */
1164 (gdk_event
->keyval
== GDK_F10
) )
1166 wxWindowGTK
*ancestor
= win
;
1169 if (wxIsKindOf(ancestor
,wxFrame
))
1171 wxFrame
*frame
= (wxFrame
*) ancestor
;
1172 wxMenuBar
*menubar
= frame
->GetMenuBar();
1175 wxNode
*node
= menubar
->GetMenus().First();
1178 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1179 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1185 ancestor
= ancestor
->GetParent();
1192 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1199 //-----------------------------------------------------------------------------
1200 // "key_release_event" from any window
1201 //-----------------------------------------------------------------------------
1203 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1204 GdkEventKey
*gdk_event
,
1210 wxapp_install_idle_handler();
1215 if (g_blockEventsOnDrag
)
1218 wxKeyEvent
event( wxEVT_KEY_UP
);
1219 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1221 // unknown key pressed, ignore (the event would be useless anyhow
1225 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1228 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1232 // ============================================================================
1234 // ============================================================================
1236 // ----------------------------------------------------------------------------
1237 // mouse event processing helpers
1238 // ----------------------------------------------------------------------------
1240 // init wxMouseEvent with the info from gdk_event
1241 #define InitMouseEvent(win, event, gdk_event) \
1243 event.SetTimestamp( gdk_event->time ); \
1244 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1245 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1246 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1247 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1248 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1249 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1250 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1252 wxPoint pt = win->GetClientAreaOrigin(); \
1253 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1254 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1257 static void AdjustEventButtonState(wxMouseEvent
& event
)
1259 // GDK reports the old state of the button for a button press event, but
1260 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1261 // for a LEFT_DOWN event, not FALSE, so we will invert
1262 // left/right/middleDown for the corresponding click events
1264 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1265 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1266 (event
.GetEventType() == wxEVT_LEFT_UP
))
1268 event
.m_leftDown
= !event
.m_leftDown
;
1272 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1273 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1274 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1276 event
.m_middleDown
= !event
.m_middleDown
;
1280 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1281 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1282 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1284 event
.m_rightDown
= !event
.m_rightDown
;
1289 // find the window to send the mouse event too
1291 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1293 if (win
->m_wxwindow
)
1295 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1296 x
+= pizza
->xoffset
;
1297 y
+= pizza
->yoffset
;
1300 wxNode
*node
= win
->GetChildren().First();
1303 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1305 node
= node
->Next();
1306 if (!child
->IsShown())
1309 if (child
->IsTransparentForMouse())
1311 // wxStaticBox is transparent in the box itself
1312 int xx1
= child
->m_x
;
1313 int yy1
= child
->m_y
;
1314 int xx2
= child
->m_x
+ child
->m_width
;
1315 int yy2
= child
->m_x
+ child
->m_height
;
1318 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1320 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1322 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1324 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1335 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1336 (child
->m_x
<= x
) &&
1337 (child
->m_y
<= y
) &&
1338 (child
->m_x
+child
->m_width
>= x
) &&
1339 (child
->m_y
+child
->m_height
>= y
))
1352 //-----------------------------------------------------------------------------
1353 // "button_press_event"
1354 //-----------------------------------------------------------------------------
1356 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1357 GdkEventButton
*gdk_event
,
1363 wxapp_install_idle_handler();
1366 wxPrintf( wxT("1) OnButtonPress from ") );
1367 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1368 wxPrintf( win->GetClassInfo()->GetClassName() );
1369 wxPrintf( wxT(".\n") );
1371 if (!win
->m_hasVMT
) return FALSE
;
1372 if (g_blockEventsOnDrag
) return TRUE
;
1373 if (g_blockEventsOnScroll
) return TRUE
;
1375 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1377 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1379 gtk_widget_grab_focus( win
->m_wxwindow
);
1381 wxPrintf( wxT("GrabFocus from ") );
1382 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1383 wxPrintf( win->GetClassInfo()->GetClassName() );
1384 wxPrintf( wxT(".\n") );
1388 wxEventType event_type
= wxEVT_NULL
;
1390 if (gdk_event
->button
== 1)
1392 switch (gdk_event
->type
)
1394 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1395 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1399 else if (gdk_event
->button
== 2)
1401 switch (gdk_event
->type
)
1403 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1404 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1408 else if (gdk_event
->button
== 3)
1410 switch (gdk_event
->type
)
1412 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1413 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1418 if ( event_type
== wxEVT_NULL
)
1420 // unknown mouse button or click type
1424 wxMouseEvent
event( event_type
);
1425 InitMouseEvent( win
, event
, gdk_event
);
1427 AdjustEventButtonState(event
);
1429 // wxListBox actually get mouse events from the item, so we need to give it
1430 // a chance to correct this
1431 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1433 // find the correct window to send the event too: it may be a different one
1434 // from the one which got it at GTK+ level because some control don't have
1435 // their own X window and thus cannot get any events.
1436 if ( !g_captureWindow
)
1437 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1439 event
.SetEventObject( win
);
1441 gs_timeLastClick
= gdk_event
->time
;
1444 wxPrintf( wxT("2) OnButtonPress from ") );
1445 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1446 wxPrintf( win->GetClassInfo()->GetClassName() );
1447 wxPrintf( wxT(".\n") );
1450 if (win
->GetEventHandler()->ProcessEvent( event
))
1452 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1459 //-----------------------------------------------------------------------------
1460 // "button_release_event"
1461 //-----------------------------------------------------------------------------
1463 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1468 wxapp_install_idle_handler();
1470 if (!win
->m_hasVMT
) return FALSE
;
1471 if (g_blockEventsOnDrag
) return FALSE
;
1472 if (g_blockEventsOnScroll
) return FALSE
;
1474 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1477 printf( "OnButtonRelease from " );
1478 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1479 printf( win->GetClassInfo()->GetClassName() );
1483 wxEventType event_type
= wxEVT_NULL
;
1485 switch (gdk_event
->button
)
1487 case 1: event_type
= wxEVT_LEFT_UP
; break;
1488 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1489 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1490 default: return FALSE
;
1493 wxMouseEvent
event( event_type
);
1494 InitMouseEvent( win
, event
, gdk_event
);
1496 AdjustEventButtonState(event
);
1498 // same wxListBox hack as above
1499 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1501 if ( !g_captureWindow
)
1502 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1504 event
.SetEventObject( win
);
1506 if (win
->GetEventHandler()->ProcessEvent( event
))
1508 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1515 //-----------------------------------------------------------------------------
1516 // "motion_notify_event"
1517 //-----------------------------------------------------------------------------
1519 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1520 GdkEventMotion
*gdk_event
,
1526 wxapp_install_idle_handler();
1528 if (!win
->m_hasVMT
) return FALSE
;
1529 if (g_blockEventsOnDrag
) return FALSE
;
1530 if (g_blockEventsOnScroll
) return FALSE
;
1532 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1534 if (gdk_event
->is_hint
)
1538 GdkModifierType state
;
1539 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1545 printf( "OnMotion from " );
1546 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1547 printf( win->GetClassInfo()->GetClassName() );
1551 wxMouseEvent
event( wxEVT_MOTION
);
1552 InitMouseEvent(win
, event
, gdk_event
);
1554 if ( g_captureWindow
)
1556 // synthetize a mouse enter or leave event if needed
1557 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1558 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1559 if ( hasMouse
!= g_captureWindowHasMouse
)
1561 // the mouse changed window
1562 g_captureWindowHasMouse
= hasMouse
;
1564 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1565 : wxEVT_LEAVE_WINDOW
);
1566 InitMouseEvent(win
, event
, gdk_event
);
1567 event
.SetEventObject(win
);
1568 win
->GetEventHandler()->ProcessEvent(event
);
1573 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1576 event
.SetEventObject( win
);
1578 if (win
->GetEventHandler()->ProcessEvent( event
))
1580 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1587 //-----------------------------------------------------------------------------
1589 //-----------------------------------------------------------------------------
1591 // send the wxChildFocusEvent and wxFocusEvent, common code of
1592 // gtk_window_focus_in_callback() and SetFocus()
1593 static bool DoSendFocusEvents(wxWindow
*win
)
1595 // Notify the parent keeping track of focus for the kbd navigation
1596 // purposes that we got it.
1597 wxChildFocusEvent
eventChildFocus(win
);
1598 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1600 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1601 eventFocus
.SetEventObject(win
);
1603 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1606 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1607 GdkEvent
*WXUNUSED(event
),
1613 wxapp_install_idle_handler();
1615 if (!win
->m_hasVMT
) return FALSE
;
1616 if (g_blockEventsOnDrag
) return FALSE
;
1618 switch ( g_sendActivateEvent
)
1621 // we've got focus from outside, synthetize wxActivateEvent
1622 g_sendActivateEvent
= 1;
1626 // another our window just lost focus, it was already ours before
1627 // - don't send any wxActivateEvent
1628 g_sendActivateEvent
= -1;
1633 g_focusWindow
= win
;
1635 wxLogTrace(TRACE_FOCUS
,
1636 _T("%s: focus in"), win
->GetName().c_str());
1640 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1644 // caret needs to be informed about focus change
1645 wxCaret
*caret
= win
->GetCaret();
1648 caret
->OnSetFocus();
1650 #endif // wxUSE_CARET
1652 g_activeFrameLostFocus
= FALSE
;
1654 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1655 if ( active
!= g_activeFrame
)
1657 if ( g_activeFrame
)
1659 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1660 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1661 event
.SetEventObject(g_activeFrame
);
1662 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1665 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1666 g_activeFrame
= active
;
1667 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1668 event
.SetEventObject(g_activeFrame
);
1669 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1671 // Don't send focus events in addition to activate
1672 // if (win == g_activeFrame)
1676 // does the window itself think that it has the focus?
1677 if ( !win
->m_hasFocus
)
1679 // not yet, notify it
1680 win
->m_hasFocus
= TRUE
;
1682 if ( DoSendFocusEvents(win
) )
1684 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1692 //-----------------------------------------------------------------------------
1693 // "focus_out_event"
1694 //-----------------------------------------------------------------------------
1696 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1701 wxapp_install_idle_handler();
1703 if (!win
->m_hasVMT
) return FALSE
;
1704 if (g_blockEventsOnDrag
) return FALSE
;
1706 wxLogTrace( TRACE_FOCUS
,
1707 _T("%s: focus out"), win
->GetName().c_str() );
1709 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1711 // VZ: commenting this out because it does happen (although not easy
1712 // to reproduce, I only see it when using wxMiniFrame and not
1713 // always) and makes using Mahogany quite annoying
1715 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1716 wxT("unfocusing window that hasn't gained focus properly") )
1719 g_activeFrameLostFocus
= TRUE
;
1722 // if the focus goes out of our app alltogether, OnIdle() will send
1723 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1724 // g_sendActivateEvent to -1
1725 g_sendActivateEvent
= 0;
1727 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1731 g_focusWindow
= (wxWindowGTK
*)NULL
;
1739 // caret needs to be informed about focus change
1740 wxCaret
*caret
= win
->GetCaret();
1743 caret
->OnKillFocus();
1745 #endif // wxUSE_CARET
1747 // don't send the window a kill focus event if it thinks that it doesn't
1748 // have focus already
1749 if ( win
->m_hasFocus
)
1751 win
->m_hasFocus
= FALSE
;
1753 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1754 event
.SetEventObject( win
);
1756 if (win
->GetEventHandler()->ProcessEvent( event
))
1758 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1766 //-----------------------------------------------------------------------------
1767 // "enter_notify_event"
1768 //-----------------------------------------------------------------------------
1770 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1775 wxapp_install_idle_handler();
1777 if (!win
->m_hasVMT
) return FALSE
;
1778 if (g_blockEventsOnDrag
) return FALSE
;
1780 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1782 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1783 event
.SetTimestamp( gdk_event
->time
);
1784 event
.SetEventObject( win
);
1788 GdkModifierType state
= (GdkModifierType
)0;
1790 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1792 InitMouseEvent(win
, event
, gdk_event
);
1793 wxPoint pt
= win
->GetClientAreaOrigin();
1794 event
.m_x
= x
+ pt
.x
;
1795 event
.m_y
= y
+ pt
.y
;
1797 if (win
->GetEventHandler()->ProcessEvent( event
))
1799 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1806 //-----------------------------------------------------------------------------
1807 // "leave_notify_event"
1808 //-----------------------------------------------------------------------------
1810 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1815 wxapp_install_idle_handler();
1817 if (!win
->m_hasVMT
) return FALSE
;
1818 if (g_blockEventsOnDrag
) return FALSE
;
1820 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1822 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1823 event
.SetTimestamp( gdk_event
->time
);
1824 event
.SetEventObject( win
);
1828 GdkModifierType state
= (GdkModifierType
)0;
1830 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1832 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1833 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1834 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1835 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1836 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1837 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1838 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1840 wxPoint pt
= win
->GetClientAreaOrigin();
1841 event
.m_x
= x
+ pt
.x
;
1842 event
.m_y
= y
+ pt
.y
;
1844 if (win
->GetEventHandler()->ProcessEvent( event
))
1846 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1853 //-----------------------------------------------------------------------------
1854 // "value_changed" from m_vAdjust
1855 //-----------------------------------------------------------------------------
1857 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1864 wxapp_install_idle_handler();
1866 if (g_blockEventsOnDrag
) return;
1868 if (!win
->m_hasVMT
) return;
1870 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1871 if (fabs(diff
) < 0.2) return;
1873 win
->m_oldVerticalPos
= adjust
->value
;
1875 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1876 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
1878 int value
= (int)(adjust
->value
+0.5);
1880 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1881 event
.SetEventObject( win
);
1882 win
->GetEventHandler()->ProcessEvent( event
);
1885 //-----------------------------------------------------------------------------
1886 // "value_changed" from m_hAdjust
1887 //-----------------------------------------------------------------------------
1889 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1896 wxapp_install_idle_handler();
1898 if (g_blockEventsOnDrag
) return;
1899 if (!win
->m_hasVMT
) return;
1901 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1902 if (fabs(diff
) < 0.2) return;
1904 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1905 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
1907 win
->m_oldHorizontalPos
= adjust
->value
;
1909 int value
= (int)(adjust
->value
+0.5);
1911 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1912 event
.SetEventObject( win
);
1913 win
->GetEventHandler()->ProcessEvent( event
);
1916 //-----------------------------------------------------------------------------
1917 // "button_press_event" from scrollbar
1918 //-----------------------------------------------------------------------------
1920 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1921 GdkEventButton
*gdk_event
,
1927 wxapp_install_idle_handler();
1930 g_blockEventsOnScroll
= TRUE
;
1932 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1934 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1940 //-----------------------------------------------------------------------------
1941 // "button_release_event" from scrollbar
1942 //-----------------------------------------------------------------------------
1944 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1945 GdkEventButton
*WXUNUSED(gdk_event
),
1950 // don't test here as we can release the mouse while being over
1951 // a different window than the slider
1953 // if (gdk_event->window != widget->slider) return FALSE;
1955 g_blockEventsOnScroll
= FALSE
;
1957 if (win
->m_isScrolling
)
1959 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1963 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1964 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1966 value
= (int)(win
->m_hAdjust
->value
+0.5);
1969 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
1971 value
= (int)(win
->m_vAdjust
->value
+0.5);
1975 wxScrollWinEvent
event( command
, value
, dir
);
1976 event
.SetEventObject( win
);
1977 win
->GetEventHandler()->ProcessEvent( event
);
1980 win
->m_isScrolling
= FALSE
;
1985 // ----------------------------------------------------------------------------
1986 // this wxWindowBase function is implemented here (in platform-specific file)
1987 // because it is static and so couldn't be made virtual
1988 // ----------------------------------------------------------------------------
1990 wxWindow
*wxWindowBase::FindFocus()
1992 // the cast is necessary when we compile in wxUniversal mode
1993 return (wxWindow
*)g_focusWindow
;
1996 //-----------------------------------------------------------------------------
1997 // "realize" from m_widget
1998 //-----------------------------------------------------------------------------
2000 /* We cannot set colours and fonts before the widget has
2001 been realized, so we do this directly after realization. */
2004 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2009 wxapp_install_idle_handler();
2011 if (win
->m_delayedBackgroundColour
)
2012 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2014 if (win
->m_delayedForegroundColour
)
2015 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2017 wxWindowCreateEvent
event( win
);
2018 event
.SetEventObject( win
);
2019 win
->GetEventHandler()->ProcessEvent( event
);
2024 //-----------------------------------------------------------------------------
2026 //-----------------------------------------------------------------------------
2029 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2030 GtkAllocation
*WXUNUSED(alloc
),
2034 wxapp_install_idle_handler();
2036 if (!win
->m_hasScrolling
) return;
2038 int client_width
= 0;
2039 int client_height
= 0;
2040 win
->GetClientSize( &client_width
, &client_height
);
2041 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2044 win
->m_oldClientWidth
= client_width
;
2045 win
->m_oldClientHeight
= client_height
;
2047 if (!win
->m_nativeSizeEvent
)
2049 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2050 event
.SetEventObject( win
);
2051 win
->GetEventHandler()->ProcessEvent( event
);
2057 #define WXUNUSED_UNLESS_XIM(param) param
2059 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2062 /* Resize XIM window */
2065 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2066 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2067 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2070 wxapp_install_idle_handler();
2076 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2080 gdk_window_get_size (widget
->window
, &width
, &height
);
2081 win
->m_icattr
->preedit_area
.width
= width
;
2082 win
->m_icattr
->preedit_area
.height
= height
;
2083 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2088 //-----------------------------------------------------------------------------
2089 // "realize" from m_wxwindow
2090 //-----------------------------------------------------------------------------
2092 /* Initialize XIM support */
2095 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2096 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2099 wxapp_install_idle_handler();
2102 if (win
->m_ic
) return FALSE
;
2103 if (!widget
) return FALSE
;
2104 if (!gdk_im_ready()) return FALSE
;
2106 win
->m_icattr
= gdk_ic_attr_new();
2107 if (!win
->m_icattr
) return FALSE
;
2111 GdkColormap
*colormap
;
2112 GdkICAttr
*attr
= win
->m_icattr
;
2113 unsigned attrmask
= GDK_IC_ALL_REQ
;
2115 GdkIMStyle supported_style
= (GdkIMStyle
)
2116 (GDK_IM_PREEDIT_NONE
|
2117 GDK_IM_PREEDIT_NOTHING
|
2118 GDK_IM_PREEDIT_POSITION
|
2119 GDK_IM_STATUS_NONE
|
2120 GDK_IM_STATUS_NOTHING
);
2122 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2123 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2125 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2126 attr
->client_window
= widget
->window
;
2128 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2129 gtk_widget_get_default_colormap ())
2131 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2132 attr
->preedit_colormap
= colormap
;
2135 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2136 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2137 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2138 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2140 switch (style
& GDK_IM_PREEDIT_MASK
)
2142 case GDK_IM_PREEDIT_POSITION
:
2143 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2145 g_warning ("over-the-spot style requires fontset");
2149 gdk_window_get_size (widget
->window
, &width
, &height
);
2151 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2152 attr
->spot_location
.x
= 0;
2153 attr
->spot_location
.y
= height
;
2154 attr
->preedit_area
.x
= 0;
2155 attr
->preedit_area
.y
= 0;
2156 attr
->preedit_area
.width
= width
;
2157 attr
->preedit_area
.height
= height
;
2158 attr
->preedit_fontset
= widget
->style
->font
;
2163 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2165 if (win
->m_ic
== NULL
)
2166 g_warning ("Can't create input context.");
2169 mask
= gdk_window_get_events (widget
->window
);
2170 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2171 gdk_window_set_events (widget
->window
, mask
);
2173 if (GTK_WIDGET_HAS_FOCUS(widget
))
2174 gdk_im_begin (win
->m_ic
, widget
->window
);
2181 //-----------------------------------------------------------------------------
2182 // InsertChild for wxWindowGTK.
2183 //-----------------------------------------------------------------------------
2185 /* Callback for wxWindowGTK. This very strange beast has to be used because
2186 * C++ has no virtual methods in a constructor. We have to emulate a
2187 * virtual function here as wxNotebook requires a different way to insert
2188 * a child in it. I had opted for creating a wxNotebookPage window class
2189 * which would have made this superfluous (such in the MDI window system),
2190 * but no-one was listening to me... */
2192 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2194 /* the window might have been scrolled already, do we
2195 have to adapt the position */
2196 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2197 child
->m_x
+= pizza
->xoffset
;
2198 child
->m_y
+= pizza
->yoffset
;
2200 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2201 GTK_WIDGET(child
->m_widget
),
2208 //-----------------------------------------------------------------------------
2210 //-----------------------------------------------------------------------------
2212 wxWindow
*wxGetActiveWindow()
2214 return wxWindow::FindFocus();
2217 //-----------------------------------------------------------------------------
2219 //-----------------------------------------------------------------------------
2221 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2223 #ifdef __WXUNIVERSAL__
2224 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2226 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2227 #endif // __WXUNIVERSAL__/__WXGTK__
2229 void wxWindowGTK::Init()
2235 m_widget
= (GtkWidget
*) NULL
;
2236 m_wxwindow
= (GtkWidget
*) NULL
;
2237 m_focusWidget
= (GtkWidget
*) NULL
;
2247 m_needParent
= TRUE
;
2248 m_isBeingDeleted
= FALSE
;
2251 m_nativeSizeEvent
= FALSE
;
2253 m_hasScrolling
= FALSE
;
2254 m_isScrolling
= FALSE
;
2256 m_hAdjust
= (GtkAdjustment
*) NULL
;
2257 m_vAdjust
= (GtkAdjustment
*) NULL
;
2258 m_oldHorizontalPos
= 0.0;
2259 m_oldVerticalPos
= 0.0;
2262 m_widgetStyle
= (GtkStyle
*) NULL
;
2264 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2266 m_acceptsFocus
= FALSE
;
2269 m_clipPaintRegion
= FALSE
;
2271 m_cursor
= *wxSTANDARD_CURSOR
;
2273 m_delayedForegroundColour
= FALSE
;
2274 m_delayedBackgroundColour
= FALSE
;
2277 m_ic
= (GdkIC
*) NULL
;
2278 m_icattr
= (GdkICAttr
*) NULL
;
2282 wxWindowGTK::wxWindowGTK()
2287 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2292 const wxString
&name
)
2296 Create( parent
, id
, pos
, size
, style
, name
);
2299 bool wxWindowGTK::Create( wxWindow
*parent
,
2304 const wxString
&name
)
2306 if (!PreCreation( parent
, pos
, size
) ||
2307 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2309 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2313 m_insertCallback
= wxInsertChildInWindow
;
2315 // always needed for background clearing
2316 m_delayedBackgroundColour
= TRUE
;
2318 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2319 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2321 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2323 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2324 scroll_class
->scrollbar_spacing
= 0;
2326 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2328 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2329 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2331 m_wxwindow
= gtk_pizza_new();
2333 #ifndef __WXUNIVERSAL__
2334 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2336 if (HasFlag(wxRAISED_BORDER
))
2338 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2340 else if (HasFlag(wxSUNKEN_BORDER
))
2342 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2344 else if (HasFlag(wxSIMPLE_BORDER
))
2346 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2350 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2352 #endif // __WXUNIVERSAL__
2354 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2356 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2357 m_acceptsFocus
= TRUE
;
2359 // I _really_ don't want scrollbars in the beginning
2360 m_vAdjust
->lower
= 0.0;
2361 m_vAdjust
->upper
= 1.0;
2362 m_vAdjust
->value
= 0.0;
2363 m_vAdjust
->step_increment
= 1.0;
2364 m_vAdjust
->page_increment
= 1.0;
2365 m_vAdjust
->page_size
= 5.0;
2366 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2367 m_hAdjust
->lower
= 0.0;
2368 m_hAdjust
->upper
= 1.0;
2369 m_hAdjust
->value
= 0.0;
2370 m_hAdjust
->step_increment
= 1.0;
2371 m_hAdjust
->page_increment
= 1.0;
2372 m_hAdjust
->page_size
= 5.0;
2373 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2375 // these handlers block mouse events to any window during scrolling such as
2376 // motion events and prevent GTK and wxWindows from fighting over where the
2379 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2380 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2382 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2383 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2385 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2386 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2388 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2389 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2391 // these handlers get notified when screen updates are required either when
2392 // scrolling or when the window size (and therefore scrollbar configuration)
2395 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2396 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2397 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2398 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2400 gtk_widget_show( m_wxwindow
);
2403 m_parent
->DoAddChild( this );
2405 m_focusWidget
= m_wxwindow
;
2414 wxWindowGTK::~wxWindowGTK()
2416 if (g_focusWindow
== this)
2417 g_focusWindow
= NULL
;
2419 if (g_activeFrame
== this)
2420 g_activeFrame
= NULL
;
2422 if ( g_delayedFocus
== this )
2423 g_delayedFocus
= NULL
;
2425 m_isBeingDeleted
= TRUE
;
2434 m_parent
->RemoveChild( this );
2438 gdk_ic_destroy (m_ic
);
2440 gdk_ic_attr_destroy (m_icattr
);
2445 #if DISABLE_STYLE_IF_BROKEN_THEME
2446 // don't delete if it's a pixmap theme style
2447 if (!m_widgetStyle
->engine_data
)
2448 gtk_style_unref( m_widgetStyle
);
2450 m_widgetStyle
= (GtkStyle
*) NULL
;
2455 gtk_widget_destroy( m_wxwindow
);
2456 m_wxwindow
= (GtkWidget
*) NULL
;
2461 gtk_widget_destroy( m_widget
);
2462 m_widget
= (GtkWidget
*) NULL
;
2466 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2468 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2470 /* this turns -1 into 20 so that a minimal window is
2471 visible even although -1,-1 has been given as the
2472 size of the window. the same trick is used in other
2473 ports and should make debugging easier */
2474 m_width
= WidthDefault(size
.x
);
2475 m_height
= HeightDefault(size
.y
);
2480 /* some reasonable defaults */
2485 m_x
= (gdk_screen_width () - m_width
) / 2;
2486 if (m_x
< 10) m_x
= 10;
2490 m_y
= (gdk_screen_height () - m_height
) / 2;
2491 if (m_y
< 10) m_y
= 10;
2498 void wxWindowGTK::PostCreation()
2500 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2506 // these get reported to wxWindows -> wxPaintEvent
2508 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2510 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2511 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2514 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2515 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2517 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2519 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2520 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2523 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2527 // these are called when the "sunken" or "raised" borders are drawn
2528 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2529 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2532 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2533 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2539 if (m_focusWidget
== NULL
)
2540 m_focusWidget
= m_widget
;
2542 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2543 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2545 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2546 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2548 // connect to the various key and mouse handlers
2550 GtkWidget
*connect_widget
= GetConnectWidget();
2552 ConnectWidget( connect_widget
);
2554 /* We cannot set colours, fonts and cursors before the widget has
2555 been realized, so we do this directly after realization */
2556 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2557 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2561 // Catch native resize events
2562 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2563 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2565 // Initialize XIM support
2566 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2567 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2569 // And resize XIM window
2570 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2571 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2574 if (!GTK_IS_COMBO(m_widget
))
2576 // This is needed if we want to add our windows into native
2577 // GTK control, such as the toolbar. With this callback, the
2578 // toolbar gets to know the correct size (the one set by the
2579 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2580 // when moving to GTK 2.0.
2581 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2582 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2588 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2590 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2591 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2593 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2594 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2596 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2597 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2599 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2600 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2602 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2603 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2605 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2606 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2608 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2609 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2612 bool wxWindowGTK::Destroy()
2614 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2618 return wxWindowBase::Destroy();
2621 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2623 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2626 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2628 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2629 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2632 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2635 if (m_resizing
) return; /* I don't like recursions */
2638 int currentX
, currentY
;
2639 GetPosition(¤tX
, ¤tY
);
2644 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2646 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2648 /* don't set the size for children of wxNotebook, just take the values. */
2656 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2657 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2659 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2660 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2661 if (width
!= -1) m_width
= width
;
2662 if (height
!= -1) m_height
= height
;
2666 m_x
= x
+ pizza
->xoffset
;
2667 m_y
= y
+ pizza
->yoffset
;
2672 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2674 if (width
== -1) m_width
= 80;
2677 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2679 if (height
== -1) m_height
= 26;
2682 int minWidth
= GetMinWidth(),
2683 minHeight
= GetMinHeight(),
2684 maxWidth
= GetMaxWidth(),
2685 maxHeight
= GetMaxHeight();
2687 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2688 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2689 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2690 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2693 int bottom_border
= 0;
2696 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2698 /* the default button has a border around it */
2704 DoMoveWindow( m_x
-border
,
2707 m_height
+border
+bottom_border
);
2712 /* Sometimes the client area changes size without the
2713 whole windows's size changing, but if the whole
2714 windows's size doesn't change, no wxSizeEvent will
2715 normally be sent. Here we add an extra test if
2716 the client test has been changed and this will
2718 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2722 wxPrintf( "OnSize sent from " );
2723 if (GetClassInfo() && GetClassInfo()->GetClassName())
2724 wxPrintf( GetClassInfo()->GetClassName() );
2725 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2728 if (!m_nativeSizeEvent
)
2730 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2731 event
.SetEventObject( this );
2732 GetEventHandler()->ProcessEvent( event
);
2738 void wxWindowGTK::OnInternalIdle()
2740 // Update invalidated regions.
2743 // Synthetize activate events.
2744 if ( g_sendActivateEvent
!= -1 )
2746 bool activate
= g_sendActivateEvent
!= 0;
2749 g_sendActivateEvent
= -1;
2751 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2754 if ( g_activeFrameLostFocus
)
2756 if ( g_activeFrame
)
2758 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2759 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2760 event
.SetEventObject(g_activeFrame
);
2761 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2762 g_activeFrame
= NULL
;
2764 g_activeFrameLostFocus
= FALSE
;
2767 wxCursor cursor
= m_cursor
;
2768 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2772 /* I now set the cursor anew in every OnInternalIdle call
2773 as setting the cursor in a parent window also effects the
2774 windows above so that checking for the current cursor is
2779 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2781 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2783 if (!g_globalCursor
.Ok())
2784 cursor
= *wxSTANDARD_CURSOR
;
2786 window
= m_widget
->window
;
2787 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2788 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2794 GdkWindow
*window
= m_widget
->window
;
2795 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2796 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2804 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2806 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2808 if (width
) (*width
) = m_width
;
2809 if (height
) (*height
) = m_height
;
2812 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2814 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2818 SetSize( width
, height
);
2825 #ifndef __WXUNIVERSAL__
2826 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2828 /* when using GTK 1.2 we set the shadow border size to 2 */
2832 if (HasFlag(wxSIMPLE_BORDER
))
2834 /* when using GTK 1.2 we set the simple border size to 1 */
2838 #endif // __WXUNIVERSAL__
2842 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2844 GtkRequisition vscroll_req
;
2845 vscroll_req
.width
= 2;
2846 vscroll_req
.height
= 2;
2847 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2848 (scroll_window
->vscrollbar
, &vscroll_req
);
2850 GtkRequisition hscroll_req
;
2851 hscroll_req
.width
= 2;
2852 hscroll_req
.height
= 2;
2853 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2854 (scroll_window
->hscrollbar
, &hscroll_req
);
2856 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2858 if (scroll_window
->vscrollbar_visible
)
2860 dw
+= vscroll_req
.width
;
2861 dw
+= scroll_class
->scrollbar_spacing
;
2864 if (scroll_window
->hscrollbar_visible
)
2866 dh
+= hscroll_req
.height
;
2867 dh
+= scroll_class
->scrollbar_spacing
;
2871 SetSize( width
+dw
, height
+dh
);
2875 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2877 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2881 if (width
) (*width
) = m_width
;
2882 if (height
) (*height
) = m_height
;
2889 #ifndef __WXUNIVERSAL__
2890 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2892 /* when using GTK 1.2 we set the shadow border size to 2 */
2896 if (HasFlag(wxSIMPLE_BORDER
))
2898 /* when using GTK 1.2 we set the simple border size to 1 */
2902 #endif // __WXUNIVERSAL__
2906 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2908 GtkRequisition vscroll_req
;
2909 vscroll_req
.width
= 2;
2910 vscroll_req
.height
= 2;
2911 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2912 (scroll_window
->vscrollbar
, &vscroll_req
);
2914 GtkRequisition hscroll_req
;
2915 hscroll_req
.width
= 2;
2916 hscroll_req
.height
= 2;
2917 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2918 (scroll_window
->hscrollbar
, &hscroll_req
);
2920 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2922 if (scroll_window
->vscrollbar_visible
)
2924 dw
+= vscroll_req
.width
;
2925 dw
+= scroll_class
->scrollbar_spacing
;
2928 if (scroll_window
->hscrollbar_visible
)
2930 dh
+= hscroll_req
.height
;
2931 dh
+= scroll_class
->scrollbar_spacing
;
2935 if (width
) (*width
) = m_width
- dw
;
2936 if (height
) (*height
) = m_height
- dh
;
2940 printf( "GetClientSize, name %s ", GetName().c_str() );
2941 if (width) printf( " width = %d", (*width) );
2942 if (height) printf( " height = %d", (*height) );
2947 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2949 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2953 if (m_parent
&& m_parent
->m_wxwindow
)
2955 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2956 dx
= pizza
->xoffset
;
2957 dy
= pizza
->yoffset
;
2960 if (x
) (*x
) = m_x
- dx
;
2961 if (y
) (*y
) = m_y
- dy
;
2964 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2966 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2968 if (!m_widget
->window
) return;
2970 GdkWindow
*source
= (GdkWindow
*) NULL
;
2972 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2974 source
= m_widget
->window
;
2978 gdk_window_get_origin( source
, &org_x
, &org_y
);
2982 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2984 org_x
+= m_widget
->allocation
.x
;
2985 org_y
+= m_widget
->allocation
.y
;
2993 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
2995 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2997 if (!m_widget
->window
) return;
2999 GdkWindow
*source
= (GdkWindow
*) NULL
;
3001 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3003 source
= m_widget
->window
;
3007 gdk_window_get_origin( source
, &org_x
, &org_y
);
3011 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3013 org_x
+= m_widget
->allocation
.x
;
3014 org_y
+= m_widget
->allocation
.y
;
3022 bool wxWindowGTK::Show( bool show
)
3024 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3026 if (!wxWindowBase::Show(show
))
3033 gtk_widget_show( m_widget
);
3035 gtk_widget_hide( m_widget
);
3040 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3042 win
->OnParentEnable(enable
);
3044 // Recurse, so that children have the opportunity to Do The Right Thing
3045 // and reset colours that have been messed up by a parent's (really ancestor's)
3047 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3049 node
= node
->GetNext() )
3051 wxWindow
*child
= node
->GetData();
3052 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3053 wxWindowNotifyEnable(child
, enable
);
3057 bool wxWindowGTK::Enable( bool enable
)
3059 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3061 if (!wxWindowBase::Enable(enable
))
3067 gtk_widget_set_sensitive( m_widget
, enable
);
3069 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3071 wxWindowNotifyEnable(this, enable
);
3076 int wxWindowGTK::GetCharHeight() const
3078 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3080 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3082 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3084 return font
->ascent
+ font
->descent
;
3087 int wxWindowGTK::GetCharWidth() const
3089 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3091 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3093 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3095 return gdk_string_width( font
, "H" );
3098 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3102 int *externalLeading
,
3103 const wxFont
*theFont
) const
3105 wxFont fontToUse
= m_font
;
3106 if (theFont
) fontToUse
= *theFont
;
3108 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3110 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3111 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3112 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3113 if (descent
) (*descent
) = font
->descent
;
3114 if (externalLeading
) (*externalLeading
) = 0; // ??
3117 void wxWindowGTK::SetFocus()
3119 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3123 // don't do anything if we already have focus
3129 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3131 gtk_widget_grab_focus (m_wxwindow
);
3136 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3138 if (!GTK_WIDGET_REALIZED(m_widget
))
3140 // we can't set the focus to the widget now so we remember that
3141 // it should be focused and will do it later, during the idle
3142 // time, as soon as we can
3143 wxLogTrace(TRACE_FOCUS
,
3144 _T("Delaying setting focus to %s(%s)"),
3145 GetClassInfo()->GetClassName(), GetLabel().c_str());
3147 g_delayedFocus
= this;
3151 wxLogTrace(TRACE_FOCUS
,
3152 _T("Setting focus to %s(%s)"),
3153 GetClassInfo()->GetClassName(), GetLabel().c_str());
3155 gtk_widget_grab_focus (m_widget
);
3158 else if (GTK_IS_CONTAINER(m_widget
))
3160 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3164 wxLogTrace(TRACE_FOCUS
,
3165 _T("Can't set focus to %s(%s)"),
3166 GetClassInfo()->GetClassName(), GetLabel().c_str());
3171 bool wxWindowGTK::AcceptsFocus() const
3173 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3176 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3178 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3180 wxWindowGTK
*oldParent
= m_parent
,
3181 *newParent
= (wxWindowGTK
*)newParentBase
;
3183 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3185 if ( !wxWindowBase::Reparent(newParent
) )
3188 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3190 /* prevent GTK from deleting the widget arbitrarily */
3191 gtk_widget_ref( m_widget
);
3195 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3198 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3202 /* insert GTK representation */
3203 (*(newParent
->m_insertCallback
))(newParent
, this);
3206 /* reverse: prevent GTK from deleting the widget arbitrarily */
3207 gtk_widget_unref( m_widget
);
3212 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3214 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3216 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3218 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3223 /* insert GTK representation */
3224 (*m_insertCallback
)(this, child
);
3227 void wxWindowGTK::Raise()
3229 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3231 if (!m_widget
->window
) return;
3233 gdk_window_raise( m_widget
->window
);
3236 void wxWindowGTK::Lower()
3238 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3240 if (!m_widget
->window
) return;
3242 gdk_window_lower( m_widget
->window
);
3245 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3247 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3249 if (cursor
== m_cursor
)
3253 wxapp_install_idle_handler();
3255 if (cursor
== wxNullCursor
)
3256 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3258 return wxWindowBase::SetCursor( cursor
);
3261 void wxWindowGTK::WarpPointer( int x
, int y
)
3263 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3265 // We provide this function ourselves as it is
3266 // missing in GDK (top of this file).
3268 GdkWindow
*window
= (GdkWindow
*) NULL
;
3270 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3272 window
= GetConnectWidget()->window
;
3275 gdk_window_warp_pointer( window
, x
, y
);
3278 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3280 if (!m_widget
) return;
3281 if (!m_widget
->window
) return;
3285 wxapp_install_idle_handler();
3287 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3291 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3292 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3296 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3297 m_clearRegion
.Clear();
3298 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3306 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3307 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3311 GdkRectangle gdk_rect
;
3312 gdk_rect
.x
= rect
->x
;
3313 gdk_rect
.y
= rect
->y
;
3314 gdk_rect
.width
= rect
->width
;
3315 gdk_rect
.height
= rect
->height
;
3316 gtk_widget_draw( m_widget
, &gdk_rect
);
3323 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3324 m_updateRegion
.Clear();
3325 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3329 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3337 GdkRectangle gdk_rect
;
3338 gdk_rect
.x
= rect
->x
;
3339 gdk_rect
.y
= rect
->y
;
3340 gdk_rect
.width
= rect
->width
;
3341 gdk_rect
.height
= rect
->height
;
3342 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3346 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3352 void wxWindowGTK::Update()
3357 void wxWindowGTK::GtkUpdate()
3360 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3361 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3364 if (!m_updateRegion
.IsEmpty())
3365 GtkSendPaintEvents();
3368 void wxWindowGTK::GtkSendPaintEvents()
3372 m_clearRegion
.Clear();
3373 m_updateRegion
.Clear();
3377 // widget to draw on
3378 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3380 // Clip to paint region in wxClientDC
3381 m_clipPaintRegion
= TRUE
;
3383 if (GetThemeEnabled())
3385 // find ancestor from which to steal background
3386 wxWindow
*parent
= GetParent();
3387 while (parent
&& !parent
->IsTopLevel())
3388 parent
= parent
->GetParent();
3390 parent
= (wxWindow
*)this;
3392 wxRegionIterator
upd( m_updateRegion
);
3396 rect
.x
= upd
.GetX();
3397 rect
.y
= upd
.GetY();
3398 rect
.width
= upd
.GetWidth();
3399 rect
.height
= upd
.GetHeight();
3401 gtk_paint_flat_box( parent
->m_widget
->style
,
3414 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3416 wxWindowDC
dc( (wxWindow
*)this );
3417 dc
.SetClippingRegion( m_clearRegion
);
3419 wxEraseEvent
erase_event( GetId(), &dc
);
3420 erase_event
.SetEventObject( this );
3422 if (!GetEventHandler()->ProcessEvent(erase_event
))
3426 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3427 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3429 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3431 wxRegionIterator
upd( m_clearRegion
);
3434 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3435 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3439 m_clearRegion
.Clear();
3442 wxNcPaintEvent
nc_paint_event( GetId() );
3443 nc_paint_event
.SetEventObject( this );
3444 GetEventHandler()->ProcessEvent( nc_paint_event
);
3446 wxPaintEvent
paint_event( GetId() );
3447 paint_event
.SetEventObject( this );
3448 GetEventHandler()->ProcessEvent( paint_event
);
3450 m_clipPaintRegion
= FALSE
;
3452 #ifndef __WXUNIVERSAL__
3454 // The following code will result in all window-less widgets
3455 // being redrawn because the wxWindows class is allowed to
3456 // paint over the window-less widgets.
3458 GList
*children
= pizza
->children
;
3461 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3462 children
= children
->next
;
3464 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3465 GTK_WIDGET_DRAWABLE (child
->widget
))
3467 // Get intersection of widget area and update region
3468 wxRegion
region( m_updateRegion
);
3470 GdkEventExpose gdk_event
;
3471 gdk_event
.type
= GDK_EXPOSE
;
3472 gdk_event
.window
= pizza
->bin_window
;
3473 gdk_event
.count
= 0;
3475 wxRegionIterator
upd( m_updateRegion
);
3479 rect
.x
= upd
.GetX();
3480 rect
.y
= upd
.GetY();
3481 rect
.width
= upd
.GetWidth();
3482 rect
.height
= upd
.GetHeight();
3484 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3486 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3496 m_updateRegion
.Clear();
3499 void wxWindowGTK::Clear()
3501 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3503 if (m_wxwindow
&& m_wxwindow
->window
)
3505 m_clearRegion
.Clear();
3506 wxSize
size( GetClientSize() );
3507 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3509 // Better do this in idle?
3515 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3517 wxWindowBase::DoSetToolTip(tip
);
3520 m_tooltip
->Apply( (wxWindow
*)this );
3523 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3525 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3527 #endif // wxUSE_TOOLTIPS
3529 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3531 GdkWindow
*window
= (GdkWindow
*) NULL
;
3533 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3535 window
= GetConnectWidget()->window
;
3539 // We need the pixel value e.g. for background clearing.
3540 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3544 // wxMSW doesn't clear the window here, either.
3545 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3551 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3553 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3555 if (!wxWindowBase::SetBackgroundColour(colour
))
3558 GdkWindow
*window
= (GdkWindow
*) NULL
;
3560 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3562 window
= GetConnectWidget()->window
;
3566 // indicate that a new style has been set
3567 // but it couldn't get applied as the
3568 // widget hasn't been realized yet.
3569 m_delayedBackgroundColour
= TRUE
;
3574 GtkSetBackgroundColour( colour
);
3580 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3582 GdkWindow
*window
= (GdkWindow
*) NULL
;
3584 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3586 window
= GetConnectWidget()->window
;
3593 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3595 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3597 if (!wxWindowBase::SetForegroundColour(colour
))
3599 // don't leave if the GTK widget has just
3601 if (!m_delayedForegroundColour
) return FALSE
;
3604 GdkWindow
*window
= (GdkWindow
*) NULL
;
3606 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3608 window
= GetConnectWidget()->window
;
3612 // indicate that a new style has been set
3613 // but it couldn't get applied as the
3614 // widget hasn't been realized yet.
3615 m_delayedForegroundColour
= TRUE
;
3619 GtkSetForegroundColour( colour
);
3625 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3629 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3631 // FIXME: no more klass in 2.0
3633 remake
->klass
= m_widgetStyle
->klass
;
3636 gtk_style_unref( m_widgetStyle
);
3637 m_widgetStyle
= remake
;
3641 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3644 def
= gtk_widget_get_default_style();
3646 m_widgetStyle
= gtk_style_copy( def
);
3648 // FIXME: no more klass in 2.0
3650 m_widgetStyle
->klass
= def
->klass
;
3654 return m_widgetStyle
;
3657 void wxWindowGTK::SetWidgetStyle()
3659 #if DISABLE_STYLE_IF_BROKEN_THEME
3660 if (m_widget
->style
->engine_data
)
3662 static bool s_warningPrinted
= FALSE
;
3663 if (!s_warningPrinted
)
3665 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3666 s_warningPrinted
= TRUE
;
3668 m_widgetStyle
= m_widget
->style
;
3673 GtkStyle
*style
= GetWidgetStyle();
3675 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3677 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3680 if (m_foregroundColour
.Ok())
3682 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3683 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3685 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3686 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3687 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3691 // Try to restore the gtk default style. This is still a little
3692 // oversimplified for what is probably really needed here for controls
3693 // other than buttons, but is better than not being able to (re)set a
3694 // control's foreground colour to *wxBLACK -- RL
3695 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3698 def
= gtk_widget_get_default_style();
3700 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3701 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3702 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3706 if (m_backgroundColour
.Ok())
3708 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3709 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3711 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3712 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3713 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3714 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3715 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3716 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3717 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3718 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3722 // Try to restore the gtk default style. This is still a little
3723 // oversimplified for what is probably really needed here for controls
3724 // other than buttons, but is better than not being able to (re)set a
3725 // control's background colour to default grey and means resetting a
3726 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3728 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3731 def
= gtk_widget_get_default_style();
3733 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3734 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3735 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3736 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3737 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3738 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3739 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3740 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3745 void wxWindowGTK::ApplyWidgetStyle()
3749 //-----------------------------------------------------------------------------
3750 // Pop-up menu stuff
3751 //-----------------------------------------------------------------------------
3753 #if wxUSE_MENUS_NATIVE
3756 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3758 *is_waiting
= FALSE
;
3761 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3763 menu
->SetInvokingWindow( win
);
3764 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3767 wxMenuItem
*menuitem
= node
->GetData();
3768 if (menuitem
->IsSubMenu())
3770 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3773 node
= node
->GetNext();
3777 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3778 // wxPopupMenuPositionCallback()
3780 // should be safe even in the MT case as the user can hardly popup 2 menus
3781 // simultaneously, can he?
3782 static gint gs_pop_x
= 0;
3783 static gint gs_pop_y
= 0;
3785 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3788 gboolean
* WXUNUSED(whatever
),
3790 gpointer
WXUNUSED(user_data
) )
3792 // ensure that the menu appears entirely on screen
3794 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3796 wxSize sizeScreen
= wxGetDisplaySize();
3798 gint xmax
= sizeScreen
.x
- req
.width
,
3799 ymax
= sizeScreen
.y
- req
.height
;
3801 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3802 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3805 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3807 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3809 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3811 SetInvokingWindow( menu
, this );
3817 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3819 bool is_waiting
= TRUE
;
3821 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3823 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3824 (gpointer
)&is_waiting
);
3827 GTK_MENU(menu
->m_menu
),
3828 (GtkWidget
*) NULL
, // parent menu shell
3829 (GtkWidget
*) NULL
, // parent menu item
3830 wxPopupMenuPositionCallback
, // function to position it
3831 NULL
, // client data
3832 0, // button used to activate it
3833 gs_timeLastClick
// the time of activation
3838 while (gtk_events_pending())
3839 gtk_main_iteration();
3845 #endif // wxUSE_MENUS_NATIVE
3847 #if wxUSE_DRAG_AND_DROP
3849 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3851 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3853 GtkWidget
*dnd_widget
= GetConnectWidget();
3855 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3857 if (m_dropTarget
) delete m_dropTarget
;
3858 m_dropTarget
= dropTarget
;
3860 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3863 #endif // wxUSE_DRAG_AND_DROP
3865 GtkWidget
* wxWindowGTK::GetConnectWidget()
3867 GtkWidget
*connect_widget
= m_widget
;
3868 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3870 return connect_widget
;
3873 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3876 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3878 return (window
== m_widget
->window
);
3881 bool wxWindowGTK::SetFont( const wxFont
&font
)
3883 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3885 if (!wxWindowBase::SetFont(font
))
3890 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3891 if ( sysbg
== m_backgroundColour
)
3893 m_backgroundColour
= wxNullColour
;
3895 m_backgroundColour
= sysbg
;
3905 void wxWindowGTK::DoCaptureMouse()
3907 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3909 GdkWindow
*window
= (GdkWindow
*) NULL
;
3911 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3913 window
= GetConnectWidget()->window
;
3915 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3917 wxCursor
* cursor
= & m_cursor
;
3919 cursor
= wxSTANDARD_CURSOR
;
3921 gdk_pointer_grab( window
, FALSE
,
3923 (GDK_BUTTON_PRESS_MASK
|
3924 GDK_BUTTON_RELEASE_MASK
|
3925 GDK_POINTER_MOTION_HINT_MASK
|
3926 GDK_POINTER_MOTION_MASK
),
3928 cursor
->GetCursor(),
3929 (guint32
)GDK_CURRENT_TIME
);
3930 g_captureWindow
= this;
3931 g_captureWindowHasMouse
= TRUE
;
3934 void wxWindowGTK::DoReleaseMouse()
3936 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3938 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3940 g_captureWindow
= (wxWindowGTK
*) NULL
;
3942 GdkWindow
*window
= (GdkWindow
*) NULL
;
3944 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3946 window
= GetConnectWidget()->window
;
3951 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3955 wxWindow
*wxWindowBase::GetCapture()
3957 return (wxWindow
*)g_captureWindow
;
3960 bool wxWindowGTK::IsRetained() const
3965 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3966 int range
, bool refresh
)
3968 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3970 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3972 m_hasScrolling
= TRUE
;
3974 if (orient
== wxHORIZONTAL
)
3976 float fpos
= (float)pos
;
3977 float frange
= (float)range
;
3978 float fthumb
= (float)thumbVisible
;
3979 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3980 if (fpos
< 0.0) fpos
= 0.0;
3982 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
3983 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
3985 SetScrollPos( orient
, pos
, refresh
);
3989 m_oldHorizontalPos
= fpos
;
3991 m_hAdjust
->lower
= 0.0;
3992 m_hAdjust
->upper
= frange
;
3993 m_hAdjust
->value
= fpos
;
3994 m_hAdjust
->step_increment
= 1.0;
3995 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3996 m_hAdjust
->page_size
= fthumb
;
4000 float fpos
= (float)pos
;
4001 float frange
= (float)range
;
4002 float fthumb
= (float)thumbVisible
;
4003 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4004 if (fpos
< 0.0) fpos
= 0.0;
4006 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4007 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4009 SetScrollPos( orient
, pos
, refresh
);
4013 m_oldVerticalPos
= fpos
;
4015 m_vAdjust
->lower
= 0.0;
4016 m_vAdjust
->upper
= frange
;
4017 m_vAdjust
->value
= fpos
;
4018 m_vAdjust
->step_increment
= 1.0;
4019 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4020 m_vAdjust
->page_size
= fthumb
;
4023 if (orient
== wxHORIZONTAL
)
4024 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4026 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4029 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4031 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4033 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4035 if (orient
== wxHORIZONTAL
)
4037 float fpos
= (float)pos
;
4038 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4039 if (fpos
< 0.0) fpos
= 0.0;
4040 m_oldHorizontalPos
= fpos
;
4042 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4043 m_hAdjust
->value
= fpos
;
4047 float fpos
= (float)pos
;
4048 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4049 if (fpos
< 0.0) fpos
= 0.0;
4050 m_oldVerticalPos
= fpos
;
4052 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4053 m_vAdjust
->value
= fpos
;
4056 if (m_wxwindow
->window
)
4058 if (orient
== wxHORIZONTAL
)
4060 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4061 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4063 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4065 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4066 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4070 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4071 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4073 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4075 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4076 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4081 int wxWindowGTK::GetScrollThumb( int orient
) const
4083 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4085 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4087 if (orient
== wxHORIZONTAL
)
4088 return (int)(m_hAdjust
->page_size
+0.5);
4090 return (int)(m_vAdjust
->page_size
+0.5);
4093 int wxWindowGTK::GetScrollPos( int orient
) const
4095 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4097 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4099 if (orient
== wxHORIZONTAL
)
4100 return (int)(m_hAdjust
->value
+0.5);
4102 return (int)(m_vAdjust
->value
+0.5);
4105 int wxWindowGTK::GetScrollRange( int orient
) const
4107 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4109 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4111 if (orient
== wxHORIZONTAL
)
4112 return (int)(m_hAdjust
->upper
+0.5);
4114 return (int)(m_vAdjust
->upper
+0.5);
4117 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4119 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4121 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4123 // No scrolling requested.
4124 if ((dx
== 0) && (dy
== 0)) return;
4127 if (!m_updateRegion
.IsEmpty())
4129 m_updateRegion
.Offset( dx
, dy
);
4133 GetClientSize( &cw
, &ch
);
4134 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4137 if (!m_clearRegion
.IsEmpty())
4139 m_clearRegion
.Offset( dx
, dy
);
4143 GetClientSize( &cw
, &ch
);
4144 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4146 m_clipPaintRegion
= TRUE
;
4148 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4150 m_clipPaintRegion
= FALSE
;
4153 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4155 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4156 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4163 // Find the wxWindow at the current mouse position, also returning the mouse
4165 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4167 pt
= wxGetMousePosition();
4168 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4172 // Get the current mouse position.
4173 wxPoint
wxGetMousePosition()
4175 /* This crashes when used within wxHelpContext,
4176 so we have to use the X-specific implementation below.
4178 GdkModifierType *mask;
4179 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4181 return wxPoint(x, y);
4185 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4187 return wxPoint(-999, -999);
4189 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4190 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4191 Window rootReturn
, childReturn
;
4192 int rootX
, rootY
, winX
, winY
;
4193 unsigned int maskReturn
;
4195 XQueryPointer (display
,
4199 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4200 return wxPoint(rootX
, rootY
);
4204 // ----------------------------------------------------------------------------
4206 // ----------------------------------------------------------------------------
4208 class wxWinModule
: public wxModule
4215 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4218 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4220 bool wxWinModule::OnInit()
4222 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4223 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4228 void wxWinModule::OnExit()
4231 gdk_gc_unref( g_eraseGC
);