1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "window.h"
16 #define XWarpPointer XWARPPOINTER
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
24 #include "wx/layout.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28 #include "wx/module.h"
30 #if wxUSE_DRAG_AND_DROP
35 #include "wx/tooltip.h"
43 #include "wx/textctrl.h"
47 #include "wx/statusbr.h"
49 #include "wx/settings.h"
53 #include "wx/thread.h"
58 #include "wx/gtk/private.h"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
69 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
71 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
81 extern GtkContainerClass
*pizza_parent_class
;
84 //-----------------------------------------------------------------------------
85 // documentation on internals
86 //-----------------------------------------------------------------------------
89 I have been asked several times about writing some documentation about
90 the GTK port of wxWindows, especially its internal structures. Obviously,
91 you cannot understand wxGTK without knowing a little about the GTK, but
92 some more information about what the wxWindow, which is the base class
93 for all other window classes, does seems required as well.
97 What does wxWindow do? It contains the common interface for the following
98 jobs of its descendants:
100 1) Define the rudimentary behaviour common to all window classes, such as
101 resizing, intercepting user input (so as to make it possible to use these
102 events for special purposes in a derived class), window names etc.
104 2) Provide the possibility to contain and manage children, if the derived
105 class is allowed to contain children, which holds true for those window
106 classes which do not display a native GTK widget. To name them, these
107 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
108 work classes are a special case and are handled a bit differently from
109 the rest. The same holds true for the wxNotebook class.
111 3) Provide the possibility to draw into a client area of a window. This,
112 too, only holds true for classes that do not display a native GTK widget
115 4) Provide the entire mechanism for scrolling widgets. This actual inter-
116 face for this is usually in wxScrolledWindow, but the GTK implementation
119 5) A multitude of helper or extra methods for special purposes, such as
120 Drag'n'Drop, managing validators etc.
122 6) Display a border (sunken, raised, simple or none).
124 Normally one might expect, that one wxWindows window would always correspond
125 to one GTK widget. Under GTK, there is no such allround widget that has all
126 the functionality. Moreover, the GTK defines a client area as a different
127 widget from the actual widget you are handling. Last but not least some
128 special classes (e.g. wxFrame) handle different categories of widgets and
129 still have the possibility to draw something in the client area.
130 It was therefore required to write a special purpose GTK widget, that would
131 represent a client area in the sense of wxWindows capable to do the jobs
132 2), 3) and 4). I have written this class and it resides in win_gtk.c of
135 All windows must have a widget, with which they interact with other under-
136 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
137 thw wxWindow class has a member variable called m_widget which holds a
138 pointer to this widget. When the window class represents a GTK native widget,
139 this is (in most cases) the only GTK widget the class manages. E.g. the
140 wxStatitText class handles only a GtkLabel widget a pointer to which you
141 can find in m_widget (defined in wxWindow)
143 When the class has a client area for drawing into and for containing children
144 it has to handle the client area widget (of the type GtkPizza, defined in
145 win_gtk.c), but there could be any number of widgets, handled by a class
146 The common rule for all windows is only, that the widget that interacts with
147 the rest of GTK must be referenced in m_widget and all other widgets must be
148 children of this widget on the GTK level. The top-most widget, which also
149 represents the client area, must be in the m_wxwindow field and must be of
152 As I said, the window classes that display a GTK native widget only have
153 one widget, so in the case of e.g. the wxButton class m_widget holds a
154 pointer to a GtkButton widget. But windows with client areas (for drawing
155 and children) have a m_widget field that is a pointer to a GtkScrolled-
156 Window and a m_wxwindow field that is pointer to a GtkPizza and this
157 one is (in the GTK sense) a child of the GtkScrolledWindow.
159 If the m_wxwindow field is set, then all input to this widget is inter-
160 cepted and sent to the wxWindows class. If not, all input to the widget
161 that gets pointed to by m_widget gets intercepted and sent to the class.
165 The design of scrolling in wxWindows is markedly different from that offered
166 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
167 clicking on a scrollbar belonging to scrolled window will inevitably move
168 the window. In wxWindows, the scrollbar will only emit an event, send this
169 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
170 which actually moves the window and its subchildren. Note that GtkPizza
171 memorizes how much it has been scrolled but that wxWindows forgets this
172 so that the two coordinates systems have to be kept in synch. This is done
173 in various places using the pizza->xoffset and pizza->yoffset values.
177 Singularily the most broken code in GTK is the code that is supposes to
178 inform subwindows (child windows) about new positions. Very often, duplicate
179 events are sent without changes in size or position, equally often no
180 events are sent at all (All this is due to a bug in the GtkContainer code
181 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
182 GTK's own system and it simply waits for size events for toplevel windows
183 and then iterates down the respective size events to all window. This has
184 the disadvantage, that windows might get size events before the GTK widget
185 actually has the reported size. This doesn't normally pose any problem, but
186 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
187 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
188 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
189 window that is used for OpenGl output really has that size (as reported by
194 If someone at some point of time feels the immense desire to have a look at,
195 change or attempt to optimse the Refresh() logic, this person will need an
196 intimate understanding of what a "draw" and what an "expose" events are and
197 what there are used for, in particular when used in connection with GTK's
198 own windowless widgets. Beware.
202 Cursors, too, have been a constant source of pleasure. The main difficulty
203 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
204 for the parent. To prevent this from doing too much harm, I use idle time
205 to set the cursor over and over again, starting from the toplevel windows
206 and ending with the youngest generation (speaking of parent and child windows).
207 Also don't forget that cursors (like much else) are connected to GdkWindows,
208 not GtkWidgets and that the "window" field of a GtkWidget might very well
209 point to the GdkWindow of the parent widget (-> "window less widget") and
210 that the two obviously have very different meanings.
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 extern wxList wxPendingDelete
;
219 extern bool g_blockEventsOnDrag
;
220 extern bool g_blockEventsOnScroll
;
221 extern wxCursor g_globalCursor
;
223 static GdkGC
*g_eraseGC
= NULL
;
225 // mouse capture state: the window which has it and if the mouse is currently
227 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
228 static bool g_captureWindowHasMouse
= FALSE
;
230 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
232 // the last window which had the focus - this is normally never NULL (except
233 // if we never had focus at all) as even when g_focusWindow is NULL it still
234 // keeps its previous value
235 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
237 // the frame that is currently active (i.e. its child has focus). It is
238 // used to generate wxActivateEvents
239 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
240 static bool g_activeFrameLostFocus
= FALSE
;
242 // If a window get the focus set but has not been realized
243 // yet, defer setting the focus to idle time.
244 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
246 // if we detect that the app has got/lost the focus, we set this variable to
247 // either TRUE or FALSE and an activate event will be sent during the next
248 // OnIdle() call and it is reset to -1: this value means that we shouldn't
249 // send any activate events at all
250 static int g_sendActivateEvent
= -1;
252 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
253 the last click here */
254 static guint32 gs_timeLastClick
= 0;
256 extern bool g_mainThreadLocked
;
258 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
263 #define DISABLE_STYLE_IF_BROKEN_THEME 1
269 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
271 # define DEBUG_MAIN_THREAD
274 #define DEBUG_MAIN_THREAD
277 // the trace mask used for the focus debugging messages
278 #define TRACE_FOCUS _T("focus")
280 //-----------------------------------------------------------------------------
281 // missing gdk functions
282 //-----------------------------------------------------------------------------
285 gdk_window_warp_pointer (GdkWindow
*window
,
290 GdkWindowPrivate
*priv
;
294 window
= GDK_ROOT_PARENT();
297 if (!GDK_WINDOW_DESTROYED(window
))
299 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
300 None
, /* not source window -> move from anywhere */
301 GDK_WINDOW_XID(window
), /* dest window */
302 0, 0, 0, 0, /* not source window -> move from anywhere */
306 priv
= (GdkWindowPrivate
*) window
;
308 if (!priv
->destroyed
)
310 XWarpPointer (priv
->xdisplay
,
311 None
, /* not source window -> move from anywhere */
312 priv
->xwindow
, /* dest window */
313 0, 0, 0, 0, /* not source window -> move from anywhere */
319 //-----------------------------------------------------------------------------
321 //-----------------------------------------------------------------------------
323 extern void wxapp_install_idle_handler();
324 extern bool g_isIdle
;
326 //-----------------------------------------------------------------------------
327 // local code (see below)
328 //-----------------------------------------------------------------------------
330 // returns the child of win which currently has focus or NULL if not found
332 // Note: can't be static, needed by textctrl.cpp.
333 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
335 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
337 return (wxWindow
*)NULL
;
339 if ( winFocus
== win
)
340 return (wxWindow
*)win
;
342 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
344 node
= node
->GetNext() )
346 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
351 return (wxWindow
*)NULL
;
354 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
356 // wxUniversal widgets draw the borders and scrollbars themselves
357 #ifndef __WXUNIVERSAL__
364 if (win
->m_hasScrolling
)
366 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
368 GtkRequisition vscroll_req
;
369 vscroll_req
.width
= 2;
370 vscroll_req
.height
= 2;
371 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
372 (scroll_window
->vscrollbar
, &vscroll_req
);
374 GtkRequisition hscroll_req
;
375 hscroll_req
.width
= 2;
376 hscroll_req
.height
= 2;
377 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
378 (scroll_window
->hscrollbar
, &hscroll_req
);
380 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
382 if (scroll_window
->vscrollbar_visible
)
384 dw
+= vscroll_req
.width
;
385 dw
+= scroll_class
->scrollbar_spacing
;
388 if (scroll_window
->hscrollbar_visible
)
390 dh
+= hscroll_req
.height
;
391 dh
+= scroll_class
->scrollbar_spacing
;
397 if (GTK_WIDGET_NO_WINDOW (widget
))
399 dx
+= widget
->allocation
.x
;
400 dy
+= widget
->allocation
.y
;
403 if (win
->HasFlag(wxRAISED_BORDER
))
405 gtk_draw_shadow( widget
->style
,
410 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
414 if (win
->HasFlag(wxSUNKEN_BORDER
))
416 gtk_draw_shadow( widget
->style
,
421 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
425 if (win
->HasFlag(wxSIMPLE_BORDER
))
428 gc
= gdk_gc_new( widget
->window
);
429 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
430 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
432 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
436 #endif // __WXUNIVERSAL__
439 //-----------------------------------------------------------------------------
440 // "expose_event" of m_widget
441 //-----------------------------------------------------------------------------
443 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
445 if (gdk_event
->count
> 0) return FALSE
;
447 draw_frame( widget
, win
);
451 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
457 //-----------------------------------------------------------------------------
458 // "draw" of m_widget
459 //-----------------------------------------------------------------------------
463 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
465 draw_frame( widget
, win
);
470 //-----------------------------------------------------------------------------
471 // "size_request" of m_widget
472 //-----------------------------------------------------------------------------
474 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
477 win
->GetSize( &w
, &h
);
481 requisition
->height
= h
;
482 requisition
->width
= w
;
485 //-----------------------------------------------------------------------------
486 // "expose_event" of m_wxwindow
487 //-----------------------------------------------------------------------------
489 static int gtk_window_expose_callback( GtkWidget
*widget
,
490 GdkEventExpose
*gdk_event
,
496 wxapp_install_idle_handler();
501 wxPrintf( wxT("OnExpose from ") );
502 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
503 wxPrintf( win
->GetClassInfo()->GetClassName() );
504 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
505 (int)gdk_event
->area
.y
,
506 (int)gdk_event
->area
.width
,
507 (int)gdk_event
->area
.height
);
511 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
513 gdk_event
->area
.width
,
514 gdk_event
->area
.height
);
515 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
517 gdk_event
->area
.width
,
518 gdk_event
->area
.height
);
520 // Actual redrawing takes place in idle time.
525 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
532 //-----------------------------------------------------------------------------
533 // "event" of m_wxwindow
534 //-----------------------------------------------------------------------------
536 // GTK thinks it is clever and filters out a certain amount of "unneeded"
537 // expose events. We need them, of course, so we override the main event
538 // procedure in GtkWidget by giving our own handler for all system events.
539 // There, we look for expose events ourselves whereas all other events are
542 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
543 GdkEventExpose
*event
,
546 if (event
->type
== GDK_EXPOSE
)
548 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
555 //-----------------------------------------------------------------------------
556 // "draw" of m_wxwindow
557 //-----------------------------------------------------------------------------
561 // This callback is a complete replacement of the gtk_pizza_draw() function,
562 // which is disabled.
564 static void gtk_window_draw_callback( GtkWidget
*widget
,
571 wxapp_install_idle_handler();
573 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
574 // there are no child windows.
575 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
576 (win
->GetChildren().GetCount() == 0))
584 wxPrintf( wxT("OnDraw from ") );
585 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
586 wxPrintf( win
->GetClassInfo()->GetClassName() );
587 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
594 #ifndef __WXUNIVERSAL__
595 GtkPizza
*pizza
= GTK_PIZZA (widget
);
597 if (win
->GetThemeEnabled())
599 wxWindow
*parent
= win
->GetParent();
600 while (parent
&& !parent
->IsTopLevel())
601 parent
= parent
->GetParent();
605 gtk_paint_flat_box (parent
->m_widget
->style
,
616 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
617 (pizza
->clear_on_draw
))
619 gdk_window_clear_area( pizza
->bin_window
,
620 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
624 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
626 // Actual redrawing takes place in idle time.
630 #ifndef __WXUNIVERSAL__
631 // Redraw child widgets
632 GList
*children
= pizza
->children
;
635 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
636 children
= children
->next
;
638 GdkRectangle child_area
;
639 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
641 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
649 //-----------------------------------------------------------------------------
650 // "key_press_event" from any window
651 //-----------------------------------------------------------------------------
653 // set WXTRACE to this to see the key event codes on the console
654 #define TRACE_KEYS _T("keyevent")
656 // translates an X key symbol to WXK_XXX value
658 // if isChar is true it means that the value returned will be used for EVT_CHAR
659 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
660 // for example, while if it is false it means that the value is going to be
661 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
663 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
669 // Shift, Control and Alt don't generate the CHAR events at all
672 key_code
= isChar
? 0 : WXK_SHIFT
;
676 key_code
= isChar
? 0 : WXK_CONTROL
;
684 key_code
= isChar
? 0 : WXK_ALT
;
687 // neither do the toggle modifies
688 case GDK_Scroll_Lock
:
689 key_code
= isChar
? 0 : WXK_SCROLL
;
693 key_code
= isChar
? 0 : WXK_CAPITAL
;
697 key_code
= isChar
? 0 : WXK_NUMLOCK
;
701 // various other special keys
714 case GDK_ISO_Left_Tab
:
721 key_code
= WXK_RETURN
;
725 key_code
= WXK_CLEAR
;
729 key_code
= WXK_PAUSE
;
733 key_code
= WXK_SELECT
;
737 key_code
= WXK_PRINT
;
741 key_code
= WXK_EXECUTE
;
745 key_code
= WXK_ESCAPE
;
748 // cursor and other extended keyboard keys
750 key_code
= WXK_DELETE
;
766 key_code
= WXK_RIGHT
;
773 case GDK_Prior
: // == GDK_Page_Up
774 key_code
= WXK_PRIOR
;
777 case GDK_Next
: // == GDK_Page_Down
790 key_code
= WXK_INSERT
;
805 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
809 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
813 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
817 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
821 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
825 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
829 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
833 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
837 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
841 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
845 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
849 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
853 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
856 case GDK_KP_Prior
: // == GDK_KP_Page_Up
857 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
860 case GDK_KP_Next
: // == GDK_KP_Page_Down
861 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
865 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
869 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
873 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
877 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
881 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
884 case GDK_KP_Multiply
:
885 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
889 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
892 case GDK_KP_Separator
:
893 // FIXME: what is this?
894 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
897 case GDK_KP_Subtract
:
898 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
902 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
906 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
923 key_code
= WXK_F1
+ keysym
- GDK_F1
;
933 static inline bool wxIsAsciiKeysym(KeySym ks
)
939 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
941 GdkEventKey
*gdk_event
)
943 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
944 // but only event->keyval which is quite useless to us, so remember
945 // the last character from GDK_KEY_PRESS and reuse it as last resort
947 // NB: should be MT-safe as we're always called from the main thread only
952 } s_lastKeyPress
= { 0, 0 };
954 KeySym keysym
= gdk_event
->keyval
;
956 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %d"),
957 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
961 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
965 // do we have the translation or is it a plain ASCII character?
966 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
968 // we should use keysym if it is ASCII as X does some translations
969 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
970 // which we don't want here (but which we do use for OnChar())
971 if ( !wxIsAsciiKeysym(keysym
) )
973 keysym
= (KeySym
)gdk_event
->string
[0];
976 // we want to always get the same key code when the same key is
977 // pressed regardless of the state of the modifies, i.e. on a
978 // standard US keyboard pressing '5' or '%' ('5' key with
979 // Shift) should result in the same key code in OnKeyDown():
980 // '5' (although OnChar() will get either '5' or '%').
982 // to do it we first translate keysym to keycode (== scan code)
983 // and then back but always using the lower register
984 Display
*dpy
= (Display
*)wxGetDisplay();
985 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
987 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
989 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
991 // use the normalized, i.e. lower register, keysym if we've
993 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
995 // as explained above, we want to have lower register key codes
996 // normally but for the letter keys we want to have the upper ones
998 // NB: don't use XConvertCase() here, we want to do it for letters
1000 key_code
= toupper(key_code
);
1002 else // non ASCII key, what to do?
1004 // by default, ignore it
1007 // but if we have cached information from the last KEY_PRESS
1008 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1011 if ( keysym
== s_lastKeyPress
.keysym
)
1013 key_code
= s_lastKeyPress
.keycode
;
1018 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1020 // remember it to be reused for KEY_UP event later
1021 s_lastKeyPress
.keysym
= keysym
;
1022 s_lastKeyPress
.keycode
= key_code
;
1026 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %d"), key_code
);
1028 // sending unknown key events doesn't really make sense
1032 // now fill all the other fields
1035 GdkModifierType state
;
1036 if (gdk_event
->window
)
1037 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1039 event
.SetTimestamp( gdk_event
->time
);
1040 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1041 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1042 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1043 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1044 event
.m_keyCode
= key_code
;
1045 event
.m_scanCode
= gdk_event
->keyval
;
1046 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1047 event
.m_rawFlags
= 0;
1050 event
.SetEventObject( win
);
1055 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1056 GdkEventKey
*gdk_event
,
1062 wxapp_install_idle_handler();
1066 if (g_blockEventsOnDrag
)
1071 wxKeyEvent
event( wxEVT_CHAR_HOOK
);
1072 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1074 // unknown key pressed, ignore (the event would be useless anyhow)
1078 // Implement wxFrame::OnCharHook by checking ancestor.
1079 wxWindow
*parent
= win
;
1080 while (parent
&& !parent
->IsTopLevel())
1081 parent
= parent
->GetParent();
1084 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1088 event
.SetEventType(wxEVT_KEY_DOWN
);
1089 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1095 wxWindowGTK
*ancestor
= win
;
1098 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1101 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1102 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1105 if (ancestor
->IsTopLevel())
1107 ancestor
= ancestor
->GetParent();
1110 #endif // wxUSE_ACCEL
1112 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1113 will only be sent if it is not in an accelerator table. */
1116 KeySym keysym
= gdk_event
->keyval
;
1117 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1120 if ( gdk_event
->length
== 1 )
1122 key_code
= (unsigned char)gdk_event
->string
[0];
1124 else if ( wxIsAsciiKeysym(keysym
) )
1127 key_code
= (unsigned char)keysym
;
1133 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1135 // reuse the same event object, just change its type and use the
1136 // translated keycode instead of the raw one
1137 event
.SetEventType(wxEVT_CHAR
);
1138 event
.m_keyCode
= key_code
;
1140 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1144 /* win is a control: tab can be propagated up */
1146 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1147 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1148 // have this style, yet choose not to process this particular TAB in which
1149 // case TAB must still work as a navigational character
1151 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1153 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1155 wxNavigationKeyEvent new_event
;
1156 new_event
.SetEventObject( win
->GetParent() );
1157 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1158 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1159 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1160 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1161 new_event
.SetCurrentFocus( win
);
1162 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1165 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1167 (gdk_event
->keyval
== GDK_Escape
) )
1169 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1170 new_event
.SetEventObject( win
);
1171 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1175 #if 0 // (GTK_MINOR_VERSION > 0)
1176 /* Pressing F10 will activate the menu bar of the top frame. */
1178 (gdk_event
->keyval
== GDK_F10
) )
1180 wxWindowGTK
*ancestor
= win
;
1183 if (wxIsKindOf(ancestor
,wxFrame
))
1185 wxFrame
*frame
= (wxFrame
*) ancestor
;
1186 wxMenuBar
*menubar
= frame
->GetMenuBar();
1189 wxNode
*node
= menubar
->GetMenus().First();
1192 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1193 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1199 ancestor
= ancestor
->GetParent();
1206 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1213 //-----------------------------------------------------------------------------
1214 // "key_release_event" from any window
1215 //-----------------------------------------------------------------------------
1217 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1218 GdkEventKey
*gdk_event
,
1224 wxapp_install_idle_handler();
1229 if (g_blockEventsOnDrag
)
1232 wxKeyEvent
event( wxEVT_KEY_UP
);
1233 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1235 // unknown key pressed, ignore (the event would be useless anyhow
1239 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1242 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1246 // ============================================================================
1248 // ============================================================================
1250 // ----------------------------------------------------------------------------
1251 // mouse event processing helpers
1252 // ----------------------------------------------------------------------------
1254 // init wxMouseEvent with the info from gdk_event
1255 #define InitMouseEvent(win, event, gdk_event) \
1257 event.SetTimestamp( gdk_event->time ); \
1258 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1259 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1260 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1261 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1262 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1263 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1264 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1266 wxPoint pt = win->GetClientAreaOrigin(); \
1267 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1268 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1271 static void AdjustEventButtonState(wxMouseEvent
& event
)
1273 // GDK reports the old state of the button for a button press event, but
1274 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1275 // for a LEFT_DOWN event, not FALSE, so we will invert
1276 // left/right/middleDown for the corresponding click events
1278 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1279 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1280 (event
.GetEventType() == wxEVT_LEFT_UP
))
1282 event
.m_leftDown
= !event
.m_leftDown
;
1286 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1287 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1288 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1290 event
.m_middleDown
= !event
.m_middleDown
;
1294 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1295 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1296 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1298 event
.m_rightDown
= !event
.m_rightDown
;
1303 // find the window to send the mouse event too
1305 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1310 if (win
->m_wxwindow
)
1312 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1313 xx
+= pizza
->xoffset
;
1314 yy
+= pizza
->yoffset
;
1317 wxNode
*node
= win
->GetChildren().First();
1320 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1322 node
= node
->Next();
1323 if (!child
->IsShown())
1326 if (child
->IsTransparentForMouse())
1328 // wxStaticBox is transparent in the box itself
1329 int xx1
= child
->m_x
;
1330 int yy1
= child
->m_y
;
1331 int xx2
= child
->m_x
+ child
->m_width
;
1332 int yy2
= child
->m_x
+ child
->m_height
;
1335 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1337 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1339 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1341 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1352 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1353 (child
->m_x
<= xx
) &&
1354 (child
->m_y
<= yy
) &&
1355 (child
->m_x
+child
->m_width
>= x
) &&
1356 (child
->m_y
+child
->m_height
>= y
))
1369 //-----------------------------------------------------------------------------
1370 // "button_press_event"
1371 //-----------------------------------------------------------------------------
1373 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1374 GdkEventButton
*gdk_event
,
1380 wxapp_install_idle_handler();
1383 wxPrintf( wxT("1) OnButtonPress from ") );
1384 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1385 wxPrintf( win->GetClassInfo()->GetClassName() );
1386 wxPrintf( wxT(".\n") );
1388 if (!win
->m_hasVMT
) return FALSE
;
1389 if (g_blockEventsOnDrag
) return TRUE
;
1390 if (g_blockEventsOnScroll
) return TRUE
;
1392 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1394 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1396 gtk_widget_grab_focus( win
->m_wxwindow
);
1398 wxPrintf( wxT("GrabFocus from ") );
1399 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1400 wxPrintf( win->GetClassInfo()->GetClassName() );
1401 wxPrintf( wxT(".\n") );
1405 wxEventType event_type
= wxEVT_NULL
;
1407 if (gdk_event
->button
== 1)
1409 switch (gdk_event
->type
)
1411 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1412 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1416 else if (gdk_event
->button
== 2)
1418 switch (gdk_event
->type
)
1420 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1421 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1425 else if (gdk_event
->button
== 3)
1427 switch (gdk_event
->type
)
1429 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1430 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1435 if ( event_type
== wxEVT_NULL
)
1437 // unknown mouse button or click type
1441 wxMouseEvent
event( event_type
);
1442 InitMouseEvent( win
, event
, gdk_event
);
1444 AdjustEventButtonState(event
);
1446 // wxListBox actually get mouse events from the item, so we need to give it
1447 // a chance to correct this
1448 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1450 // find the correct window to send the event too: it may be a different one
1451 // from the one which got it at GTK+ level because some control don't have
1452 // their own X window and thus cannot get any events.
1453 if ( !g_captureWindow
)
1454 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1456 event
.SetEventObject( win
);
1458 gs_timeLastClick
= gdk_event
->time
;
1461 wxPrintf( wxT("2) OnButtonPress from ") );
1462 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1463 wxPrintf( win->GetClassInfo()->GetClassName() );
1464 wxPrintf( wxT(".\n") );
1467 if (win
->GetEventHandler()->ProcessEvent( event
))
1469 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1476 //-----------------------------------------------------------------------------
1477 // "button_release_event"
1478 //-----------------------------------------------------------------------------
1480 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1485 wxapp_install_idle_handler();
1487 if (!win
->m_hasVMT
) return FALSE
;
1488 if (g_blockEventsOnDrag
) return FALSE
;
1489 if (g_blockEventsOnScroll
) return FALSE
;
1491 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1494 printf( "OnButtonRelease from " );
1495 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1496 printf( win->GetClassInfo()->GetClassName() );
1500 wxEventType event_type
= wxEVT_NULL
;
1502 switch (gdk_event
->button
)
1504 case 1: event_type
= wxEVT_LEFT_UP
; break;
1505 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1506 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1507 default: return FALSE
;
1510 wxMouseEvent
event( event_type
);
1511 InitMouseEvent( win
, event
, gdk_event
);
1513 AdjustEventButtonState(event
);
1515 // same wxListBox hack as above
1516 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1518 if ( !g_captureWindow
)
1519 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1521 event
.SetEventObject( win
);
1523 if (win
->GetEventHandler()->ProcessEvent( event
))
1525 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1532 //-----------------------------------------------------------------------------
1533 // "motion_notify_event"
1534 //-----------------------------------------------------------------------------
1536 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1537 GdkEventMotion
*gdk_event
,
1543 wxapp_install_idle_handler();
1545 if (!win
->m_hasVMT
) return FALSE
;
1546 if (g_blockEventsOnDrag
) return FALSE
;
1547 if (g_blockEventsOnScroll
) return FALSE
;
1549 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1551 if (gdk_event
->is_hint
)
1555 GdkModifierType state
;
1556 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1562 printf( "OnMotion from " );
1563 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1564 printf( win->GetClassInfo()->GetClassName() );
1568 wxMouseEvent
event( wxEVT_MOTION
);
1569 InitMouseEvent(win
, event
, gdk_event
);
1571 if ( g_captureWindow
)
1573 // synthetize a mouse enter or leave event if needed
1574 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1575 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1576 if ( hasMouse
!= g_captureWindowHasMouse
)
1578 // the mouse changed window
1579 g_captureWindowHasMouse
= hasMouse
;
1581 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1582 : wxEVT_LEAVE_WINDOW
);
1583 InitMouseEvent(win
, event
, gdk_event
);
1584 event
.SetEventObject(win
);
1585 win
->GetEventHandler()->ProcessEvent(event
);
1590 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1593 event
.SetEventObject( win
);
1595 if (win
->GetEventHandler()->ProcessEvent( event
))
1597 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1604 //-----------------------------------------------------------------------------
1606 //-----------------------------------------------------------------------------
1608 // send the wxChildFocusEvent and wxFocusEvent, common code of
1609 // gtk_window_focus_in_callback() and SetFocus()
1610 static bool DoSendFocusEvents(wxWindow
*win
)
1612 // Notify the parent keeping track of focus for the kbd navigation
1613 // purposes that we got it.
1614 wxChildFocusEvent
eventChildFocus(win
);
1615 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1617 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1618 eventFocus
.SetEventObject(win
);
1620 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1623 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1624 GdkEvent
*WXUNUSED(event
),
1630 wxapp_install_idle_handler();
1632 if (!win
->m_hasVMT
) return FALSE
;
1633 if (g_blockEventsOnDrag
) return FALSE
;
1635 switch ( g_sendActivateEvent
)
1638 // we've got focus from outside, synthetize wxActivateEvent
1639 g_sendActivateEvent
= 1;
1643 // another our window just lost focus, it was already ours before
1644 // - don't send any wxActivateEvent
1645 g_sendActivateEvent
= -1;
1650 g_focusWindow
= win
;
1652 wxLogTrace(TRACE_FOCUS
,
1653 _T("%s: focus in"), win
->GetName().c_str());
1657 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1661 // caret needs to be informed about focus change
1662 wxCaret
*caret
= win
->GetCaret();
1665 caret
->OnSetFocus();
1667 #endif // wxUSE_CARET
1669 g_activeFrameLostFocus
= FALSE
;
1671 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1672 if ( active
!= g_activeFrame
)
1674 if ( g_activeFrame
)
1676 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1677 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1678 event
.SetEventObject(g_activeFrame
);
1679 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1682 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1683 g_activeFrame
= active
;
1684 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1685 event
.SetEventObject(g_activeFrame
);
1686 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1688 // Don't send focus events in addition to activate
1689 // if (win == g_activeFrame)
1693 // does the window itself think that it has the focus?
1694 if ( !win
->m_hasFocus
)
1696 // not yet, notify it
1697 win
->m_hasFocus
= TRUE
;
1699 if ( DoSendFocusEvents(win
) )
1701 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1709 //-----------------------------------------------------------------------------
1710 // "focus_out_event"
1711 //-----------------------------------------------------------------------------
1713 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1718 wxapp_install_idle_handler();
1720 if (!win
->m_hasVMT
) return FALSE
;
1721 if (g_blockEventsOnDrag
) return FALSE
;
1723 wxLogTrace( TRACE_FOCUS
,
1724 _T("%s: focus out"), win
->GetName().c_str() );
1726 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1728 // VZ: commenting this out because it does happen (although not easy
1729 // to reproduce, I only see it when using wxMiniFrame and not
1730 // always) and makes using Mahogany quite annoying
1732 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1733 wxT("unfocusing window that hasn't gained focus properly") )
1736 g_activeFrameLostFocus
= TRUE
;
1739 // if the focus goes out of our app alltogether, OnIdle() will send
1740 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1741 // g_sendActivateEvent to -1
1742 g_sendActivateEvent
= 0;
1744 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1748 g_focusWindow
= (wxWindowGTK
*)NULL
;
1756 // caret needs to be informed about focus change
1757 wxCaret
*caret
= win
->GetCaret();
1760 caret
->OnKillFocus();
1762 #endif // wxUSE_CARET
1764 // don't send the window a kill focus event if it thinks that it doesn't
1765 // have focus already
1766 if ( win
->m_hasFocus
)
1768 win
->m_hasFocus
= FALSE
;
1770 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1771 event
.SetEventObject( win
);
1773 if (win
->GetEventHandler()->ProcessEvent( event
))
1775 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1783 //-----------------------------------------------------------------------------
1784 // "enter_notify_event"
1785 //-----------------------------------------------------------------------------
1787 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1792 wxapp_install_idle_handler();
1794 if (!win
->m_hasVMT
) return FALSE
;
1795 if (g_blockEventsOnDrag
) return FALSE
;
1797 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1799 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1800 event
.SetTimestamp( gdk_event
->time
);
1801 event
.SetEventObject( win
);
1805 GdkModifierType state
= (GdkModifierType
)0;
1807 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1809 InitMouseEvent(win
, event
, gdk_event
);
1810 wxPoint pt
= win
->GetClientAreaOrigin();
1811 event
.m_x
= x
+ pt
.x
;
1812 event
.m_y
= y
+ pt
.y
;
1814 if (win
->GetEventHandler()->ProcessEvent( event
))
1816 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1823 //-----------------------------------------------------------------------------
1824 // "leave_notify_event"
1825 //-----------------------------------------------------------------------------
1827 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1832 wxapp_install_idle_handler();
1834 if (!win
->m_hasVMT
) return FALSE
;
1835 if (g_blockEventsOnDrag
) return FALSE
;
1837 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1839 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1840 event
.SetTimestamp( gdk_event
->time
);
1841 event
.SetEventObject( win
);
1845 GdkModifierType state
= (GdkModifierType
)0;
1847 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1849 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1850 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1851 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1852 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1853 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1854 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1855 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1857 wxPoint pt
= win
->GetClientAreaOrigin();
1858 event
.m_x
= x
+ pt
.x
;
1859 event
.m_y
= y
+ pt
.y
;
1861 if (win
->GetEventHandler()->ProcessEvent( event
))
1863 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1870 //-----------------------------------------------------------------------------
1871 // "value_changed" from m_vAdjust
1872 //-----------------------------------------------------------------------------
1874 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1881 wxapp_install_idle_handler();
1883 if (g_blockEventsOnDrag
) return;
1885 if (!win
->m_hasVMT
) return;
1887 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1888 if (fabs(diff
) < 0.2) return;
1890 win
->m_oldVerticalPos
= adjust
->value
;
1892 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1893 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
1895 int value
= (int)(adjust
->value
+0.5);
1897 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1898 event
.SetEventObject( win
);
1899 win
->GetEventHandler()->ProcessEvent( event
);
1902 //-----------------------------------------------------------------------------
1903 // "value_changed" from m_hAdjust
1904 //-----------------------------------------------------------------------------
1906 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1913 wxapp_install_idle_handler();
1915 if (g_blockEventsOnDrag
) return;
1916 if (!win
->m_hasVMT
) return;
1918 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1919 if (fabs(diff
) < 0.2) return;
1921 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1922 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
1924 win
->m_oldHorizontalPos
= adjust
->value
;
1926 int value
= (int)(adjust
->value
+0.5);
1928 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1929 event
.SetEventObject( win
);
1930 win
->GetEventHandler()->ProcessEvent( event
);
1933 //-----------------------------------------------------------------------------
1934 // "button_press_event" from scrollbar
1935 //-----------------------------------------------------------------------------
1937 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1938 GdkEventButton
*gdk_event
,
1944 wxapp_install_idle_handler();
1947 g_blockEventsOnScroll
= TRUE
;
1949 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1951 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1957 //-----------------------------------------------------------------------------
1958 // "button_release_event" from scrollbar
1959 //-----------------------------------------------------------------------------
1961 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1962 GdkEventButton
*WXUNUSED(gdk_event
),
1967 // don't test here as we can release the mouse while being over
1968 // a different window than the slider
1970 // if (gdk_event->window != widget->slider) return FALSE;
1972 g_blockEventsOnScroll
= FALSE
;
1974 if (win
->m_isScrolling
)
1976 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1980 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1981 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1983 value
= (int)(win
->m_hAdjust
->value
+0.5);
1986 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
1988 value
= (int)(win
->m_vAdjust
->value
+0.5);
1992 wxScrollWinEvent
event( command
, value
, dir
);
1993 event
.SetEventObject( win
);
1994 win
->GetEventHandler()->ProcessEvent( event
);
1997 win
->m_isScrolling
= FALSE
;
2002 // ----------------------------------------------------------------------------
2003 // this wxWindowBase function is implemented here (in platform-specific file)
2004 // because it is static and so couldn't be made virtual
2005 // ----------------------------------------------------------------------------
2007 wxWindow
*wxWindowBase::FindFocus()
2009 // the cast is necessary when we compile in wxUniversal mode
2010 return (wxWindow
*)g_focusWindow
;
2013 //-----------------------------------------------------------------------------
2015 //-----------------------------------------------------------------------------
2017 static void gtk_window_destroy_callback( GtkWidget
* widget
, wxWindow
*win
)
2019 wxWindowDestroyEvent
event(win
);
2020 win
->GetEventHandler()->ProcessEvent(event
);
2023 //-----------------------------------------------------------------------------
2024 // "realize" from m_widget
2025 //-----------------------------------------------------------------------------
2027 /* We cannot set colours and fonts before the widget has
2028 been realized, so we do this directly after realization. */
2031 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2036 wxapp_install_idle_handler();
2038 if (win
->m_delayedBackgroundColour
)
2039 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2041 if (win
->m_delayedForegroundColour
)
2042 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2044 wxWindowCreateEvent
event( win
);
2045 event
.SetEventObject( win
);
2046 win
->GetEventHandler()->ProcessEvent( event
);
2051 //-----------------------------------------------------------------------------
2053 //-----------------------------------------------------------------------------
2056 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2057 GtkAllocation
*WXUNUSED(alloc
),
2061 wxapp_install_idle_handler();
2063 if (!win
->m_hasScrolling
) return;
2065 int client_width
= 0;
2066 int client_height
= 0;
2067 win
->GetClientSize( &client_width
, &client_height
);
2068 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2071 win
->m_oldClientWidth
= client_width
;
2072 win
->m_oldClientHeight
= client_height
;
2074 if (!win
->m_nativeSizeEvent
)
2076 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2077 event
.SetEventObject( win
);
2078 win
->GetEventHandler()->ProcessEvent( event
);
2084 #define WXUNUSED_UNLESS_XIM(param) param
2086 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2089 /* Resize XIM window */
2092 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2093 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2094 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2097 wxapp_install_idle_handler();
2103 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2107 gdk_window_get_size (widget
->window
, &width
, &height
);
2108 win
->m_icattr
->preedit_area
.width
= width
;
2109 win
->m_icattr
->preedit_area
.height
= height
;
2110 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2115 //-----------------------------------------------------------------------------
2116 // "realize" from m_wxwindow
2117 //-----------------------------------------------------------------------------
2119 /* Initialize XIM support */
2122 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2123 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2126 wxapp_install_idle_handler();
2129 if (win
->m_ic
) return FALSE
;
2130 if (!widget
) return FALSE
;
2131 if (!gdk_im_ready()) return FALSE
;
2133 win
->m_icattr
= gdk_ic_attr_new();
2134 if (!win
->m_icattr
) return FALSE
;
2138 GdkColormap
*colormap
;
2139 GdkICAttr
*attr
= win
->m_icattr
;
2140 unsigned attrmask
= GDK_IC_ALL_REQ
;
2142 GdkIMStyle supported_style
= (GdkIMStyle
)
2143 (GDK_IM_PREEDIT_NONE
|
2144 GDK_IM_PREEDIT_NOTHING
|
2145 GDK_IM_PREEDIT_POSITION
|
2146 GDK_IM_STATUS_NONE
|
2147 GDK_IM_STATUS_NOTHING
);
2149 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2150 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2152 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2153 attr
->client_window
= widget
->window
;
2155 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2156 gtk_widget_get_default_colormap ())
2158 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2159 attr
->preedit_colormap
= colormap
;
2162 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2163 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2164 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2165 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2167 switch (style
& GDK_IM_PREEDIT_MASK
)
2169 case GDK_IM_PREEDIT_POSITION
:
2170 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2172 g_warning ("over-the-spot style requires fontset");
2176 gdk_window_get_size (widget
->window
, &width
, &height
);
2178 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2179 attr
->spot_location
.x
= 0;
2180 attr
->spot_location
.y
= height
;
2181 attr
->preedit_area
.x
= 0;
2182 attr
->preedit_area
.y
= 0;
2183 attr
->preedit_area
.width
= width
;
2184 attr
->preedit_area
.height
= height
;
2185 attr
->preedit_fontset
= widget
->style
->font
;
2190 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2192 if (win
->m_ic
== NULL
)
2193 g_warning ("Can't create input context.");
2196 mask
= gdk_window_get_events (widget
->window
);
2197 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2198 gdk_window_set_events (widget
->window
, mask
);
2200 if (GTK_WIDGET_HAS_FOCUS(widget
))
2201 gdk_im_begin (win
->m_ic
, widget
->window
);
2208 //-----------------------------------------------------------------------------
2209 // InsertChild for wxWindowGTK.
2210 //-----------------------------------------------------------------------------
2212 /* Callback for wxWindowGTK. This very strange beast has to be used because
2213 * C++ has no virtual methods in a constructor. We have to emulate a
2214 * virtual function here as wxNotebook requires a different way to insert
2215 * a child in it. I had opted for creating a wxNotebookPage window class
2216 * which would have made this superfluous (such in the MDI window system),
2217 * but no-one was listening to me... */
2219 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2221 /* the window might have been scrolled already, do we
2222 have to adapt the position */
2223 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2224 child
->m_x
+= pizza
->xoffset
;
2225 child
->m_y
+= pizza
->yoffset
;
2227 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2228 GTK_WIDGET(child
->m_widget
),
2235 //-----------------------------------------------------------------------------
2237 //-----------------------------------------------------------------------------
2239 wxWindow
*wxGetActiveWindow()
2241 return wxWindow::FindFocus();
2244 //-----------------------------------------------------------------------------
2246 //-----------------------------------------------------------------------------
2248 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2250 #ifdef __WXUNIVERSAL__
2251 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2253 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2254 #endif // __WXUNIVERSAL__/__WXGTK__
2256 void wxWindowGTK::Init()
2262 m_widget
= (GtkWidget
*) NULL
;
2263 m_wxwindow
= (GtkWidget
*) NULL
;
2264 m_focusWidget
= (GtkWidget
*) NULL
;
2274 m_needParent
= TRUE
;
2275 m_isBeingDeleted
= FALSE
;
2278 m_nativeSizeEvent
= FALSE
;
2280 m_hasScrolling
= FALSE
;
2281 m_isScrolling
= FALSE
;
2283 m_hAdjust
= (GtkAdjustment
*) NULL
;
2284 m_vAdjust
= (GtkAdjustment
*) NULL
;
2285 m_oldHorizontalPos
= 0.0;
2286 m_oldVerticalPos
= 0.0;
2289 m_widgetStyle
= (GtkStyle
*) NULL
;
2291 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2293 m_acceptsFocus
= FALSE
;
2296 m_clipPaintRegion
= FALSE
;
2298 m_cursor
= *wxSTANDARD_CURSOR
;
2300 m_delayedForegroundColour
= FALSE
;
2301 m_delayedBackgroundColour
= FALSE
;
2304 m_ic
= (GdkIC
*) NULL
;
2305 m_icattr
= (GdkICAttr
*) NULL
;
2309 wxWindowGTK::wxWindowGTK()
2314 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2319 const wxString
&name
)
2323 Create( parent
, id
, pos
, size
, style
, name
);
2326 bool wxWindowGTK::Create( wxWindow
*parent
,
2331 const wxString
&name
)
2333 if (!PreCreation( parent
, pos
, size
) ||
2334 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2336 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2340 m_insertCallback
= wxInsertChildInWindow
;
2342 // always needed for background clearing
2343 m_delayedBackgroundColour
= TRUE
;
2345 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2346 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2348 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2350 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2351 scroll_class
->scrollbar_spacing
= 0;
2353 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2355 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2356 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2358 m_wxwindow
= gtk_pizza_new();
2360 #ifndef __WXUNIVERSAL__
2361 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2363 if (HasFlag(wxRAISED_BORDER
))
2365 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2367 else if (HasFlag(wxSUNKEN_BORDER
))
2369 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2371 else if (HasFlag(wxSIMPLE_BORDER
))
2373 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2377 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2379 #endif // __WXUNIVERSAL__
2381 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2383 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2384 m_acceptsFocus
= TRUE
;
2386 // I _really_ don't want scrollbars in the beginning
2387 m_vAdjust
->lower
= 0.0;
2388 m_vAdjust
->upper
= 1.0;
2389 m_vAdjust
->value
= 0.0;
2390 m_vAdjust
->step_increment
= 1.0;
2391 m_vAdjust
->page_increment
= 1.0;
2392 m_vAdjust
->page_size
= 5.0;
2393 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2394 m_hAdjust
->lower
= 0.0;
2395 m_hAdjust
->upper
= 1.0;
2396 m_hAdjust
->value
= 0.0;
2397 m_hAdjust
->step_increment
= 1.0;
2398 m_hAdjust
->page_increment
= 1.0;
2399 m_hAdjust
->page_size
= 5.0;
2400 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2402 // these handlers block mouse events to any window during scrolling such as
2403 // motion events and prevent GTK and wxWindows from fighting over where the
2406 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2407 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2409 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2410 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2412 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2413 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2415 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2416 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2418 // these handlers get notified when screen updates are required either when
2419 // scrolling or when the window size (and therefore scrollbar configuration)
2422 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2423 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2424 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2425 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2427 gtk_widget_show( m_wxwindow
);
2430 m_parent
->DoAddChild( this );
2432 m_focusWidget
= m_wxwindow
;
2441 wxWindowGTK::~wxWindowGTK()
2443 if (g_focusWindow
== this)
2444 g_focusWindow
= NULL
;
2446 if (g_activeFrame
== this)
2447 g_activeFrame
= NULL
;
2449 if ( g_delayedFocus
== this )
2450 g_delayedFocus
= NULL
;
2452 m_isBeingDeleted
= TRUE
;
2461 m_parent
->RemoveChild( this );
2465 gdk_ic_destroy (m_ic
);
2467 gdk_ic_attr_destroy (m_icattr
);
2472 #if DISABLE_STYLE_IF_BROKEN_THEME
2473 // don't delete if it's a pixmap theme style
2474 if (!m_widgetStyle
->engine_data
)
2475 gtk_style_unref( m_widgetStyle
);
2477 m_widgetStyle
= (GtkStyle
*) NULL
;
2482 gtk_widget_destroy( m_wxwindow
);
2483 m_wxwindow
= (GtkWidget
*) NULL
;
2488 gtk_widget_destroy( m_widget
);
2489 m_widget
= (GtkWidget
*) NULL
;
2493 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2495 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2497 /* this turns -1 into 20 so that a minimal window is
2498 visible even although -1,-1 has been given as the
2499 size of the window. the same trick is used in other
2500 ports and should make debugging easier */
2501 m_width
= WidthDefault(size
.x
);
2502 m_height
= HeightDefault(size
.y
);
2507 /* some reasonable defaults */
2512 m_x
= (gdk_screen_width () - m_width
) / 2;
2513 if (m_x
< 10) m_x
= 10;
2517 m_y
= (gdk_screen_height () - m_height
) / 2;
2518 if (m_y
< 10) m_y
= 10;
2525 void wxWindowGTK::PostCreation()
2527 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2533 // these get reported to wxWindows -> wxPaintEvent
2535 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2537 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2538 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2541 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2542 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2544 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2546 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2547 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2550 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2554 // these are called when the "sunken" or "raised" borders are drawn
2555 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2556 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2559 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2560 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2566 if (m_focusWidget
== NULL
)
2567 m_focusWidget
= m_widget
;
2569 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2570 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2572 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2573 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2575 // connect to the various key and mouse handlers
2577 GtkWidget
*connect_widget
= GetConnectWidget();
2579 ConnectWidget( connect_widget
);
2581 /* We cannot set colours, fonts and cursors before the widget has
2582 been realized, so we do this directly after realization */
2583 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2584 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2588 // Catch native resize events
2589 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2590 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2592 // Initialize XIM support
2593 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2594 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2596 // And resize XIM window
2597 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2598 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2601 if (!GTK_IS_COMBO(m_widget
))
2603 // This is needed if we want to add our windows into native
2604 // GTK control, such as the toolbar. With this callback, the
2605 // toolbar gets to know the correct size (the one set by the
2606 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2607 // when moving to GTK 2.0.
2608 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2609 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2615 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2617 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2618 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2620 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2621 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2623 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2624 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2626 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2627 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2629 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2630 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2632 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2633 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2635 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2636 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2638 gtk_signal_connect( GTK_OBJECT(widget
), "destroy",
2639 GTK_SIGNAL_FUNC(gtk_window_destroy_callback
), (gpointer
)this );
2642 bool wxWindowGTK::Destroy()
2644 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2648 return wxWindowBase::Destroy();
2651 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2653 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2656 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2658 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2659 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2662 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2665 if (m_resizing
) return; /* I don't like recursions */
2668 int currentX
, currentY
;
2669 GetPosition(¤tX
, ¤tY
);
2674 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2676 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2678 /* don't set the size for children of wxNotebook, just take the values. */
2686 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2687 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2689 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2690 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2691 if (width
!= -1) m_width
= width
;
2692 if (height
!= -1) m_height
= height
;
2696 m_x
= x
+ pizza
->xoffset
;
2697 m_y
= y
+ pizza
->yoffset
;
2702 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2704 if (width
== -1) m_width
= 80;
2707 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2709 if (height
== -1) m_height
= 26;
2712 int minWidth
= GetMinWidth(),
2713 minHeight
= GetMinHeight(),
2714 maxWidth
= GetMaxWidth(),
2715 maxHeight
= GetMaxHeight();
2717 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2718 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2719 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2720 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2723 int bottom_border
= 0;
2726 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2728 /* the default button has a border around it */
2734 DoMoveWindow( m_x
-border
,
2737 m_height
+border
+bottom_border
);
2742 /* Sometimes the client area changes size without the
2743 whole windows's size changing, but if the whole
2744 windows's size doesn't change, no wxSizeEvent will
2745 normally be sent. Here we add an extra test if
2746 the client test has been changed and this will
2748 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2752 wxPrintf( "OnSize sent from " );
2753 if (GetClassInfo() && GetClassInfo()->GetClassName())
2754 wxPrintf( GetClassInfo()->GetClassName() );
2755 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2758 if (!m_nativeSizeEvent
)
2760 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2761 event
.SetEventObject( this );
2762 GetEventHandler()->ProcessEvent( event
);
2768 void wxWindowGTK::OnInternalIdle()
2770 // Update invalidated regions.
2773 // Synthetize activate events.
2774 if ( g_sendActivateEvent
!= -1 )
2776 bool activate
= g_sendActivateEvent
!= 0;
2779 g_sendActivateEvent
= -1;
2781 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2784 if ( g_activeFrameLostFocus
)
2786 if ( g_activeFrame
)
2788 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2789 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2790 event
.SetEventObject(g_activeFrame
);
2791 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2792 g_activeFrame
= NULL
;
2794 g_activeFrameLostFocus
= FALSE
;
2797 wxCursor cursor
= m_cursor
;
2798 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2802 /* I now set the cursor anew in every OnInternalIdle call
2803 as setting the cursor in a parent window also effects the
2804 windows above so that checking for the current cursor is
2809 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2811 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2813 if (!g_globalCursor
.Ok())
2814 cursor
= *wxSTANDARD_CURSOR
;
2816 window
= m_widget
->window
;
2817 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2818 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2824 GdkWindow
*window
= m_widget
->window
;
2825 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2826 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2834 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2836 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2838 if (width
) (*width
) = m_width
;
2839 if (height
) (*height
) = m_height
;
2842 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2844 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2848 SetSize( width
, height
);
2855 #ifndef __WXUNIVERSAL__
2856 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2858 /* when using GTK 1.2 we set the shadow border size to 2 */
2862 if (HasFlag(wxSIMPLE_BORDER
))
2864 /* when using GTK 1.2 we set the simple border size to 1 */
2868 #endif // __WXUNIVERSAL__
2872 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2874 GtkRequisition vscroll_req
;
2875 vscroll_req
.width
= 2;
2876 vscroll_req
.height
= 2;
2877 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2878 (scroll_window
->vscrollbar
, &vscroll_req
);
2880 GtkRequisition hscroll_req
;
2881 hscroll_req
.width
= 2;
2882 hscroll_req
.height
= 2;
2883 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2884 (scroll_window
->hscrollbar
, &hscroll_req
);
2886 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2888 if (scroll_window
->vscrollbar_visible
)
2890 dw
+= vscroll_req
.width
;
2891 dw
+= scroll_class
->scrollbar_spacing
;
2894 if (scroll_window
->hscrollbar_visible
)
2896 dh
+= hscroll_req
.height
;
2897 dh
+= scroll_class
->scrollbar_spacing
;
2901 SetSize( width
+dw
, height
+dh
);
2905 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2907 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2911 if (width
) (*width
) = m_width
;
2912 if (height
) (*height
) = m_height
;
2919 #ifndef __WXUNIVERSAL__
2920 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2922 /* when using GTK 1.2 we set the shadow border size to 2 */
2926 if (HasFlag(wxSIMPLE_BORDER
))
2928 /* when using GTK 1.2 we set the simple border size to 1 */
2932 #endif // __WXUNIVERSAL__
2936 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2938 GtkRequisition vscroll_req
;
2939 vscroll_req
.width
= 2;
2940 vscroll_req
.height
= 2;
2941 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2942 (scroll_window
->vscrollbar
, &vscroll_req
);
2944 GtkRequisition hscroll_req
;
2945 hscroll_req
.width
= 2;
2946 hscroll_req
.height
= 2;
2947 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2948 (scroll_window
->hscrollbar
, &hscroll_req
);
2950 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2952 if (scroll_window
->vscrollbar_visible
)
2954 dw
+= vscroll_req
.width
;
2955 dw
+= scroll_class
->scrollbar_spacing
;
2958 if (scroll_window
->hscrollbar_visible
)
2960 dh
+= hscroll_req
.height
;
2961 dh
+= scroll_class
->scrollbar_spacing
;
2965 if (width
) (*width
) = m_width
- dw
;
2966 if (height
) (*height
) = m_height
- dh
;
2970 printf( "GetClientSize, name %s ", GetName().c_str() );
2971 if (width) printf( " width = %d", (*width) );
2972 if (height) printf( " height = %d", (*height) );
2977 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2979 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2983 if (m_parent
&& m_parent
->m_wxwindow
)
2985 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2986 dx
= pizza
->xoffset
;
2987 dy
= pizza
->yoffset
;
2990 if (x
) (*x
) = m_x
- dx
;
2991 if (y
) (*y
) = m_y
- dy
;
2994 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2996 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2998 if (!m_widget
->window
) return;
3000 GdkWindow
*source
= (GdkWindow
*) NULL
;
3002 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3004 source
= m_widget
->window
;
3008 gdk_window_get_origin( source
, &org_x
, &org_y
);
3012 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3014 org_x
+= m_widget
->allocation
.x
;
3015 org_y
+= m_widget
->allocation
.y
;
3023 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3025 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3027 if (!m_widget
->window
) return;
3029 GdkWindow
*source
= (GdkWindow
*) NULL
;
3031 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3033 source
= m_widget
->window
;
3037 gdk_window_get_origin( source
, &org_x
, &org_y
);
3041 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3043 org_x
+= m_widget
->allocation
.x
;
3044 org_y
+= m_widget
->allocation
.y
;
3052 bool wxWindowGTK::Show( bool show
)
3054 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3056 if (!wxWindowBase::Show(show
))
3063 gtk_widget_show( m_widget
);
3065 gtk_widget_hide( m_widget
);
3070 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3072 win
->OnParentEnable(enable
);
3074 // Recurse, so that children have the opportunity to Do The Right Thing
3075 // and reset colours that have been messed up by a parent's (really ancestor's)
3077 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3079 node
= node
->GetNext() )
3081 wxWindow
*child
= node
->GetData();
3082 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3083 wxWindowNotifyEnable(child
, enable
);
3087 bool wxWindowGTK::Enable( bool enable
)
3089 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3091 if (!wxWindowBase::Enable(enable
))
3097 gtk_widget_set_sensitive( m_widget
, enable
);
3099 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3101 wxWindowNotifyEnable(this, enable
);
3106 int wxWindowGTK::GetCharHeight() const
3108 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3110 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3112 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3114 return font
->ascent
+ font
->descent
;
3117 int wxWindowGTK::GetCharWidth() const
3119 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3121 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3123 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3125 return gdk_string_width( font
, "H" );
3128 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3132 int *externalLeading
,
3133 const wxFont
*theFont
) const
3135 wxFont fontToUse
= m_font
;
3136 if (theFont
) fontToUse
= *theFont
;
3138 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3140 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3141 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3142 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3143 if (descent
) (*descent
) = font
->descent
;
3144 if (externalLeading
) (*externalLeading
) = 0; // ??
3147 void wxWindowGTK::SetFocus()
3149 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3153 // don't do anything if we already have focus
3159 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3161 gtk_widget_grab_focus (m_wxwindow
);
3166 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3168 if (!GTK_WIDGET_REALIZED(m_widget
))
3170 // we can't set the focus to the widget now so we remember that
3171 // it should be focused and will do it later, during the idle
3172 // time, as soon as we can
3173 wxLogTrace(TRACE_FOCUS
,
3174 _T("Delaying setting focus to %s(%s)"),
3175 GetClassInfo()->GetClassName(), GetLabel().c_str());
3177 g_delayedFocus
= this;
3181 wxLogTrace(TRACE_FOCUS
,
3182 _T("Setting focus to %s(%s)"),
3183 GetClassInfo()->GetClassName(), GetLabel().c_str());
3185 gtk_widget_grab_focus (m_widget
);
3188 else if (GTK_IS_CONTAINER(m_widget
))
3190 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3194 wxLogTrace(TRACE_FOCUS
,
3195 _T("Can't set focus to %s(%s)"),
3196 GetClassInfo()->GetClassName(), GetLabel().c_str());
3201 bool wxWindowGTK::AcceptsFocus() const
3203 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3206 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3208 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3210 wxWindowGTK
*oldParent
= m_parent
,
3211 *newParent
= (wxWindowGTK
*)newParentBase
;
3213 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3215 if ( !wxWindowBase::Reparent(newParent
) )
3218 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3220 /* prevent GTK from deleting the widget arbitrarily */
3221 gtk_widget_ref( m_widget
);
3225 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3228 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3232 /* insert GTK representation */
3233 (*(newParent
->m_insertCallback
))(newParent
, this);
3236 /* reverse: prevent GTK from deleting the widget arbitrarily */
3237 gtk_widget_unref( m_widget
);
3242 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3244 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3246 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3248 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3253 /* insert GTK representation */
3254 (*m_insertCallback
)(this, child
);
3257 void wxWindowGTK::Raise()
3259 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3261 if (!m_widget
->window
) return;
3263 gdk_window_raise( m_widget
->window
);
3266 void wxWindowGTK::Lower()
3268 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3270 if (!m_widget
->window
) return;
3272 gdk_window_lower( m_widget
->window
);
3275 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3277 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3279 if (cursor
== m_cursor
)
3283 wxapp_install_idle_handler();
3285 if (cursor
== wxNullCursor
)
3286 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3288 return wxWindowBase::SetCursor( cursor
);
3291 void wxWindowGTK::WarpPointer( int x
, int y
)
3293 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3295 // We provide this function ourselves as it is
3296 // missing in GDK (top of this file).
3298 GdkWindow
*window
= (GdkWindow
*) NULL
;
3300 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3302 window
= GetConnectWidget()->window
;
3305 gdk_window_warp_pointer( window
, x
, y
);
3308 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3310 if (!m_widget
) return;
3311 if (!m_widget
->window
) return;
3315 wxapp_install_idle_handler();
3317 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3321 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3322 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3326 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3327 m_clearRegion
.Clear();
3328 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3336 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3337 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3341 GdkRectangle gdk_rect
;
3342 gdk_rect
.x
= rect
->x
;
3343 gdk_rect
.y
= rect
->y
;
3344 gdk_rect
.width
= rect
->width
;
3345 gdk_rect
.height
= rect
->height
;
3346 gtk_widget_draw( m_widget
, &gdk_rect
);
3353 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3354 m_updateRegion
.Clear();
3355 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3359 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3367 GdkRectangle gdk_rect
;
3368 gdk_rect
.x
= rect
->x
;
3369 gdk_rect
.y
= rect
->y
;
3370 gdk_rect
.width
= rect
->width
;
3371 gdk_rect
.height
= rect
->height
;
3372 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3376 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3382 void wxWindowGTK::Update()
3387 void wxWindowGTK::GtkUpdate()
3390 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3391 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3394 if (!m_updateRegion
.IsEmpty())
3395 GtkSendPaintEvents();
3398 void wxWindowGTK::GtkSendPaintEvents()
3402 m_clearRegion
.Clear();
3403 m_updateRegion
.Clear();
3407 // widget to draw on
3408 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3410 // Clip to paint region in wxClientDC
3411 m_clipPaintRegion
= TRUE
;
3413 if (GetThemeEnabled())
3415 // find ancestor from which to steal background
3416 wxWindow
*parent
= GetParent();
3417 while (parent
&& !parent
->IsTopLevel())
3418 parent
= parent
->GetParent();
3420 parent
= (wxWindow
*)this;
3422 wxRegionIterator
upd( m_updateRegion
);
3426 rect
.x
= upd
.GetX();
3427 rect
.y
= upd
.GetY();
3428 rect
.width
= upd
.GetWidth();
3429 rect
.height
= upd
.GetHeight();
3431 gtk_paint_flat_box( parent
->m_widget
->style
,
3444 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3446 wxWindowDC
dc( (wxWindow
*)this );
3447 dc
.SetClippingRegion( m_clearRegion
);
3449 wxEraseEvent
erase_event( GetId(), &dc
);
3450 erase_event
.SetEventObject( this );
3452 if (!GetEventHandler()->ProcessEvent(erase_event
))
3456 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3457 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3459 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3461 wxRegionIterator
upd( m_clearRegion
);
3464 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3465 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3469 m_clearRegion
.Clear();
3472 wxNcPaintEvent
nc_paint_event( GetId() );
3473 nc_paint_event
.SetEventObject( this );
3474 GetEventHandler()->ProcessEvent( nc_paint_event
);
3476 wxPaintEvent
paint_event( GetId() );
3477 paint_event
.SetEventObject( this );
3478 GetEventHandler()->ProcessEvent( paint_event
);
3480 m_clipPaintRegion
= FALSE
;
3482 #ifndef __WXUNIVERSAL__
3484 // The following code will result in all window-less widgets
3485 // being redrawn because the wxWindows class is allowed to
3486 // paint over the window-less widgets.
3488 GList
*children
= pizza
->children
;
3491 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3492 children
= children
->next
;
3494 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3495 GTK_WIDGET_DRAWABLE (child
->widget
))
3497 // Get intersection of widget area and update region
3498 wxRegion
region( m_updateRegion
);
3500 GdkEventExpose gdk_event
;
3501 gdk_event
.type
= GDK_EXPOSE
;
3502 gdk_event
.window
= pizza
->bin_window
;
3503 gdk_event
.count
= 0;
3505 wxRegionIterator
upd( m_updateRegion
);
3509 rect
.x
= upd
.GetX();
3510 rect
.y
= upd
.GetY();
3511 rect
.width
= upd
.GetWidth();
3512 rect
.height
= upd
.GetHeight();
3514 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3516 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3526 m_updateRegion
.Clear();
3529 void wxWindowGTK::Clear()
3531 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3533 if (m_wxwindow
&& m_wxwindow
->window
)
3535 m_clearRegion
.Clear();
3536 wxSize
size( GetClientSize() );
3537 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3539 // Better do this in idle?
3545 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3547 wxWindowBase::DoSetToolTip(tip
);
3550 m_tooltip
->Apply( (wxWindow
*)this );
3553 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3555 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3557 #endif // wxUSE_TOOLTIPS
3559 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3561 GdkWindow
*window
= (GdkWindow
*) NULL
;
3563 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3565 window
= GetConnectWidget()->window
;
3569 // We need the pixel value e.g. for background clearing.
3570 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3574 // wxMSW doesn't clear the window here, either.
3575 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3581 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3583 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3585 if (!wxWindowBase::SetBackgroundColour(colour
))
3588 GdkWindow
*window
= (GdkWindow
*) NULL
;
3590 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3592 window
= GetConnectWidget()->window
;
3596 // indicate that a new style has been set
3597 // but it couldn't get applied as the
3598 // widget hasn't been realized yet.
3599 m_delayedBackgroundColour
= TRUE
;
3604 GtkSetBackgroundColour( colour
);
3610 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3612 GdkWindow
*window
= (GdkWindow
*) NULL
;
3614 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3616 window
= GetConnectWidget()->window
;
3623 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3625 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3627 if (!wxWindowBase::SetForegroundColour(colour
))
3629 // don't leave if the GTK widget has just
3631 if (!m_delayedForegroundColour
) return FALSE
;
3634 GdkWindow
*window
= (GdkWindow
*) NULL
;
3636 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3638 window
= GetConnectWidget()->window
;
3642 // indicate that a new style has been set
3643 // but it couldn't get applied as the
3644 // widget hasn't been realized yet.
3645 m_delayedForegroundColour
= TRUE
;
3649 GtkSetForegroundColour( colour
);
3655 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3659 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3661 // FIXME: no more klass in 2.0
3663 remake
->klass
= m_widgetStyle
->klass
;
3666 gtk_style_unref( m_widgetStyle
);
3667 m_widgetStyle
= remake
;
3671 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3674 def
= gtk_widget_get_default_style();
3676 m_widgetStyle
= gtk_style_copy( def
);
3678 // FIXME: no more klass in 2.0
3680 m_widgetStyle
->klass
= def
->klass
;
3684 return m_widgetStyle
;
3687 void wxWindowGTK::SetWidgetStyle()
3689 #if DISABLE_STYLE_IF_BROKEN_THEME
3690 if (m_widget
->style
->engine_data
)
3692 static bool s_warningPrinted
= FALSE
;
3693 if (!s_warningPrinted
)
3695 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3696 s_warningPrinted
= TRUE
;
3698 m_widgetStyle
= m_widget
->style
;
3703 GtkStyle
*style
= GetWidgetStyle();
3705 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3707 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3710 if (m_foregroundColour
.Ok())
3712 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3713 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3715 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3716 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3717 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3721 // Try to restore the gtk default style. This is still a little
3722 // oversimplified for what is probably really needed here for controls
3723 // other than buttons, but is better than not being able to (re)set a
3724 // control's foreground colour to *wxBLACK -- RL
3725 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3728 def
= gtk_widget_get_default_style();
3730 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3731 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3732 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3736 if (m_backgroundColour
.Ok())
3738 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3739 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3741 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3742 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3743 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3744 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3745 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3746 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3747 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3748 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3752 // Try to restore the gtk default style. This is still a little
3753 // oversimplified for what is probably really needed here for controls
3754 // other than buttons, but is better than not being able to (re)set a
3755 // control's background colour to default grey and means resetting a
3756 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3758 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3761 def
= gtk_widget_get_default_style();
3763 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3764 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3765 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3766 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3767 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3768 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3769 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3770 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3775 void wxWindowGTK::ApplyWidgetStyle()
3779 //-----------------------------------------------------------------------------
3780 // Pop-up menu stuff
3781 //-----------------------------------------------------------------------------
3783 #if wxUSE_MENUS_NATIVE
3786 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3788 *is_waiting
= FALSE
;
3791 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3793 menu
->SetInvokingWindow( win
);
3794 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3797 wxMenuItem
*menuitem
= node
->GetData();
3798 if (menuitem
->IsSubMenu())
3800 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3803 node
= node
->GetNext();
3807 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3808 // wxPopupMenuPositionCallback()
3810 // should be safe even in the MT case as the user can hardly popup 2 menus
3811 // simultaneously, can he?
3812 static gint gs_pop_x
= 0;
3813 static gint gs_pop_y
= 0;
3815 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3818 gboolean
* WXUNUSED(whatever
),
3820 gpointer
WXUNUSED(user_data
) )
3822 // ensure that the menu appears entirely on screen
3824 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3826 wxSize sizeScreen
= wxGetDisplaySize();
3828 gint xmax
= sizeScreen
.x
- req
.width
,
3829 ymax
= sizeScreen
.y
- req
.height
;
3831 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3832 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3835 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3837 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3839 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3841 SetInvokingWindow( menu
, this );
3847 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3849 bool is_waiting
= TRUE
;
3851 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3853 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3854 (gpointer
)&is_waiting
);
3857 GTK_MENU(menu
->m_menu
),
3858 (GtkWidget
*) NULL
, // parent menu shell
3859 (GtkWidget
*) NULL
, // parent menu item
3860 wxPopupMenuPositionCallback
, // function to position it
3861 NULL
, // client data
3862 0, // button used to activate it
3863 gs_timeLastClick
// the time of activation
3868 while (gtk_events_pending())
3869 gtk_main_iteration();
3875 #endif // wxUSE_MENUS_NATIVE
3877 #if wxUSE_DRAG_AND_DROP
3879 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3881 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3883 GtkWidget
*dnd_widget
= GetConnectWidget();
3885 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3887 if (m_dropTarget
) delete m_dropTarget
;
3888 m_dropTarget
= dropTarget
;
3890 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3893 #endif // wxUSE_DRAG_AND_DROP
3895 GtkWidget
* wxWindowGTK::GetConnectWidget()
3897 GtkWidget
*connect_widget
= m_widget
;
3898 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3900 return connect_widget
;
3903 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3906 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3908 return (window
== m_widget
->window
);
3911 bool wxWindowGTK::SetFont( const wxFont
&font
)
3913 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3915 if (!wxWindowBase::SetFont(font
))
3920 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3921 if ( sysbg
== m_backgroundColour
)
3923 m_backgroundColour
= wxNullColour
;
3925 m_backgroundColour
= sysbg
;
3935 void wxWindowGTK::DoCaptureMouse()
3937 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3939 GdkWindow
*window
= (GdkWindow
*) NULL
;
3941 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3943 window
= GetConnectWidget()->window
;
3945 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3947 wxCursor
* cursor
= & m_cursor
;
3949 cursor
= wxSTANDARD_CURSOR
;
3951 gdk_pointer_grab( window
, FALSE
,
3953 (GDK_BUTTON_PRESS_MASK
|
3954 GDK_BUTTON_RELEASE_MASK
|
3955 GDK_POINTER_MOTION_HINT_MASK
|
3956 GDK_POINTER_MOTION_MASK
),
3958 cursor
->GetCursor(),
3959 (guint32
)GDK_CURRENT_TIME
);
3960 g_captureWindow
= this;
3961 g_captureWindowHasMouse
= TRUE
;
3964 void wxWindowGTK::DoReleaseMouse()
3966 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3968 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3970 g_captureWindow
= (wxWindowGTK
*) NULL
;
3972 GdkWindow
*window
= (GdkWindow
*) NULL
;
3974 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3976 window
= GetConnectWidget()->window
;
3981 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3985 wxWindow
*wxWindowBase::GetCapture()
3987 return (wxWindow
*)g_captureWindow
;
3990 bool wxWindowGTK::IsRetained() const
3995 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3996 int range
, bool refresh
)
3998 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4000 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4002 m_hasScrolling
= TRUE
;
4004 if (orient
== wxHORIZONTAL
)
4006 float fpos
= (float)pos
;
4007 float frange
= (float)range
;
4008 float fthumb
= (float)thumbVisible
;
4009 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4010 if (fpos
< 0.0) fpos
= 0.0;
4012 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4013 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4015 SetScrollPos( orient
, pos
, refresh
);
4019 m_oldHorizontalPos
= fpos
;
4021 m_hAdjust
->lower
= 0.0;
4022 m_hAdjust
->upper
= frange
;
4023 m_hAdjust
->value
= fpos
;
4024 m_hAdjust
->step_increment
= 1.0;
4025 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4026 m_hAdjust
->page_size
= fthumb
;
4030 float fpos
= (float)pos
;
4031 float frange
= (float)range
;
4032 float fthumb
= (float)thumbVisible
;
4033 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4034 if (fpos
< 0.0) fpos
= 0.0;
4036 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4037 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4039 SetScrollPos( orient
, pos
, refresh
);
4043 m_oldVerticalPos
= fpos
;
4045 m_vAdjust
->lower
= 0.0;
4046 m_vAdjust
->upper
= frange
;
4047 m_vAdjust
->value
= fpos
;
4048 m_vAdjust
->step_increment
= 1.0;
4049 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4050 m_vAdjust
->page_size
= fthumb
;
4053 if (orient
== wxHORIZONTAL
)
4054 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4056 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4059 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4061 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4063 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4065 if (orient
== wxHORIZONTAL
)
4067 float fpos
= (float)pos
;
4068 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4069 if (fpos
< 0.0) fpos
= 0.0;
4070 m_oldHorizontalPos
= fpos
;
4072 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4073 m_hAdjust
->value
= fpos
;
4077 float fpos
= (float)pos
;
4078 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4079 if (fpos
< 0.0) fpos
= 0.0;
4080 m_oldVerticalPos
= fpos
;
4082 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4083 m_vAdjust
->value
= fpos
;
4086 if (m_wxwindow
->window
)
4088 if (orient
== wxHORIZONTAL
)
4090 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4091 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4093 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4095 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4096 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4100 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4101 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4103 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4105 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4106 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4111 int wxWindowGTK::GetScrollThumb( int orient
) const
4113 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4115 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4117 if (orient
== wxHORIZONTAL
)
4118 return (int)(m_hAdjust
->page_size
+0.5);
4120 return (int)(m_vAdjust
->page_size
+0.5);
4123 int wxWindowGTK::GetScrollPos( int orient
) const
4125 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4127 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4129 if (orient
== wxHORIZONTAL
)
4130 return (int)(m_hAdjust
->value
+0.5);
4132 return (int)(m_vAdjust
->value
+0.5);
4135 int wxWindowGTK::GetScrollRange( int orient
) const
4137 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4139 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4141 if (orient
== wxHORIZONTAL
)
4142 return (int)(m_hAdjust
->upper
+0.5);
4144 return (int)(m_vAdjust
->upper
+0.5);
4147 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4149 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4151 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4153 // No scrolling requested.
4154 if ((dx
== 0) && (dy
== 0)) return;
4157 if (!m_updateRegion
.IsEmpty())
4159 m_updateRegion
.Offset( dx
, dy
);
4163 GetClientSize( &cw
, &ch
);
4164 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4167 if (!m_clearRegion
.IsEmpty())
4169 m_clearRegion
.Offset( dx
, dy
);
4173 GetClientSize( &cw
, &ch
);
4174 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4176 m_clipPaintRegion
= TRUE
;
4178 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4180 m_clipPaintRegion
= FALSE
;
4183 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4185 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4186 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4193 // Find the wxWindow at the current mouse position, also returning the mouse
4195 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4197 pt
= wxGetMousePosition();
4198 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4202 // Get the current mouse position.
4203 wxPoint
wxGetMousePosition()
4205 /* This crashes when used within wxHelpContext,
4206 so we have to use the X-specific implementation below.
4208 GdkModifierType *mask;
4209 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4211 return wxPoint(x, y);
4215 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4217 return wxPoint(-999, -999);
4219 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4220 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4221 Window rootReturn
, childReturn
;
4222 int rootX
, rootY
, winX
, winY
;
4223 unsigned int maskReturn
;
4225 XQueryPointer (display
,
4229 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4230 return wxPoint(rootX
, rootY
);
4234 // ----------------------------------------------------------------------------
4236 // ----------------------------------------------------------------------------
4238 class wxWinModule
: public wxModule
4245 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4248 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4250 bool wxWinModule::OnInit()
4252 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4253 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4258 void wxWinModule::OnExit()
4261 gdk_gc_unref( g_eraseGC
);