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 = %ld"),
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 %ld"), key_code
);
1028 // sending unknown key events doesn't really make sense
1032 // now fill all the other fields
1035 GdkModifierType state
;
1036 if (gdk_event
->window
)
1037 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1039 event
.SetTimestamp( gdk_event
->time
);
1040 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1041 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1042 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1043 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1044 event
.m_keyCode
= key_code
;
1045 event
.m_scanCode
= gdk_event
->keyval
;
1046 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1047 event
.m_rawFlags
= 0;
1050 event
.SetEventObject( win
);
1055 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1056 GdkEventKey
*gdk_event
,
1062 wxapp_install_idle_handler();
1066 if (g_blockEventsOnDrag
)
1070 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1071 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1073 // unknown key pressed, ignore (the event would be useless anyhow)
1077 // Emit KEY_DOWN event
1078 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1083 wxWindowGTK
*ancestor
= win
;
1086 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1089 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1090 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1093 if (ancestor
->IsTopLevel())
1095 ancestor
= ancestor
->GetParent();
1098 #endif // wxUSE_ACCEL
1100 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1101 // will only be sent if it is not in an accelerator table.
1104 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1105 KeySym keysym
= gdk_event
->keyval
;
1106 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1109 if ( gdk_event
->length
== 1 )
1111 key_code
= (unsigned char)gdk_event
->string
[0];
1113 else if ( wxIsAsciiKeysym(keysym
) )
1116 key_code
= (unsigned char)keysym
;
1122 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1124 event
.m_keyCode
= key_code
;
1126 // Implement OnCharHook by checking ancesteror top level windows
1127 wxWindow
*parent
= win
;
1128 while (parent
&& !parent
->IsTopLevel())
1129 parent
= parent
->GetParent();
1132 event
.SetEventType( wxEVT_CHAR_HOOK
);
1133 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1138 event
.SetEventType(wxEVT_CHAR
);
1139 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1144 // win is a control: tab can be propagated up
1146 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1147 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1148 // have this style, yet choose not to process this particular TAB in which
1149 // case TAB must still work as a navigational character
1151 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1153 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1155 wxNavigationKeyEvent new_event
;
1156 new_event
.SetEventObject( win
->GetParent() );
1157 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1158 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1159 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1160 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1161 new_event
.SetCurrentFocus( win
);
1162 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1165 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1167 (gdk_event
->keyval
== GDK_Escape
) )
1169 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1170 new_event
.SetEventObject( win
);
1171 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1176 // Pressing F10 will activate the menu bar of the top frame
1178 (gdk_event
->keyval
== GDK_F10
) )
1180 wxWindowGTK
*ancestor
= win
;
1183 if (wxIsKindOf(ancestor
,wxFrame
))
1185 wxFrame
*frame
= (wxFrame
*) ancestor
;
1186 wxMenuBar
*menubar
= frame
->GetMenuBar();
1189 wxNode
*node
= menubar
->GetMenus().First();
1192 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1193 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1199 ancestor
= ancestor
->GetParent();
1206 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1213 //-----------------------------------------------------------------------------
1214 // "key_release_event" from any window
1215 //-----------------------------------------------------------------------------
1217 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1218 GdkEventKey
*gdk_event
,
1224 wxapp_install_idle_handler();
1229 if (g_blockEventsOnDrag
)
1232 wxKeyEvent
event( wxEVT_KEY_UP
);
1233 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1235 // unknown key pressed, ignore (the event would be useless anyhow
1239 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1242 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1246 // ============================================================================
1248 // ============================================================================
1250 // ----------------------------------------------------------------------------
1251 // mouse event processing helpers
1252 // ----------------------------------------------------------------------------
1254 // init wxMouseEvent with the info from gdk_event
1256 // NB: this has to be a macro as gdk_event type is different for different
1257 // events we're used with
1258 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1259 /* wxMouseEvent& */ event, \
1260 /* GdkEventXXX * */ gdk_event) \
1262 event.SetTimestamp( gdk_event->time ); \
1263 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1264 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1265 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1266 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1267 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1268 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1269 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1271 wxPoint pt = win->GetClientAreaOrigin(); \
1272 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1273 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1275 event.SetEventObject( win ); \
1276 event.SetId( win->GetId() ); \
1277 event.SetTimestamp( gdk_event->time ); \
1280 static void AdjustEventButtonState(wxMouseEvent& event)
1282 // GDK reports the old state of the button for a button press event, but
1283 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1284 // for a LEFT_DOWN event, not FALSE, so we will invert
1285 // left/right/middleDown for the corresponding click events
1287 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1288 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1289 (event
.GetEventType() == wxEVT_LEFT_UP
))
1291 event
.m_leftDown
= !event
.m_leftDown
;
1295 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1296 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1297 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1299 event
.m_middleDown
= !event
.m_middleDown
;
1303 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1304 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1305 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1307 event
.m_rightDown
= !event
.m_rightDown
;
1312 // find the window to send the mouse event too
1314 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1319 if (win
->m_wxwindow
)
1321 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1322 xx
+= pizza
->xoffset
;
1323 yy
+= pizza
->yoffset
;
1326 wxNode
*node
= win
->GetChildren().First();
1329 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1331 node
= node
->Next();
1332 if (!child
->IsShown())
1335 if (child
->IsTransparentForMouse())
1337 // wxStaticBox is transparent in the box itself
1338 int xx1
= child
->m_x
;
1339 int yy1
= child
->m_y
;
1340 int xx2
= child
->m_x
+ child
->m_width
;
1341 int yy2
= child
->m_x
+ child
->m_height
;
1344 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1346 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1348 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1350 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1361 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1362 (child
->m_x
<= xx
) &&
1363 (child
->m_y
<= yy
) &&
1364 (child
->m_x
+child
->m_width
>= xx
) &&
1365 (child
->m_y
+child
->m_height
>= yy
))
1378 //-----------------------------------------------------------------------------
1379 // "button_press_event"
1380 //-----------------------------------------------------------------------------
1382 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1383 GdkEventButton
*gdk_event
,
1389 wxapp_install_idle_handler();
1392 wxPrintf( wxT("1) OnButtonPress from ") );
1393 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1394 wxPrintf( win->GetClassInfo()->GetClassName() );
1395 wxPrintf( wxT(".\n") );
1397 if (!win
->m_hasVMT
) return FALSE
;
1398 if (g_blockEventsOnDrag
) return TRUE
;
1399 if (g_blockEventsOnScroll
) return TRUE
;
1401 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1403 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1405 gtk_widget_grab_focus( win
->m_wxwindow
);
1407 wxPrintf( wxT("GrabFocus from ") );
1408 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1409 wxPrintf( win->GetClassInfo()->GetClassName() );
1410 wxPrintf( wxT(".\n") );
1414 wxEventType event_type
= wxEVT_NULL
;
1416 if (gdk_event
->button
== 1)
1418 switch (gdk_event
->type
)
1420 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1421 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1425 else if (gdk_event
->button
== 2)
1427 switch (gdk_event
->type
)
1429 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1430 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1434 else if (gdk_event
->button
== 3)
1436 switch (gdk_event
->type
)
1438 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1439 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1444 if ( event_type
== wxEVT_NULL
)
1446 // unknown mouse button or click type
1450 wxMouseEvent
event( event_type
);
1451 InitMouseEvent( win
, event
, gdk_event
);
1453 AdjustEventButtonState(event
);
1455 // wxListBox actually get mouse events from the item, so we need to give it
1456 // a chance to correct this
1457 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1459 // find the correct window to send the event too: it may be a different one
1460 // from the one which got it at GTK+ level because some control don't have
1461 // their own X window and thus cannot get any events.
1462 if ( !g_captureWindow
)
1463 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1465 gs_timeLastClick
= gdk_event
->time
;
1468 wxPrintf( wxT("2) OnButtonPress from ") );
1469 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1470 wxPrintf( win->GetClassInfo()->GetClassName() );
1471 wxPrintf( wxT(".\n") );
1474 if (win
->GetEventHandler()->ProcessEvent( event
))
1476 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1483 //-----------------------------------------------------------------------------
1484 // "button_release_event"
1485 //-----------------------------------------------------------------------------
1487 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1492 wxapp_install_idle_handler();
1494 if (!win
->m_hasVMT
) return FALSE
;
1495 if (g_blockEventsOnDrag
) return FALSE
;
1496 if (g_blockEventsOnScroll
) return FALSE
;
1498 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1501 printf( "OnButtonRelease from " );
1502 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1503 printf( win->GetClassInfo()->GetClassName() );
1507 wxEventType event_type
= wxEVT_NULL
;
1509 switch (gdk_event
->button
)
1511 case 1: event_type
= wxEVT_LEFT_UP
; break;
1512 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1513 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1514 default: return FALSE
;
1517 wxMouseEvent
event( event_type
);
1518 InitMouseEvent( win
, event
, gdk_event
);
1520 AdjustEventButtonState(event
);
1522 // same wxListBox hack as above
1523 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1525 if ( !g_captureWindow
)
1526 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1528 if (win
->GetEventHandler()->ProcessEvent( event
))
1530 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1537 //-----------------------------------------------------------------------------
1538 // "motion_notify_event"
1539 //-----------------------------------------------------------------------------
1541 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1542 GdkEventMotion
*gdk_event
,
1548 wxapp_install_idle_handler();
1550 if (!win
->m_hasVMT
) return FALSE
;
1551 if (g_blockEventsOnDrag
) return FALSE
;
1552 if (g_blockEventsOnScroll
) return FALSE
;
1554 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1556 if (gdk_event
->is_hint
)
1560 GdkModifierType state
;
1561 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1567 printf( "OnMotion from " );
1568 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1569 printf( win->GetClassInfo()->GetClassName() );
1573 wxMouseEvent
event( wxEVT_MOTION
);
1574 InitMouseEvent(win
, event
, gdk_event
);
1576 if ( g_captureWindow
)
1578 // synthetize a mouse enter or leave event if needed
1579 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1580 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1581 if ( hasMouse
!= g_captureWindowHasMouse
)
1583 // the mouse changed window
1584 g_captureWindowHasMouse
= hasMouse
;
1586 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1587 : wxEVT_LEAVE_WINDOW
);
1588 InitMouseEvent(win
, event
, gdk_event
);
1589 event
.SetEventObject(win
);
1590 win
->GetEventHandler()->ProcessEvent(event
);
1595 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1598 if (win
->GetEventHandler()->ProcessEvent( event
))
1600 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1607 //-----------------------------------------------------------------------------
1609 //-----------------------------------------------------------------------------
1611 // send the wxChildFocusEvent and wxFocusEvent, common code of
1612 // gtk_window_focus_in_callback() and SetFocus()
1613 static bool DoSendFocusEvents(wxWindow
*win
)
1615 // Notify the parent keeping track of focus for the kbd navigation
1616 // purposes that we got it.
1617 wxChildFocusEvent
eventChildFocus(win
);
1618 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1620 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1621 eventFocus
.SetEventObject(win
);
1623 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1626 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1627 GdkEvent
*WXUNUSED(event
),
1633 wxapp_install_idle_handler();
1635 if (!win
->m_hasVMT
) return FALSE
;
1636 if (g_blockEventsOnDrag
) return FALSE
;
1638 switch ( g_sendActivateEvent
)
1641 // we've got focus from outside, synthetize wxActivateEvent
1642 g_sendActivateEvent
= 1;
1646 // another our window just lost focus, it was already ours before
1647 // - don't send any wxActivateEvent
1648 g_sendActivateEvent
= -1;
1653 g_focusWindow
= win
;
1655 wxLogTrace(TRACE_FOCUS
,
1656 _T("%s: focus in"), win
->GetName().c_str());
1660 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1664 // caret needs to be informed about focus change
1665 wxCaret
*caret
= win
->GetCaret();
1668 caret
->OnSetFocus();
1670 #endif // wxUSE_CARET
1672 g_activeFrameLostFocus
= FALSE
;
1674 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1675 if ( active
!= g_activeFrame
)
1677 if ( g_activeFrame
)
1679 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1680 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1681 event
.SetEventObject(g_activeFrame
);
1682 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1685 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1686 g_activeFrame
= active
;
1687 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1688 event
.SetEventObject(g_activeFrame
);
1689 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1691 // Don't send focus events in addition to activate
1692 // if (win == g_activeFrame)
1696 // does the window itself think that it has the focus?
1697 if ( !win
->m_hasFocus
)
1699 // not yet, notify it
1700 win
->m_hasFocus
= TRUE
;
1702 if ( DoSendFocusEvents(win
) )
1704 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1712 //-----------------------------------------------------------------------------
1713 // "focus_out_event"
1714 //-----------------------------------------------------------------------------
1716 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1721 wxapp_install_idle_handler();
1723 if (!win
->m_hasVMT
) return FALSE
;
1724 if (g_blockEventsOnDrag
) return FALSE
;
1726 wxLogTrace( TRACE_FOCUS
,
1727 _T("%s: focus out"), win
->GetName().c_str() );
1729 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1731 // VZ: commenting this out because it does happen (although not easy
1732 // to reproduce, I only see it when using wxMiniFrame and not
1733 // always) and makes using Mahogany quite annoying
1735 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1736 wxT("unfocusing window that hasn't gained focus properly") );
1739 g_activeFrameLostFocus
= TRUE
;
1742 // if the focus goes out of our app alltogether, OnIdle() will send
1743 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1744 // g_sendActivateEvent to -1
1745 g_sendActivateEvent
= 0;
1747 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1751 g_focusWindow
= (wxWindowGTK
*)NULL
;
1759 // caret needs to be informed about focus change
1760 wxCaret
*caret
= win
->GetCaret();
1763 caret
->OnKillFocus();
1765 #endif // wxUSE_CARET
1767 // don't send the window a kill focus event if it thinks that it doesn't
1768 // have focus already
1769 if ( win
->m_hasFocus
)
1771 win
->m_hasFocus
= FALSE
;
1773 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1774 event
.SetEventObject( win
);
1776 if (win
->GetEventHandler()->ProcessEvent( event
))
1778 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1786 //-----------------------------------------------------------------------------
1787 // "enter_notify_event"
1788 //-----------------------------------------------------------------------------
1791 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1792 GdkEventCrossing
*gdk_event
,
1798 wxapp_install_idle_handler();
1800 if (!win
->m_hasVMT
) return FALSE
;
1801 if (g_blockEventsOnDrag
) return FALSE
;
1803 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1807 GdkModifierType state
= (GdkModifierType
)0;
1809 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1811 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1812 InitMouseEvent(win
, event
, gdk_event
);
1813 wxPoint pt
= win
->GetClientAreaOrigin();
1814 event
.m_x
= x
+ pt
.x
;
1815 event
.m_y
= y
+ pt
.y
;
1817 if (win
->GetEventHandler()->ProcessEvent( event
))
1819 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1826 //-----------------------------------------------------------------------------
1827 // "leave_notify_event"
1828 //-----------------------------------------------------------------------------
1830 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1835 wxapp_install_idle_handler();
1837 if (!win
->m_hasVMT
) return FALSE
;
1838 if (g_blockEventsOnDrag
) return FALSE
;
1840 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1842 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1843 event
.SetTimestamp( gdk_event
->time
);
1844 event
.SetEventObject( win
);
1848 GdkModifierType state
= (GdkModifierType
)0;
1850 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1852 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1853 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1854 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1855 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1856 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1857 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1858 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1860 wxPoint pt
= win
->GetClientAreaOrigin();
1861 event
.m_x
= x
+ pt
.x
;
1862 event
.m_y
= y
+ pt
.y
;
1864 if (win
->GetEventHandler()->ProcessEvent( event
))
1866 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1873 //-----------------------------------------------------------------------------
1874 // "value_changed" from m_vAdjust
1875 //-----------------------------------------------------------------------------
1877 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1884 wxapp_install_idle_handler();
1886 if (g_blockEventsOnDrag
) return;
1888 if (!win
->m_hasVMT
) return;
1890 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1891 if (fabs(diff
) < 0.2) return;
1893 win
->m_oldVerticalPos
= adjust
->value
;
1895 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1896 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
1898 int value
= (int)(adjust
->value
+0.5);
1900 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1901 event
.SetEventObject( win
);
1902 win
->GetEventHandler()->ProcessEvent( event
);
1905 //-----------------------------------------------------------------------------
1906 // "value_changed" from m_hAdjust
1907 //-----------------------------------------------------------------------------
1909 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1916 wxapp_install_idle_handler();
1918 if (g_blockEventsOnDrag
) return;
1919 if (!win
->m_hasVMT
) return;
1921 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1922 if (fabs(diff
) < 0.2) return;
1924 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1925 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
1927 win
->m_oldHorizontalPos
= adjust
->value
;
1929 int value
= (int)(adjust
->value
+0.5);
1931 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1932 event
.SetEventObject( win
);
1933 win
->GetEventHandler()->ProcessEvent( event
);
1936 //-----------------------------------------------------------------------------
1937 // "button_press_event" from scrollbar
1938 //-----------------------------------------------------------------------------
1940 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1941 GdkEventButton
*gdk_event
,
1947 wxapp_install_idle_handler();
1950 g_blockEventsOnScroll
= TRUE
;
1952 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1954 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1960 //-----------------------------------------------------------------------------
1961 // "button_release_event" from scrollbar
1962 //-----------------------------------------------------------------------------
1964 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1965 GdkEventButton
*WXUNUSED(gdk_event
),
1970 // don't test here as we can release the mouse while being over
1971 // a different window than the slider
1973 // if (gdk_event->window != widget->slider) return FALSE;
1975 g_blockEventsOnScroll
= FALSE
;
1977 if (win
->m_isScrolling
)
1979 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1983 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1984 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1986 value
= (int)(win
->m_hAdjust
->value
+0.5);
1989 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
1991 value
= (int)(win
->m_vAdjust
->value
+0.5);
1995 wxScrollWinEvent
event( command
, value
, dir
);
1996 event
.SetEventObject( win
);
1997 win
->GetEventHandler()->ProcessEvent( event
);
2000 win
->m_isScrolling
= FALSE
;
2005 // ----------------------------------------------------------------------------
2006 // this wxWindowBase function is implemented here (in platform-specific file)
2007 // because it is static and so couldn't be made virtual
2008 // ----------------------------------------------------------------------------
2010 wxWindow
*wxWindowBase::FindFocus()
2012 // the cast is necessary when we compile in wxUniversal mode
2013 return (wxWindow
*)g_focusWindow
;
2016 //-----------------------------------------------------------------------------
2018 //-----------------------------------------------------------------------------
2020 // VZ: Robert commented the code using out so it generates warnings: should
2021 // be either fixed or removed completely
2024 static void gtk_window_destroy_callback( GtkWidget
* widget
, wxWindow
*win
)
2026 wxWindowDestroyEvent
event(win
);
2027 win
->GetEventHandler()->ProcessEvent(event
);
2032 //-----------------------------------------------------------------------------
2033 // "realize" from m_widget
2034 //-----------------------------------------------------------------------------
2036 /* We cannot set colours and fonts before the widget has
2037 been realized, so we do this directly after realization. */
2040 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2045 wxapp_install_idle_handler();
2047 if (win
->m_delayedBackgroundColour
)
2048 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2050 if (win
->m_delayedForegroundColour
)
2051 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2053 wxWindowCreateEvent
event( win
);
2054 event
.SetEventObject( win
);
2055 win
->GetEventHandler()->ProcessEvent( event
);
2060 //-----------------------------------------------------------------------------
2062 //-----------------------------------------------------------------------------
2065 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2066 GtkAllocation
*WXUNUSED(alloc
),
2070 wxapp_install_idle_handler();
2072 if (!win
->m_hasScrolling
) return;
2074 int client_width
= 0;
2075 int client_height
= 0;
2076 win
->GetClientSize( &client_width
, &client_height
);
2077 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2080 win
->m_oldClientWidth
= client_width
;
2081 win
->m_oldClientHeight
= client_height
;
2083 if (!win
->m_nativeSizeEvent
)
2085 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2086 event
.SetEventObject( win
);
2087 win
->GetEventHandler()->ProcessEvent( event
);
2093 #define WXUNUSED_UNLESS_XIM(param) param
2095 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2098 /* Resize XIM window */
2101 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2102 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2103 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2106 wxapp_install_idle_handler();
2112 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2116 gdk_window_get_size (widget
->window
, &width
, &height
);
2117 win
->m_icattr
->preedit_area
.width
= width
;
2118 win
->m_icattr
->preedit_area
.height
= height
;
2119 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2124 //-----------------------------------------------------------------------------
2125 // "realize" from m_wxwindow
2126 //-----------------------------------------------------------------------------
2128 /* Initialize XIM support */
2131 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2132 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2135 wxapp_install_idle_handler();
2138 if (win
->m_ic
) return FALSE
;
2139 if (!widget
) return FALSE
;
2140 if (!gdk_im_ready()) return FALSE
;
2142 win
->m_icattr
= gdk_ic_attr_new();
2143 if (!win
->m_icattr
) return FALSE
;
2147 GdkColormap
*colormap
;
2148 GdkICAttr
*attr
= win
->m_icattr
;
2149 unsigned attrmask
= GDK_IC_ALL_REQ
;
2151 GdkIMStyle supported_style
= (GdkIMStyle
)
2152 (GDK_IM_PREEDIT_NONE
|
2153 GDK_IM_PREEDIT_NOTHING
|
2154 GDK_IM_PREEDIT_POSITION
|
2155 GDK_IM_STATUS_NONE
|
2156 GDK_IM_STATUS_NOTHING
);
2158 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2159 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2161 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2162 attr
->client_window
= widget
->window
;
2164 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2165 gtk_widget_get_default_colormap ())
2167 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2168 attr
->preedit_colormap
= colormap
;
2171 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2172 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2173 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2174 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2176 switch (style
& GDK_IM_PREEDIT_MASK
)
2178 case GDK_IM_PREEDIT_POSITION
:
2179 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2181 g_warning ("over-the-spot style requires fontset");
2185 gdk_window_get_size (widget
->window
, &width
, &height
);
2187 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2188 attr
->spot_location
.x
= 0;
2189 attr
->spot_location
.y
= height
;
2190 attr
->preedit_area
.x
= 0;
2191 attr
->preedit_area
.y
= 0;
2192 attr
->preedit_area
.width
= width
;
2193 attr
->preedit_area
.height
= height
;
2194 attr
->preedit_fontset
= widget
->style
->font
;
2199 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2201 if (win
->m_ic
== NULL
)
2202 g_warning ("Can't create input context.");
2205 mask
= gdk_window_get_events (widget
->window
);
2206 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2207 gdk_window_set_events (widget
->window
, mask
);
2209 if (GTK_WIDGET_HAS_FOCUS(widget
))
2210 gdk_im_begin (win
->m_ic
, widget
->window
);
2217 //-----------------------------------------------------------------------------
2218 // InsertChild for wxWindowGTK.
2219 //-----------------------------------------------------------------------------
2221 /* Callback for wxWindowGTK. This very strange beast has to be used because
2222 * C++ has no virtual methods in a constructor. We have to emulate a
2223 * virtual function here as wxNotebook requires a different way to insert
2224 * a child in it. I had opted for creating a wxNotebookPage window class
2225 * which would have made this superfluous (such in the MDI window system),
2226 * but no-one was listening to me... */
2228 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2230 /* the window might have been scrolled already, do we
2231 have to adapt the position */
2232 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2233 child
->m_x
+= pizza
->xoffset
;
2234 child
->m_y
+= pizza
->yoffset
;
2236 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2237 GTK_WIDGET(child
->m_widget
),
2244 //-----------------------------------------------------------------------------
2246 //-----------------------------------------------------------------------------
2248 wxWindow
*wxGetActiveWindow()
2250 return wxWindow::FindFocus();
2253 //-----------------------------------------------------------------------------
2255 //-----------------------------------------------------------------------------
2257 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2259 #ifdef __WXUNIVERSAL__
2260 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2262 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2263 #endif // __WXUNIVERSAL__/__WXGTK__
2265 void wxWindowGTK::Init()
2271 m_widget
= (GtkWidget
*) NULL
;
2272 m_wxwindow
= (GtkWidget
*) NULL
;
2273 m_focusWidget
= (GtkWidget
*) NULL
;
2283 m_needParent
= TRUE
;
2284 m_isBeingDeleted
= FALSE
;
2287 m_nativeSizeEvent
= FALSE
;
2289 m_hasScrolling
= FALSE
;
2290 m_isScrolling
= FALSE
;
2292 m_hAdjust
= (GtkAdjustment
*) NULL
;
2293 m_vAdjust
= (GtkAdjustment
*) NULL
;
2294 m_oldHorizontalPos
= 0.0;
2295 m_oldVerticalPos
= 0.0;
2298 m_widgetStyle
= (GtkStyle
*) NULL
;
2300 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2302 m_acceptsFocus
= FALSE
;
2305 m_clipPaintRegion
= FALSE
;
2307 m_cursor
= *wxSTANDARD_CURSOR
;
2309 m_delayedForegroundColour
= FALSE
;
2310 m_delayedBackgroundColour
= FALSE
;
2313 m_ic
= (GdkIC
*) NULL
;
2314 m_icattr
= (GdkICAttr
*) NULL
;
2318 wxWindowGTK::wxWindowGTK()
2323 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2328 const wxString
&name
)
2332 Create( parent
, id
, pos
, size
, style
, name
);
2335 bool wxWindowGTK::Create( wxWindow
*parent
,
2340 const wxString
&name
)
2342 if (!PreCreation( parent
, pos
, size
) ||
2343 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2345 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2349 m_insertCallback
= wxInsertChildInWindow
;
2351 // always needed for background clearing
2352 m_delayedBackgroundColour
= TRUE
;
2354 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2355 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2357 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2359 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2360 scroll_class
->scrollbar_spacing
= 0;
2362 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2364 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2365 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2367 m_wxwindow
= gtk_pizza_new();
2369 #ifndef __WXUNIVERSAL__
2370 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2372 if (HasFlag(wxRAISED_BORDER
))
2374 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2376 else if (HasFlag(wxSUNKEN_BORDER
))
2378 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2380 else if (HasFlag(wxSIMPLE_BORDER
))
2382 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2386 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2388 #endif // __WXUNIVERSAL__
2390 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2392 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2393 m_acceptsFocus
= TRUE
;
2395 // I _really_ don't want scrollbars in the beginning
2396 m_vAdjust
->lower
= 0.0;
2397 m_vAdjust
->upper
= 1.0;
2398 m_vAdjust
->value
= 0.0;
2399 m_vAdjust
->step_increment
= 1.0;
2400 m_vAdjust
->page_increment
= 1.0;
2401 m_vAdjust
->page_size
= 5.0;
2402 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2403 m_hAdjust
->lower
= 0.0;
2404 m_hAdjust
->upper
= 1.0;
2405 m_hAdjust
->value
= 0.0;
2406 m_hAdjust
->step_increment
= 1.0;
2407 m_hAdjust
->page_increment
= 1.0;
2408 m_hAdjust
->page_size
= 5.0;
2409 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2411 // these handlers block mouse events to any window during scrolling such as
2412 // motion events and prevent GTK and wxWindows from fighting over where the
2415 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2416 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2418 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2419 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2421 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2422 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2424 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2425 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2427 // these handlers get notified when screen updates are required either when
2428 // scrolling or when the window size (and therefore scrollbar configuration)
2431 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2432 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2433 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2434 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2436 gtk_widget_show( m_wxwindow
);
2439 m_parent
->DoAddChild( this );
2441 m_focusWidget
= m_wxwindow
;
2450 wxWindowGTK::~wxWindowGTK()
2452 if (g_focusWindow
== this)
2453 g_focusWindow
= NULL
;
2455 if (g_activeFrame
== this)
2456 g_activeFrame
= NULL
;
2458 if ( g_delayedFocus
== this )
2459 g_delayedFocus
= NULL
;
2461 m_isBeingDeleted
= TRUE
;
2470 m_parent
->RemoveChild( this );
2474 gdk_ic_destroy (m_ic
);
2476 gdk_ic_attr_destroy (m_icattr
);
2481 #if DISABLE_STYLE_IF_BROKEN_THEME
2482 // don't delete if it's a pixmap theme style
2483 if (!m_widgetStyle
->engine_data
)
2484 gtk_style_unref( m_widgetStyle
);
2486 m_widgetStyle
= (GtkStyle
*) NULL
;
2491 gtk_widget_destroy( m_wxwindow
);
2492 m_wxwindow
= (GtkWidget
*) NULL
;
2497 gtk_widget_destroy( m_widget
);
2498 m_widget
= (GtkWidget
*) NULL
;
2502 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2504 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2506 // This turns -1 into 30 so that a minimal window is
2507 // visible even although -1,-1 has been given as the
2508 // size of the window. the same trick is used in other
2509 // ports and should make debugging easier.
2510 m_width
= WidthDefault(size
.x
) ;
2511 m_height
= HeightDefault(size
.y
);
2516 // some reasonable defaults
2521 m_x
= (gdk_screen_width () - m_width
) / 2;
2522 if (m_x
< 10) m_x
= 10;
2526 m_y
= (gdk_screen_height () - m_height
) / 2;
2527 if (m_y
< 10) m_y
= 10;
2534 void wxWindowGTK::PostCreation()
2536 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2542 // these get reported to wxWindows -> wxPaintEvent
2544 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2546 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2547 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2550 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2551 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2553 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2555 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2556 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2559 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2563 // these are called when the "sunken" or "raised" borders are drawn
2564 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2565 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2568 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2569 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2575 if (m_focusWidget
== NULL
)
2576 m_focusWidget
= m_widget
;
2578 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2579 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2581 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2582 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2584 // connect to the various key and mouse handlers
2586 GtkWidget
*connect_widget
= GetConnectWidget();
2588 ConnectWidget( connect_widget
);
2590 /* We cannot set colours, fonts and cursors before the widget has
2591 been realized, so we do this directly after realization */
2592 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2593 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2597 // Catch native resize events
2598 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2599 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2601 // Initialize XIM support
2602 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2603 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2605 // And resize XIM window
2606 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2607 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2610 if (!GTK_IS_COMBO(m_widget
))
2612 // This is needed if we want to add our windows into native
2613 // GTK control, such as the toolbar. With this callback, the
2614 // toolbar gets to know the correct size (the one set by the
2615 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2616 // when moving to GTK 2.0.
2617 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2618 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2624 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2626 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2627 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2629 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2630 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2632 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2633 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2635 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2636 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2638 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2639 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2641 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2642 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2644 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2645 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2647 // This keeps crashing on me. RR.
2649 // gtk_signal_connect( GTK_OBJECT(widget), "destroy",
2650 // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this );
2653 bool wxWindowGTK::Destroy()
2655 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2659 return wxWindowBase::Destroy();
2662 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2664 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2667 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2669 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2670 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2673 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2676 if (m_resizing
) return; /* I don't like recursions */
2679 int currentX
, currentY
;
2680 GetPosition(¤tX
, ¤tY
);
2685 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2687 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2689 /* don't set the size for children of wxNotebook, just take the values. */
2697 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2698 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2700 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2701 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2702 if (width
!= -1) m_width
= width
;
2703 if (height
!= -1) m_height
= height
;
2707 m_x
= x
+ pizza
->xoffset
;
2708 m_y
= y
+ pizza
->yoffset
;
2713 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2715 if (width
== -1) m_width
= 80;
2718 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2720 if (height
== -1) m_height
= 26;
2723 int minWidth
= GetMinWidth(),
2724 minHeight
= GetMinHeight(),
2725 maxWidth
= GetMaxWidth(),
2726 maxHeight
= GetMaxHeight();
2728 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2729 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2730 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2731 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2734 int bottom_border
= 0;
2737 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2739 /* the default button has a border around it */
2745 DoMoveWindow( m_x
-border
,
2748 m_height
+border
+bottom_border
);
2753 /* Sometimes the client area changes size without the
2754 whole windows's size changing, but if the whole
2755 windows's size doesn't change, no wxSizeEvent will
2756 normally be sent. Here we add an extra test if
2757 the client test has been changed and this will
2759 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2763 wxPrintf( "OnSize sent from " );
2764 if (GetClassInfo() && GetClassInfo()->GetClassName())
2765 wxPrintf( GetClassInfo()->GetClassName() );
2766 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2769 if (!m_nativeSizeEvent
)
2771 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2772 event
.SetEventObject( this );
2773 GetEventHandler()->ProcessEvent( event
);
2779 void wxWindowGTK::OnInternalIdle()
2781 // Update invalidated regions.
2784 // Synthetize activate events.
2785 if ( g_sendActivateEvent
!= -1 )
2787 bool activate
= g_sendActivateEvent
!= 0;
2790 g_sendActivateEvent
= -1;
2792 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2795 if ( g_activeFrameLostFocus
)
2797 if ( g_activeFrame
)
2799 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2800 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2801 event
.SetEventObject(g_activeFrame
);
2802 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2803 g_activeFrame
= NULL
;
2805 g_activeFrameLostFocus
= FALSE
;
2808 wxCursor cursor
= m_cursor
;
2809 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2813 /* I now set the cursor anew in every OnInternalIdle call
2814 as setting the cursor in a parent window also effects the
2815 windows above so that checking for the current cursor is
2820 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2822 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2824 if (!g_globalCursor
.Ok())
2825 cursor
= *wxSTANDARD_CURSOR
;
2827 window
= m_widget
->window
;
2828 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2829 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2835 GdkWindow
*window
= m_widget
->window
;
2836 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2837 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2845 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2847 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2849 if (width
) (*width
) = m_width
;
2850 if (height
) (*height
) = m_height
;
2853 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2855 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2859 SetSize( width
, height
);
2866 #ifndef __WXUNIVERSAL__
2867 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2869 /* when using GTK 1.2 we set the shadow border size to 2 */
2873 if (HasFlag(wxSIMPLE_BORDER
))
2875 /* when using GTK 1.2 we set the simple border size to 1 */
2879 #endif // __WXUNIVERSAL__
2883 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2885 GtkRequisition vscroll_req
;
2886 vscroll_req
.width
= 2;
2887 vscroll_req
.height
= 2;
2888 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2889 (scroll_window
->vscrollbar
, &vscroll_req
);
2891 GtkRequisition hscroll_req
;
2892 hscroll_req
.width
= 2;
2893 hscroll_req
.height
= 2;
2894 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2895 (scroll_window
->hscrollbar
, &hscroll_req
);
2897 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2899 if (scroll_window
->vscrollbar_visible
)
2901 dw
+= vscroll_req
.width
;
2902 dw
+= scroll_class
->scrollbar_spacing
;
2905 if (scroll_window
->hscrollbar_visible
)
2907 dh
+= hscroll_req
.height
;
2908 dh
+= scroll_class
->scrollbar_spacing
;
2912 SetSize( width
+dw
, height
+dh
);
2916 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2918 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2922 if (width
) (*width
) = m_width
;
2923 if (height
) (*height
) = m_height
;
2930 #ifndef __WXUNIVERSAL__
2931 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2933 /* when using GTK 1.2 we set the shadow border size to 2 */
2937 if (HasFlag(wxSIMPLE_BORDER
))
2939 /* when using GTK 1.2 we set the simple border size to 1 */
2943 #endif // __WXUNIVERSAL__
2947 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2949 GtkRequisition vscroll_req
;
2950 vscroll_req
.width
= 2;
2951 vscroll_req
.height
= 2;
2952 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2953 (scroll_window
->vscrollbar
, &vscroll_req
);
2955 GtkRequisition hscroll_req
;
2956 hscroll_req
.width
= 2;
2957 hscroll_req
.height
= 2;
2958 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2959 (scroll_window
->hscrollbar
, &hscroll_req
);
2961 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2963 if (scroll_window
->vscrollbar_visible
)
2965 dw
+= vscroll_req
.width
;
2966 dw
+= scroll_class
->scrollbar_spacing
;
2969 if (scroll_window
->hscrollbar_visible
)
2971 dh
+= hscroll_req
.height
;
2972 dh
+= scroll_class
->scrollbar_spacing
;
2976 if (width
) (*width
) = m_width
- dw
;
2977 if (height
) (*height
) = m_height
- dh
;
2981 printf( "GetClientSize, name %s ", GetName().c_str() );
2982 if (width) printf( " width = %d", (*width) );
2983 if (height) printf( " height = %d", (*height) );
2988 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2990 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2994 if (m_parent
&& m_parent
->m_wxwindow
)
2996 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2997 dx
= pizza
->xoffset
;
2998 dy
= pizza
->yoffset
;
3001 if (x
) (*x
) = m_x
- dx
;
3002 if (y
) (*y
) = m_y
- dy
;
3005 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3007 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3009 if (!m_widget
->window
) return;
3011 GdkWindow
*source
= (GdkWindow
*) NULL
;
3013 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3015 source
= m_widget
->window
;
3019 gdk_window_get_origin( source
, &org_x
, &org_y
);
3023 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3025 org_x
+= m_widget
->allocation
.x
;
3026 org_y
+= m_widget
->allocation
.y
;
3034 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3036 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3038 if (!m_widget
->window
) return;
3040 GdkWindow
*source
= (GdkWindow
*) NULL
;
3042 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3044 source
= m_widget
->window
;
3048 gdk_window_get_origin( source
, &org_x
, &org_y
);
3052 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3054 org_x
+= m_widget
->allocation
.x
;
3055 org_y
+= m_widget
->allocation
.y
;
3063 bool wxWindowGTK::Show( bool show
)
3065 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3067 if (!wxWindowBase::Show(show
))
3074 gtk_widget_show( m_widget
);
3076 gtk_widget_hide( m_widget
);
3081 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3083 win
->OnParentEnable(enable
);
3085 // Recurse, so that children have the opportunity to Do The Right Thing
3086 // and reset colours that have been messed up by a parent's (really ancestor's)
3088 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3090 node
= node
->GetNext() )
3092 wxWindow
*child
= node
->GetData();
3093 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3094 wxWindowNotifyEnable(child
, enable
);
3098 bool wxWindowGTK::Enable( bool enable
)
3100 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3102 if (!wxWindowBase::Enable(enable
))
3108 gtk_widget_set_sensitive( m_widget
, enable
);
3110 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3112 wxWindowNotifyEnable(this, enable
);
3117 int wxWindowGTK::GetCharHeight() const
3119 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3121 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3123 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3125 return font
->ascent
+ font
->descent
;
3128 int wxWindowGTK::GetCharWidth() const
3130 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3132 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3134 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3136 return gdk_string_width( font
, "H" );
3139 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3143 int *externalLeading
,
3144 const wxFont
*theFont
) const
3146 wxFont fontToUse
= m_font
;
3147 if (theFont
) fontToUse
= *theFont
;
3149 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3151 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3152 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3153 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3154 if (descent
) (*descent
) = font
->descent
;
3155 if (externalLeading
) (*externalLeading
) = 0; // ??
3158 void wxWindowGTK::SetFocus()
3160 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3164 // don't do anything if we already have focus
3170 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3172 gtk_widget_grab_focus (m_wxwindow
);
3177 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3179 if (!GTK_WIDGET_REALIZED(m_widget
))
3181 // we can't set the focus to the widget now so we remember that
3182 // it should be focused and will do it later, during the idle
3183 // time, as soon as we can
3184 wxLogTrace(TRACE_FOCUS
,
3185 _T("Delaying setting focus to %s(%s)"),
3186 GetClassInfo()->GetClassName(), GetLabel().c_str());
3188 g_delayedFocus
= this;
3192 wxLogTrace(TRACE_FOCUS
,
3193 _T("Setting focus to %s(%s)"),
3194 GetClassInfo()->GetClassName(), GetLabel().c_str());
3196 gtk_widget_grab_focus (m_widget
);
3199 else if (GTK_IS_CONTAINER(m_widget
))
3201 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3205 wxLogTrace(TRACE_FOCUS
,
3206 _T("Can't set focus to %s(%s)"),
3207 GetClassInfo()->GetClassName(), GetLabel().c_str());
3212 bool wxWindowGTK::AcceptsFocus() const
3214 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3217 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3219 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3221 wxWindowGTK
*oldParent
= m_parent
,
3222 *newParent
= (wxWindowGTK
*)newParentBase
;
3224 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3226 if ( !wxWindowBase::Reparent(newParent
) )
3229 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3231 /* prevent GTK from deleting the widget arbitrarily */
3232 gtk_widget_ref( m_widget
);
3236 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3239 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3243 /* insert GTK representation */
3244 (*(newParent
->m_insertCallback
))(newParent
, this);
3247 /* reverse: prevent GTK from deleting the widget arbitrarily */
3248 gtk_widget_unref( m_widget
);
3253 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3255 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3257 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3259 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3264 /* insert GTK representation */
3265 (*m_insertCallback
)(this, child
);
3268 void wxWindowGTK::Raise()
3270 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3272 if (!m_widget
->window
) return;
3274 gdk_window_raise( m_widget
->window
);
3277 void wxWindowGTK::Lower()
3279 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3281 if (!m_widget
->window
) return;
3283 gdk_window_lower( m_widget
->window
);
3286 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3288 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3290 if (cursor
== m_cursor
)
3294 wxapp_install_idle_handler();
3296 if (cursor
== wxNullCursor
)
3297 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3299 return wxWindowBase::SetCursor( cursor
);
3302 void wxWindowGTK::WarpPointer( int x
, int y
)
3304 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3306 // We provide this function ourselves as it is
3307 // missing in GDK (top of this file).
3309 GdkWindow
*window
= (GdkWindow
*) NULL
;
3311 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3313 window
= GetConnectWidget()->window
;
3316 gdk_window_warp_pointer( window
, x
, y
);
3320 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3322 if (!m_widget
) return;
3323 if (!m_widget
->window
) return;
3327 wxapp_install_idle_handler();
3329 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3333 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3334 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3338 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3339 m_clearRegion
.Clear();
3340 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3348 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3349 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3353 GdkRectangle gdk_rect
;
3354 gdk_rect
.x
= rect
->x
;
3355 gdk_rect
.y
= rect
->y
;
3356 gdk_rect
.width
= rect
->width
;
3357 gdk_rect
.height
= rect
->height
;
3358 gtk_widget_draw( m_widget
, &gdk_rect
);
3365 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3366 m_updateRegion
.Clear();
3367 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3371 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3379 GdkRectangle gdk_rect
;
3380 gdk_rect
.x
= rect
->x
;
3381 gdk_rect
.y
= rect
->y
;
3382 gdk_rect
.width
= rect
->width
;
3383 gdk_rect
.height
= rect
->height
;
3384 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3388 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3394 void wxWindowGTK::Update()
3399 void wxWindowGTK::GtkUpdate()
3402 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3403 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3406 if (!m_updateRegion
.IsEmpty())
3407 GtkSendPaintEvents();
3410 void wxWindowGTK::GtkSendPaintEvents()
3414 m_clearRegion
.Clear();
3415 m_updateRegion
.Clear();
3419 // widget to draw on
3420 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3422 // Clip to paint region in wxClientDC
3423 m_clipPaintRegion
= TRUE
;
3425 if (GetThemeEnabled())
3427 // find ancestor from which to steal background
3428 wxWindow
*parent
= GetParent();
3429 while (parent
&& !parent
->IsTopLevel())
3430 parent
= parent
->GetParent();
3432 parent
= (wxWindow
*)this;
3434 wxRegionIterator
upd( m_updateRegion
);
3438 rect
.x
= upd
.GetX();
3439 rect
.y
= upd
.GetY();
3440 rect
.width
= upd
.GetWidth();
3441 rect
.height
= upd
.GetHeight();
3443 gtk_paint_flat_box( parent
->m_widget
->style
,
3456 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3458 // If the clear region is empty, and the update region isn't,
3459 // then we're going to clear more than we repaint,
3460 // so let's make sure the two regions are in sync.
3461 if (m_clearRegion
.IsEmpty() && !m_updateRegion
.IsEmpty())
3463 m_clearRegion
= m_updateRegion
;
3466 wxWindowDC
dc( (wxWindow
*)this );
3467 dc
.SetClippingRegion( m_clearRegion
);
3469 wxEraseEvent
erase_event( GetId(), &dc
);
3470 erase_event
.SetEventObject( this );
3472 if (!GetEventHandler()->ProcessEvent(erase_event
))
3476 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3477 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3479 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3481 wxRegionIterator
upd( m_clearRegion
);
3484 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3485 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3489 m_clearRegion
.Clear();
3492 wxNcPaintEvent
nc_paint_event( GetId() );
3493 nc_paint_event
.SetEventObject( this );
3494 GetEventHandler()->ProcessEvent( nc_paint_event
);
3496 wxPaintEvent
paint_event( GetId() );
3497 paint_event
.SetEventObject( this );
3498 GetEventHandler()->ProcessEvent( paint_event
);
3500 m_clipPaintRegion
= FALSE
;
3502 #ifndef __WXUNIVERSAL__
3504 // The following code will result in all window-less widgets
3505 // being redrawn because the wxWindows class is allowed to
3506 // paint over the window-less widgets.
3508 GList
*children
= pizza
->children
;
3511 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3512 children
= children
->next
;
3514 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3515 GTK_WIDGET_DRAWABLE (child
->widget
))
3517 // Get intersection of widget area and update region
3518 wxRegion
region( m_updateRegion
);
3520 GdkEventExpose gdk_event
;
3521 gdk_event
.type
= GDK_EXPOSE
;
3522 gdk_event
.window
= pizza
->bin_window
;
3523 gdk_event
.count
= 0;
3525 wxRegionIterator
upd( m_updateRegion
);
3529 rect
.x
= upd
.GetX();
3530 rect
.y
= upd
.GetY();
3531 rect
.width
= upd
.GetWidth();
3532 rect
.height
= upd
.GetHeight();
3534 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3536 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3546 m_updateRegion
.Clear();
3549 void wxWindowGTK::Clear()
3551 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3553 if (m_wxwindow
&& m_wxwindow
->window
)
3555 m_clearRegion
.Clear();
3556 wxSize
size( GetClientSize() );
3557 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3559 // Better do this in idle?
3565 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3567 wxWindowBase::DoSetToolTip(tip
);
3570 m_tooltip
->Apply( (wxWindow
*)this );
3573 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3575 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3577 #endif // wxUSE_TOOLTIPS
3579 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3581 GdkWindow
*window
= (GdkWindow
*) NULL
;
3583 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3585 window
= GetConnectWidget()->window
;
3589 // We need the pixel value e.g. for background clearing.
3590 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3594 // wxMSW doesn't clear the window here, either.
3595 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3601 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3603 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3605 if (!wxWindowBase::SetBackgroundColour(colour
))
3608 GdkWindow
*window
= (GdkWindow
*) NULL
;
3610 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3612 window
= GetConnectWidget()->window
;
3616 // indicate that a new style has been set
3617 // but it couldn't get applied as the
3618 // widget hasn't been realized yet.
3619 m_delayedBackgroundColour
= TRUE
;
3624 GtkSetBackgroundColour( colour
);
3630 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3632 GdkWindow
*window
= (GdkWindow
*) NULL
;
3634 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3636 window
= GetConnectWidget()->window
;
3643 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3645 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3647 if (!wxWindowBase::SetForegroundColour(colour
))
3649 // don't leave if the GTK widget has just
3651 if (!m_delayedForegroundColour
) return FALSE
;
3654 GdkWindow
*window
= (GdkWindow
*) NULL
;
3656 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3658 window
= GetConnectWidget()->window
;
3662 // indicate that a new style has been set
3663 // but it couldn't get applied as the
3664 // widget hasn't been realized yet.
3665 m_delayedForegroundColour
= TRUE
;
3669 GtkSetForegroundColour( colour
);
3675 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3679 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3681 // FIXME: no more klass in 2.0
3683 remake
->klass
= m_widgetStyle
->klass
;
3686 gtk_style_unref( m_widgetStyle
);
3687 m_widgetStyle
= remake
;
3691 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3694 def
= gtk_widget_get_default_style();
3696 m_widgetStyle
= gtk_style_copy( def
);
3698 // FIXME: no more klass in 2.0
3700 m_widgetStyle
->klass
= def
->klass
;
3704 return m_widgetStyle
;
3707 void wxWindowGTK::SetWidgetStyle()
3709 #if DISABLE_STYLE_IF_BROKEN_THEME
3710 if (m_widget
->style
->engine_data
)
3712 static bool s_warningPrinted
= FALSE
;
3713 if (!s_warningPrinted
)
3715 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3716 s_warningPrinted
= TRUE
;
3718 m_widgetStyle
= m_widget
->style
;
3723 GtkStyle
*style
= GetWidgetStyle();
3725 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3727 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3730 if (m_foregroundColour
.Ok())
3732 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3733 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3735 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3736 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3737 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3741 // Try to restore the gtk default style. This is still a little
3742 // oversimplified for what is probably really needed here for controls
3743 // other than buttons, but is better than not being able to (re)set a
3744 // control's foreground colour to *wxBLACK -- RL
3745 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3748 def
= gtk_widget_get_default_style();
3750 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3751 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3752 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3756 if (m_backgroundColour
.Ok())
3758 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3759 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3761 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3762 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3763 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3764 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3765 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3766 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3767 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3768 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3772 // Try to restore the gtk default style. This is still a little
3773 // oversimplified for what is probably really needed here for controls
3774 // other than buttons, but is better than not being able to (re)set a
3775 // control's background colour to default grey and means resetting a
3776 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3778 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3781 def
= gtk_widget_get_default_style();
3783 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3784 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3785 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3786 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3787 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3788 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3789 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3790 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3795 void wxWindowGTK::ApplyWidgetStyle()
3799 //-----------------------------------------------------------------------------
3800 // Pop-up menu stuff
3801 //-----------------------------------------------------------------------------
3803 #if wxUSE_MENUS_NATIVE
3806 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3808 *is_waiting
= FALSE
;
3811 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3813 menu
->SetInvokingWindow( win
);
3814 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3817 wxMenuItem
*menuitem
= node
->GetData();
3818 if (menuitem
->IsSubMenu())
3820 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3823 node
= node
->GetNext();
3827 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3828 // wxPopupMenuPositionCallback()
3830 // should be safe even in the MT case as the user can hardly popup 2 menus
3831 // simultaneously, can he?
3832 static gint gs_pop_x
= 0;
3833 static gint gs_pop_y
= 0;
3835 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3838 gboolean
* WXUNUSED(whatever
),
3840 gpointer
WXUNUSED(user_data
) )
3842 // ensure that the menu appears entirely on screen
3844 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3846 wxSize sizeScreen
= wxGetDisplaySize();
3848 gint xmax
= sizeScreen
.x
- req
.width
,
3849 ymax
= sizeScreen
.y
- req
.height
;
3851 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3852 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3855 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3857 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3859 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3861 SetInvokingWindow( menu
, this );
3867 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3869 bool is_waiting
= TRUE
;
3871 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3873 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3874 (gpointer
)&is_waiting
);
3877 GTK_MENU(menu
->m_menu
),
3878 (GtkWidget
*) NULL
, // parent menu shell
3879 (GtkWidget
*) NULL
, // parent menu item
3880 wxPopupMenuPositionCallback
, // function to position it
3881 NULL
, // client data
3882 0, // button used to activate it
3883 gs_timeLastClick
// the time of activation
3888 while (gtk_events_pending())
3889 gtk_main_iteration();
3895 #endif // wxUSE_MENUS_NATIVE
3897 #if wxUSE_DRAG_AND_DROP
3899 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3901 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3903 GtkWidget
*dnd_widget
= GetConnectWidget();
3905 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3907 if (m_dropTarget
) delete m_dropTarget
;
3908 m_dropTarget
= dropTarget
;
3910 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3913 #endif // wxUSE_DRAG_AND_DROP
3915 GtkWidget
* wxWindowGTK::GetConnectWidget()
3917 GtkWidget
*connect_widget
= m_widget
;
3918 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3920 return connect_widget
;
3923 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3926 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3928 return (window
== m_widget
->window
);
3931 bool wxWindowGTK::SetFont( const wxFont
&font
)
3933 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3935 if (!wxWindowBase::SetFont(font
))
3940 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3941 if ( sysbg
== m_backgroundColour
)
3943 m_backgroundColour
= wxNullColour
;
3945 m_backgroundColour
= sysbg
;
3955 void wxWindowGTK::DoCaptureMouse()
3957 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3959 GdkWindow
*window
= (GdkWindow
*) NULL
;
3961 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3963 window
= GetConnectWidget()->window
;
3965 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3967 wxCursor
* cursor
= & m_cursor
;
3969 cursor
= wxSTANDARD_CURSOR
;
3971 gdk_pointer_grab( window
, FALSE
,
3973 (GDK_BUTTON_PRESS_MASK
|
3974 GDK_BUTTON_RELEASE_MASK
|
3975 GDK_POINTER_MOTION_HINT_MASK
|
3976 GDK_POINTER_MOTION_MASK
),
3978 cursor
->GetCursor(),
3979 (guint32
)GDK_CURRENT_TIME
);
3980 g_captureWindow
= this;
3981 g_captureWindowHasMouse
= TRUE
;
3984 void wxWindowGTK::DoReleaseMouse()
3986 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3988 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3990 g_captureWindow
= (wxWindowGTK
*) NULL
;
3992 GdkWindow
*window
= (GdkWindow
*) NULL
;
3994 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3996 window
= GetConnectWidget()->window
;
4001 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4005 wxWindow
*wxWindowBase::GetCapture()
4007 return (wxWindow
*)g_captureWindow
;
4010 bool wxWindowGTK::IsRetained() const
4015 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4016 int range
, bool refresh
)
4018 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4020 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4022 m_hasScrolling
= TRUE
;
4024 if (orient
== wxHORIZONTAL
)
4026 float fpos
= (float)pos
;
4027 float frange
= (float)range
;
4028 float fthumb
= (float)thumbVisible
;
4029 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4030 if (fpos
< 0.0) fpos
= 0.0;
4032 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4033 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4035 SetScrollPos( orient
, pos
, refresh
);
4039 m_oldHorizontalPos
= fpos
;
4041 m_hAdjust
->lower
= 0.0;
4042 m_hAdjust
->upper
= frange
;
4043 m_hAdjust
->value
= fpos
;
4044 m_hAdjust
->step_increment
= 1.0;
4045 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4046 m_hAdjust
->page_size
= fthumb
;
4050 float fpos
= (float)pos
;
4051 float frange
= (float)range
;
4052 float fthumb
= (float)thumbVisible
;
4053 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4054 if (fpos
< 0.0) fpos
= 0.0;
4056 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4057 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4059 SetScrollPos( orient
, pos
, refresh
);
4063 m_oldVerticalPos
= fpos
;
4065 m_vAdjust
->lower
= 0.0;
4066 m_vAdjust
->upper
= frange
;
4067 m_vAdjust
->value
= fpos
;
4068 m_vAdjust
->step_increment
= 1.0;
4069 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4070 m_vAdjust
->page_size
= fthumb
;
4073 if (orient
== wxHORIZONTAL
)
4074 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4076 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4079 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4081 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4083 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4085 if (orient
== wxHORIZONTAL
)
4087 float fpos
= (float)pos
;
4088 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4089 if (fpos
< 0.0) fpos
= 0.0;
4090 m_oldHorizontalPos
= fpos
;
4092 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4093 m_hAdjust
->value
= fpos
;
4097 float fpos
= (float)pos
;
4098 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4099 if (fpos
< 0.0) fpos
= 0.0;
4100 m_oldVerticalPos
= fpos
;
4102 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4103 m_vAdjust
->value
= fpos
;
4106 if (m_wxwindow
->window
)
4108 if (orient
== wxHORIZONTAL
)
4110 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4111 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4113 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4115 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4116 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4120 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4121 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4123 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4125 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4126 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4131 int wxWindowGTK::GetScrollThumb( int orient
) const
4133 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4135 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4137 if (orient
== wxHORIZONTAL
)
4138 return (int)(m_hAdjust
->page_size
+0.5);
4140 return (int)(m_vAdjust
->page_size
+0.5);
4143 int wxWindowGTK::GetScrollPos( int orient
) const
4145 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4147 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4149 if (orient
== wxHORIZONTAL
)
4150 return (int)(m_hAdjust
->value
+0.5);
4152 return (int)(m_vAdjust
->value
+0.5);
4155 int wxWindowGTK::GetScrollRange( int orient
) const
4157 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4159 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4161 if (orient
== wxHORIZONTAL
)
4162 return (int)(m_hAdjust
->upper
+0.5);
4164 return (int)(m_vAdjust
->upper
+0.5);
4167 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4169 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4171 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4173 // No scrolling requested.
4174 if ((dx
== 0) && (dy
== 0)) return;
4177 if (!m_updateRegion
.IsEmpty())
4179 m_updateRegion
.Offset( dx
, dy
);
4183 GetClientSize( &cw
, &ch
);
4184 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4187 if (!m_clearRegion
.IsEmpty())
4189 m_clearRegion
.Offset( dx
, dy
);
4193 GetClientSize( &cw
, &ch
);
4194 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4196 m_clipPaintRegion
= TRUE
;
4198 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4200 m_clipPaintRegion
= FALSE
;
4203 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4205 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4206 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4213 // Find the wxWindow at the current mouse position, also returning the mouse
4215 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4217 pt
= wxGetMousePosition();
4218 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4222 // Get the current mouse position.
4223 wxPoint
wxGetMousePosition()
4225 /* This crashes when used within wxHelpContext,
4226 so we have to use the X-specific implementation below.
4228 GdkModifierType *mask;
4229 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4231 return wxPoint(x, y);
4235 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4237 return wxPoint(-999, -999);
4239 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4240 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4241 Window rootReturn
, childReturn
;
4242 int rootX
, rootY
, winX
, winY
;
4243 unsigned int maskReturn
;
4245 XQueryPointer (display
,
4249 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4250 return wxPoint(rootX
, rootY
);
4254 // ----------------------------------------------------------------------------
4256 // ----------------------------------------------------------------------------
4258 class wxWinModule
: public wxModule
4265 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4268 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4270 bool wxWinModule::OnInit()
4272 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4273 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4278 void wxWinModule::OnExit()
4281 gdk_gc_unref( g_eraseGC
);