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 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
617 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
619 // Update immediately, not in idle time.
622 #ifndef __WXUNIVERSAL__
623 // Redraw child widgets
624 GList
*children
= pizza
->children
;
627 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
628 children
= children
->next
;
630 GdkRectangle child_area
;
631 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
633 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
641 //-----------------------------------------------------------------------------
642 // "key_press_event" from any window
643 //-----------------------------------------------------------------------------
645 // set WXTRACE to this to see the key event codes on the console
646 #define TRACE_KEYS _T("keyevent")
648 // translates an X key symbol to WXK_XXX value
650 // if isChar is true it means that the value returned will be used for EVT_CHAR
651 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
652 // for example, while if it is false it means that the value is going to be
653 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
655 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
661 // Shift, Control and Alt don't generate the CHAR events at all
664 key_code
= isChar
? 0 : WXK_SHIFT
;
668 key_code
= isChar
? 0 : WXK_CONTROL
;
676 key_code
= isChar
? 0 : WXK_ALT
;
679 // neither do the toggle modifies
680 case GDK_Scroll_Lock
:
681 key_code
= isChar
? 0 : WXK_SCROLL
;
685 key_code
= isChar
? 0 : WXK_CAPITAL
;
689 key_code
= isChar
? 0 : WXK_NUMLOCK
;
693 // various other special keys
706 case GDK_ISO_Left_Tab
:
713 key_code
= WXK_RETURN
;
717 key_code
= WXK_CLEAR
;
721 key_code
= WXK_PAUSE
;
725 key_code
= WXK_SELECT
;
729 key_code
= WXK_PRINT
;
733 key_code
= WXK_EXECUTE
;
737 key_code
= WXK_ESCAPE
;
740 // cursor and other extended keyboard keys
742 key_code
= WXK_DELETE
;
758 key_code
= WXK_RIGHT
;
765 case GDK_Prior
: // == GDK_Page_Up
766 key_code
= WXK_PRIOR
;
769 case GDK_Next
: // == GDK_Page_Down
782 key_code
= WXK_INSERT
;
797 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
801 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
805 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
809 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
813 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
817 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
821 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
825 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
829 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
833 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
837 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
841 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
845 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
848 case GDK_KP_Prior
: // == GDK_KP_Page_Up
849 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
852 case GDK_KP_Next
: // == GDK_KP_Page_Down
853 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
857 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
861 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
865 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
869 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
873 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
876 case GDK_KP_Multiply
:
877 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
881 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
884 case GDK_KP_Separator
:
885 // FIXME: what is this?
886 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
889 case GDK_KP_Subtract
:
890 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
894 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
898 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
915 key_code
= WXK_F1
+ keysym
- GDK_F1
;
925 static inline bool wxIsAsciiKeysym(KeySym ks
)
931 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
933 GdkEventKey
*gdk_event
)
935 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
936 // but only event->keyval which is quite useless to us, so remember
937 // the last character from GDK_KEY_PRESS and reuse it as last resort
939 // NB: should be MT-safe as we're always called from the main thread only
944 } s_lastKeyPress
= { 0, 0 };
946 KeySym keysym
= gdk_event
->keyval
;
948 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
949 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
953 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
957 // do we have the translation or is it a plain ASCII character?
958 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
960 // we should use keysym if it is ASCII as X does some translations
961 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
962 // which we don't want here (but which we do use for OnChar())
963 if ( !wxIsAsciiKeysym(keysym
) )
965 keysym
= (KeySym
)gdk_event
->string
[0];
968 // we want to always get the same key code when the same key is
969 // pressed regardless of the state of the modifies, i.e. on a
970 // standard US keyboard pressing '5' or '%' ('5' key with
971 // Shift) should result in the same key code in OnKeyDown():
972 // '5' (although OnChar() will get either '5' or '%').
974 // to do it we first translate keysym to keycode (== scan code)
975 // and then back but always using the lower register
976 Display
*dpy
= (Display
*)wxGetDisplay();
977 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
979 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
981 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
983 // use the normalized, i.e. lower register, keysym if we've
985 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
987 // as explained above, we want to have lower register key codes
988 // normally but for the letter keys we want to have the upper ones
990 // NB: don't use XConvertCase() here, we want to do it for letters
992 key_code
= toupper(key_code
);
994 else // non ASCII key, what to do?
996 // by default, ignore it
999 // but if we have cached information from the last KEY_PRESS
1000 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1003 if ( keysym
== s_lastKeyPress
.keysym
)
1005 key_code
= s_lastKeyPress
.keycode
;
1010 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1012 // remember it to be reused for KEY_UP event later
1013 s_lastKeyPress
.keysym
= keysym
;
1014 s_lastKeyPress
.keycode
= key_code
;
1018 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1020 // sending unknown key events doesn't really make sense
1024 // now fill all the other fields
1027 GdkModifierType state
;
1028 if (gdk_event
->window
)
1029 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1031 event
.SetTimestamp( gdk_event
->time
);
1032 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1033 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1034 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1035 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1036 event
.m_keyCode
= key_code
;
1037 event
.m_scanCode
= gdk_event
->keyval
;
1038 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1039 event
.m_rawFlags
= 0;
1042 event
.SetEventObject( win
);
1047 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1048 GdkEventKey
*gdk_event
,
1054 wxapp_install_idle_handler();
1058 if (g_blockEventsOnDrag
)
1062 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1063 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1065 // unknown key pressed, ignore (the event would be useless anyhow)
1069 // Emit KEY_DOWN event
1070 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1075 wxWindowGTK
*ancestor
= win
;
1078 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1081 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1082 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1085 if (ancestor
->IsTopLevel())
1087 ancestor
= ancestor
->GetParent();
1090 #endif // wxUSE_ACCEL
1092 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1093 // will only be sent if it is not in an accelerator table.
1096 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1097 KeySym keysym
= gdk_event
->keyval
;
1098 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1101 if ( gdk_event
->length
== 1 )
1103 key_code
= (unsigned char)gdk_event
->string
[0];
1105 else if ( wxIsAsciiKeysym(keysym
) )
1108 key_code
= (unsigned char)keysym
;
1114 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1116 event
.m_keyCode
= key_code
;
1118 // Implement OnCharHook by checking ancesteror top level windows
1119 wxWindow
*parent
= win
;
1120 while (parent
&& !parent
->IsTopLevel())
1121 parent
= parent
->GetParent();
1124 event
.SetEventType( wxEVT_CHAR_HOOK
);
1125 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1130 event
.SetEventType(wxEVT_CHAR
);
1131 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1136 // win is a control: tab can be propagated up
1138 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1139 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1140 // have this style, yet choose not to process this particular TAB in which
1141 // case TAB must still work as a navigational character
1143 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1145 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1147 wxNavigationKeyEvent new_event
;
1148 new_event
.SetEventObject( win
->GetParent() );
1149 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1150 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1151 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1152 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1153 new_event
.SetCurrentFocus( win
);
1154 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1157 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1159 (gdk_event
->keyval
== GDK_Escape
) )
1161 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1162 new_event
.SetEventObject( win
);
1163 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1168 // Pressing F10 will activate the menu bar of the top frame
1170 (gdk_event
->keyval
== GDK_F10
) )
1172 wxWindowGTK
*ancestor
= win
;
1175 if (wxIsKindOf(ancestor
,wxFrame
))
1177 wxFrame
*frame
= (wxFrame
*) ancestor
;
1178 wxMenuBar
*menubar
= frame
->GetMenuBar();
1181 wxNode
*node
= menubar
->GetMenus().First();
1184 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1185 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1191 ancestor
= ancestor
->GetParent();
1198 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1205 //-----------------------------------------------------------------------------
1206 // "key_release_event" from any window
1207 //-----------------------------------------------------------------------------
1209 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1210 GdkEventKey
*gdk_event
,
1216 wxapp_install_idle_handler();
1221 if (g_blockEventsOnDrag
)
1224 wxKeyEvent
event( wxEVT_KEY_UP
);
1225 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1227 // unknown key pressed, ignore (the event would be useless anyhow
1231 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1234 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1238 // ============================================================================
1240 // ============================================================================
1242 // ----------------------------------------------------------------------------
1243 // mouse event processing helpers
1244 // ----------------------------------------------------------------------------
1246 // init wxMouseEvent with the info from gdk_event
1248 // NB: this has to be a macro as gdk_event type is different for different
1249 // events we're used with
1250 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1251 /* wxMouseEvent& */ event, \
1252 /* GdkEventXXX * */ gdk_event) \
1254 event.SetTimestamp( gdk_event->time ); \
1255 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1256 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1257 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1258 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1259 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1260 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1261 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1263 wxPoint pt = win->GetClientAreaOrigin(); \
1264 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1265 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1267 event.SetEventObject( win ); \
1268 event.SetId( win->GetId() ); \
1269 event.SetTimestamp( gdk_event->time ); \
1272 static void AdjustEventButtonState(wxMouseEvent& event)
1274 // GDK reports the old state of the button for a button press event, but
1275 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1276 // for a LEFT_DOWN event, not FALSE, so we will invert
1277 // left/right/middleDown for the corresponding click events
1279 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1280 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1281 (event
.GetEventType() == wxEVT_LEFT_UP
))
1283 event
.m_leftDown
= !event
.m_leftDown
;
1287 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1288 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1289 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1291 event
.m_middleDown
= !event
.m_middleDown
;
1295 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1296 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1297 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1299 event
.m_rightDown
= !event
.m_rightDown
;
1304 // find the window to send the mouse event too
1306 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1311 if (win
->m_wxwindow
)
1313 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1314 xx
+= pizza
->xoffset
;
1315 yy
+= pizza
->yoffset
;
1318 wxNode
*node
= win
->GetChildren().First();
1321 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1323 node
= node
->Next();
1324 if (!child
->IsShown())
1327 if (child
->IsTransparentForMouse())
1329 // wxStaticBox is transparent in the box itself
1330 int xx1
= child
->m_x
;
1331 int yy1
= child
->m_y
;
1332 int xx2
= child
->m_x
+ child
->m_width
;
1333 int yy2
= child
->m_x
+ child
->m_height
;
1336 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1338 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1340 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1342 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1353 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1354 (child
->m_x
<= xx
) &&
1355 (child
->m_y
<= yy
) &&
1356 (child
->m_x
+child
->m_width
>= xx
) &&
1357 (child
->m_y
+child
->m_height
>= yy
))
1370 //-----------------------------------------------------------------------------
1371 // "button_press_event"
1372 //-----------------------------------------------------------------------------
1374 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1375 GdkEventButton
*gdk_event
,
1381 wxapp_install_idle_handler();
1384 wxPrintf( wxT("1) OnButtonPress from ") );
1385 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1386 wxPrintf( win->GetClassInfo()->GetClassName() );
1387 wxPrintf( wxT(".\n") );
1389 if (!win
->m_hasVMT
) return FALSE
;
1390 if (g_blockEventsOnDrag
) return TRUE
;
1391 if (g_blockEventsOnScroll
) return TRUE
;
1393 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1395 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1397 gtk_widget_grab_focus( win
->m_wxwindow
);
1399 wxPrintf( wxT("GrabFocus from ") );
1400 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1401 wxPrintf( win->GetClassInfo()->GetClassName() );
1402 wxPrintf( wxT(".\n") );
1406 wxEventType event_type
= wxEVT_NULL
;
1408 if (gdk_event
->button
== 1)
1410 switch (gdk_event
->type
)
1412 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1413 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1417 else if (gdk_event
->button
== 2)
1419 switch (gdk_event
->type
)
1421 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1422 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1426 else if (gdk_event
->button
== 3)
1428 switch (gdk_event
->type
)
1430 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1431 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1436 if ( event_type
== wxEVT_NULL
)
1438 // unknown mouse button or click type
1442 wxMouseEvent
event( event_type
);
1443 InitMouseEvent( win
, event
, gdk_event
);
1445 AdjustEventButtonState(event
);
1447 // wxListBox actually get mouse events from the item, so we need to give it
1448 // a chance to correct this
1449 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1451 // find the correct window to send the event too: it may be a different one
1452 // from the one which got it at GTK+ level because some control don't have
1453 // their own X window and thus cannot get any events.
1454 if ( !g_captureWindow
)
1455 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1457 gs_timeLastClick
= gdk_event
->time
;
1460 wxPrintf( wxT("2) OnButtonPress from ") );
1461 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1462 wxPrintf( win->GetClassInfo()->GetClassName() );
1463 wxPrintf( wxT(".\n") );
1466 if (win
->GetEventHandler()->ProcessEvent( event
))
1468 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1475 //-----------------------------------------------------------------------------
1476 // "button_release_event"
1477 //-----------------------------------------------------------------------------
1479 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1484 wxapp_install_idle_handler();
1486 if (!win
->m_hasVMT
) return FALSE
;
1487 if (g_blockEventsOnDrag
) return FALSE
;
1488 if (g_blockEventsOnScroll
) return FALSE
;
1490 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1493 printf( "OnButtonRelease from " );
1494 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1495 printf( win->GetClassInfo()->GetClassName() );
1499 wxEventType event_type
= wxEVT_NULL
;
1501 switch (gdk_event
->button
)
1503 case 1: event_type
= wxEVT_LEFT_UP
; break;
1504 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1505 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1506 default: return FALSE
;
1509 wxMouseEvent
event( event_type
);
1510 InitMouseEvent( win
, event
, gdk_event
);
1512 AdjustEventButtonState(event
);
1514 // same wxListBox hack as above
1515 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1517 if ( !g_captureWindow
)
1518 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1520 if (win
->GetEventHandler()->ProcessEvent( event
))
1522 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1529 //-----------------------------------------------------------------------------
1530 // "motion_notify_event"
1531 //-----------------------------------------------------------------------------
1533 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1534 GdkEventMotion
*gdk_event
,
1540 wxapp_install_idle_handler();
1542 if (!win
->m_hasVMT
) return FALSE
;
1543 if (g_blockEventsOnDrag
) return FALSE
;
1544 if (g_blockEventsOnScroll
) return FALSE
;
1546 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1548 if (gdk_event
->is_hint
)
1552 GdkModifierType state
;
1553 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1559 printf( "OnMotion from " );
1560 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1561 printf( win->GetClassInfo()->GetClassName() );
1565 wxMouseEvent
event( wxEVT_MOTION
);
1566 InitMouseEvent(win
, event
, gdk_event
);
1568 if ( g_captureWindow
)
1570 // synthetize a mouse enter or leave event if needed
1571 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1572 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1573 if ( hasMouse
!= g_captureWindowHasMouse
)
1575 // the mouse changed window
1576 g_captureWindowHasMouse
= hasMouse
;
1578 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1579 : wxEVT_LEAVE_WINDOW
);
1580 InitMouseEvent(win
, event
, gdk_event
);
1581 event
.SetEventObject(win
);
1582 win
->GetEventHandler()->ProcessEvent(event
);
1587 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1590 if (win
->GetEventHandler()->ProcessEvent( event
))
1592 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1599 //-----------------------------------------------------------------------------
1601 //-----------------------------------------------------------------------------
1603 // send the wxChildFocusEvent and wxFocusEvent, common code of
1604 // gtk_window_focus_in_callback() and SetFocus()
1605 static bool DoSendFocusEvents(wxWindow
*win
)
1607 // Notify the parent keeping track of focus for the kbd navigation
1608 // purposes that we got it.
1609 wxChildFocusEvent
eventChildFocus(win
);
1610 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1612 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1613 eventFocus
.SetEventObject(win
);
1615 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1618 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1619 GdkEvent
*WXUNUSED(event
),
1625 wxapp_install_idle_handler();
1627 if (!win
->m_hasVMT
) return FALSE
;
1628 if (g_blockEventsOnDrag
) return FALSE
;
1630 switch ( g_sendActivateEvent
)
1633 // we've got focus from outside, synthetize wxActivateEvent
1634 g_sendActivateEvent
= 1;
1638 // another our window just lost focus, it was already ours before
1639 // - don't send any wxActivateEvent
1640 g_sendActivateEvent
= -1;
1645 g_focusWindow
= win
;
1647 wxLogTrace(TRACE_FOCUS
,
1648 _T("%s: focus in"), win
->GetName().c_str());
1652 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1656 // caret needs to be informed about focus change
1657 wxCaret
*caret
= win
->GetCaret();
1660 caret
->OnSetFocus();
1662 #endif // wxUSE_CARET
1664 g_activeFrameLostFocus
= FALSE
;
1666 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1667 if ( active
!= g_activeFrame
)
1669 if ( g_activeFrame
)
1671 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1672 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1673 event
.SetEventObject(g_activeFrame
);
1674 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1677 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1678 g_activeFrame
= active
;
1679 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1680 event
.SetEventObject(g_activeFrame
);
1681 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1683 // Don't send focus events in addition to activate
1684 // if (win == g_activeFrame)
1688 // does the window itself think that it has the focus?
1689 if ( !win
->m_hasFocus
)
1691 // not yet, notify it
1692 win
->m_hasFocus
= TRUE
;
1694 if ( DoSendFocusEvents(win
) )
1696 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1704 //-----------------------------------------------------------------------------
1705 // "focus_out_event"
1706 //-----------------------------------------------------------------------------
1708 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1713 wxapp_install_idle_handler();
1715 if (!win
->m_hasVMT
) return FALSE
;
1716 if (g_blockEventsOnDrag
) return FALSE
;
1718 wxLogTrace( TRACE_FOCUS
,
1719 _T("%s: focus out"), win
->GetName().c_str() );
1721 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1723 // VZ: commenting this out because it does happen (although not easy
1724 // to reproduce, I only see it when using wxMiniFrame and not
1725 // always) and makes using Mahogany quite annoying
1727 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1728 wxT("unfocusing window that hasn't gained focus properly") );
1731 g_activeFrameLostFocus
= TRUE
;
1734 // if the focus goes out of our app alltogether, OnIdle() will send
1735 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1736 // g_sendActivateEvent to -1
1737 g_sendActivateEvent
= 0;
1739 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1743 g_focusWindow
= (wxWindowGTK
*)NULL
;
1751 // caret needs to be informed about focus change
1752 wxCaret
*caret
= win
->GetCaret();
1755 caret
->OnKillFocus();
1757 #endif // wxUSE_CARET
1759 // don't send the window a kill focus event if it thinks that it doesn't
1760 // have focus already
1761 if ( win
->m_hasFocus
)
1763 win
->m_hasFocus
= FALSE
;
1765 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1766 event
.SetEventObject( win
);
1768 if (win
->GetEventHandler()->ProcessEvent( event
))
1770 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1778 //-----------------------------------------------------------------------------
1779 // "enter_notify_event"
1780 //-----------------------------------------------------------------------------
1783 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1784 GdkEventCrossing
*gdk_event
,
1790 wxapp_install_idle_handler();
1792 if (!win
->m_hasVMT
) return FALSE
;
1793 if (g_blockEventsOnDrag
) return FALSE
;
1795 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1799 GdkModifierType state
= (GdkModifierType
)0;
1801 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1803 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1804 InitMouseEvent(win
, event
, gdk_event
);
1805 wxPoint pt
= win
->GetClientAreaOrigin();
1806 event
.m_x
= x
+ pt
.x
;
1807 event
.m_y
= y
+ pt
.y
;
1809 if (win
->GetEventHandler()->ProcessEvent( event
))
1811 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1818 //-----------------------------------------------------------------------------
1819 // "leave_notify_event"
1820 //-----------------------------------------------------------------------------
1822 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1827 wxapp_install_idle_handler();
1829 if (!win
->m_hasVMT
) return FALSE
;
1830 if (g_blockEventsOnDrag
) return FALSE
;
1832 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1834 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1835 event
.SetTimestamp( gdk_event
->time
);
1836 event
.SetEventObject( win
);
1840 GdkModifierType state
= (GdkModifierType
)0;
1842 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1844 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1845 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1846 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1847 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1848 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1849 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1850 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1852 wxPoint pt
= win
->GetClientAreaOrigin();
1853 event
.m_x
= x
+ pt
.x
;
1854 event
.m_y
= y
+ pt
.y
;
1856 if (win
->GetEventHandler()->ProcessEvent( event
))
1858 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1865 //-----------------------------------------------------------------------------
1866 // "value_changed" from m_vAdjust
1867 //-----------------------------------------------------------------------------
1869 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1876 wxapp_install_idle_handler();
1878 if (g_blockEventsOnDrag
) return;
1880 if (!win
->m_hasVMT
) return;
1882 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1883 if (fabs(diff
) < 0.2) return;
1885 win
->m_oldVerticalPos
= adjust
->value
;
1887 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1888 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
1890 int value
= (int)(adjust
->value
+0.5);
1892 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1893 event
.SetEventObject( win
);
1894 win
->GetEventHandler()->ProcessEvent( event
);
1897 //-----------------------------------------------------------------------------
1898 // "value_changed" from m_hAdjust
1899 //-----------------------------------------------------------------------------
1901 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1908 wxapp_install_idle_handler();
1910 if (g_blockEventsOnDrag
) return;
1911 if (!win
->m_hasVMT
) return;
1913 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1914 if (fabs(diff
) < 0.2) return;
1916 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1917 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
1919 win
->m_oldHorizontalPos
= adjust
->value
;
1921 int value
= (int)(adjust
->value
+0.5);
1923 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1924 event
.SetEventObject( win
);
1925 win
->GetEventHandler()->ProcessEvent( event
);
1928 //-----------------------------------------------------------------------------
1929 // "button_press_event" from scrollbar
1930 //-----------------------------------------------------------------------------
1932 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1933 GdkEventButton
*gdk_event
,
1939 wxapp_install_idle_handler();
1942 g_blockEventsOnScroll
= TRUE
;
1944 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1946 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1952 //-----------------------------------------------------------------------------
1953 // "button_release_event" from scrollbar
1954 //-----------------------------------------------------------------------------
1956 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1957 GdkEventButton
*WXUNUSED(gdk_event
),
1962 // don't test here as we can release the mouse while being over
1963 // a different window than the slider
1965 // if (gdk_event->window != widget->slider) return FALSE;
1967 g_blockEventsOnScroll
= FALSE
;
1969 if (win
->m_isScrolling
)
1971 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1975 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1976 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1978 value
= (int)(win
->m_hAdjust
->value
+0.5);
1981 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
1983 value
= (int)(win
->m_vAdjust
->value
+0.5);
1987 wxScrollWinEvent
event( command
, value
, dir
);
1988 event
.SetEventObject( win
);
1989 win
->GetEventHandler()->ProcessEvent( event
);
1992 win
->m_isScrolling
= FALSE
;
1997 // ----------------------------------------------------------------------------
1998 // this wxWindowBase function is implemented here (in platform-specific file)
1999 // because it is static and so couldn't be made virtual
2000 // ----------------------------------------------------------------------------
2002 wxWindow
*wxWindowBase::FindFocus()
2004 // the cast is necessary when we compile in wxUniversal mode
2005 return (wxWindow
*)g_focusWindow
;
2008 //-----------------------------------------------------------------------------
2010 //-----------------------------------------------------------------------------
2012 // VZ: Robert commented the code using out so it generates warnings: should
2013 // be either fixed or removed completely
2016 static void gtk_window_destroy_callback( GtkWidget
* widget
, wxWindow
*win
)
2018 wxWindowDestroyEvent
event(win
);
2019 win
->GetEventHandler()->ProcessEvent(event
);
2024 //-----------------------------------------------------------------------------
2025 // "realize" from m_widget
2026 //-----------------------------------------------------------------------------
2028 /* We cannot set colours and fonts before the widget has
2029 been realized, so we do this directly after realization. */
2032 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2037 wxapp_install_idle_handler();
2039 if (win
->m_delayedBackgroundColour
)
2040 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2042 if (win
->m_delayedForegroundColour
)
2043 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2045 wxWindowCreateEvent
event( win
);
2046 event
.SetEventObject( win
);
2047 win
->GetEventHandler()->ProcessEvent( event
);
2052 //-----------------------------------------------------------------------------
2054 //-----------------------------------------------------------------------------
2057 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2058 GtkAllocation
*WXUNUSED(alloc
),
2062 wxapp_install_idle_handler();
2064 if (!win
->m_hasScrolling
) return;
2066 int client_width
= 0;
2067 int client_height
= 0;
2068 win
->GetClientSize( &client_width
, &client_height
);
2069 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2072 win
->m_oldClientWidth
= client_width
;
2073 win
->m_oldClientHeight
= client_height
;
2075 if (!win
->m_nativeSizeEvent
)
2077 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2078 event
.SetEventObject( win
);
2079 win
->GetEventHandler()->ProcessEvent( event
);
2085 #define WXUNUSED_UNLESS_XIM(param) param
2087 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2090 /* Resize XIM window */
2093 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2094 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2095 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2098 wxapp_install_idle_handler();
2104 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2108 gdk_window_get_size (widget
->window
, &width
, &height
);
2109 win
->m_icattr
->preedit_area
.width
= width
;
2110 win
->m_icattr
->preedit_area
.height
= height
;
2111 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2116 //-----------------------------------------------------------------------------
2117 // "realize" from m_wxwindow
2118 //-----------------------------------------------------------------------------
2120 /* Initialize XIM support */
2123 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2124 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2127 wxapp_install_idle_handler();
2130 if (win
->m_ic
) return FALSE
;
2131 if (!widget
) return FALSE
;
2132 if (!gdk_im_ready()) return FALSE
;
2134 win
->m_icattr
= gdk_ic_attr_new();
2135 if (!win
->m_icattr
) return FALSE
;
2139 GdkColormap
*colormap
;
2140 GdkICAttr
*attr
= win
->m_icattr
;
2141 unsigned attrmask
= GDK_IC_ALL_REQ
;
2143 GdkIMStyle supported_style
= (GdkIMStyle
)
2144 (GDK_IM_PREEDIT_NONE
|
2145 GDK_IM_PREEDIT_NOTHING
|
2146 GDK_IM_PREEDIT_POSITION
|
2147 GDK_IM_STATUS_NONE
|
2148 GDK_IM_STATUS_NOTHING
);
2150 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2151 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2153 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2154 attr
->client_window
= widget
->window
;
2156 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2157 gtk_widget_get_default_colormap ())
2159 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2160 attr
->preedit_colormap
= colormap
;
2163 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2164 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2165 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2166 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2168 switch (style
& GDK_IM_PREEDIT_MASK
)
2170 case GDK_IM_PREEDIT_POSITION
:
2171 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2173 g_warning ("over-the-spot style requires fontset");
2177 gdk_window_get_size (widget
->window
, &width
, &height
);
2179 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2180 attr
->spot_location
.x
= 0;
2181 attr
->spot_location
.y
= height
;
2182 attr
->preedit_area
.x
= 0;
2183 attr
->preedit_area
.y
= 0;
2184 attr
->preedit_area
.width
= width
;
2185 attr
->preedit_area
.height
= height
;
2186 attr
->preedit_fontset
= widget
->style
->font
;
2191 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2193 if (win
->m_ic
== NULL
)
2194 g_warning ("Can't create input context.");
2197 mask
= gdk_window_get_events (widget
->window
);
2198 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2199 gdk_window_set_events (widget
->window
, mask
);
2201 if (GTK_WIDGET_HAS_FOCUS(widget
))
2202 gdk_im_begin (win
->m_ic
, widget
->window
);
2209 //-----------------------------------------------------------------------------
2210 // InsertChild for wxWindowGTK.
2211 //-----------------------------------------------------------------------------
2213 /* Callback for wxWindowGTK. This very strange beast has to be used because
2214 * C++ has no virtual methods in a constructor. We have to emulate a
2215 * virtual function here as wxNotebook requires a different way to insert
2216 * a child in it. I had opted for creating a wxNotebookPage window class
2217 * which would have made this superfluous (such in the MDI window system),
2218 * but no-one was listening to me... */
2220 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2222 /* the window might have been scrolled already, do we
2223 have to adapt the position */
2224 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2225 child
->m_x
+= pizza
->xoffset
;
2226 child
->m_y
+= pizza
->yoffset
;
2228 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2229 GTK_WIDGET(child
->m_widget
),
2236 //-----------------------------------------------------------------------------
2238 //-----------------------------------------------------------------------------
2240 wxWindow
*wxGetActiveWindow()
2242 return wxWindow::FindFocus();
2245 //-----------------------------------------------------------------------------
2247 //-----------------------------------------------------------------------------
2249 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2251 #ifdef __WXUNIVERSAL__
2252 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2254 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2255 #endif // __WXUNIVERSAL__/__WXGTK__
2257 void wxWindowGTK::Init()
2263 m_widget
= (GtkWidget
*) NULL
;
2264 m_wxwindow
= (GtkWidget
*) NULL
;
2265 m_focusWidget
= (GtkWidget
*) NULL
;
2275 m_needParent
= TRUE
;
2276 m_isBeingDeleted
= FALSE
;
2279 m_nativeSizeEvent
= FALSE
;
2281 m_hasScrolling
= FALSE
;
2282 m_isScrolling
= FALSE
;
2284 m_hAdjust
= (GtkAdjustment
*) NULL
;
2285 m_vAdjust
= (GtkAdjustment
*) NULL
;
2286 m_oldHorizontalPos
= 0.0;
2287 m_oldVerticalPos
= 0.0;
2290 m_widgetStyle
= (GtkStyle
*) NULL
;
2292 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2294 m_acceptsFocus
= FALSE
;
2297 m_clipPaintRegion
= FALSE
;
2299 m_cursor
= *wxSTANDARD_CURSOR
;
2301 m_delayedForegroundColour
= FALSE
;
2302 m_delayedBackgroundColour
= FALSE
;
2305 m_ic
= (GdkIC
*) NULL
;
2306 m_icattr
= (GdkICAttr
*) NULL
;
2310 wxWindowGTK::wxWindowGTK()
2315 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2320 const wxString
&name
)
2324 Create( parent
, id
, pos
, size
, style
, name
);
2327 bool wxWindowGTK::Create( wxWindow
*parent
,
2332 const wxString
&name
)
2334 if (!PreCreation( parent
, pos
, size
) ||
2335 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2337 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2341 m_insertCallback
= wxInsertChildInWindow
;
2343 // always needed for background clearing
2344 m_delayedBackgroundColour
= TRUE
;
2346 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2347 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2349 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2351 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2352 scroll_class
->scrollbar_spacing
= 0;
2354 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2356 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2357 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2359 m_wxwindow
= gtk_pizza_new();
2361 #ifndef __WXUNIVERSAL__
2362 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2364 if (HasFlag(wxRAISED_BORDER
))
2366 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2368 else if (HasFlag(wxSUNKEN_BORDER
))
2370 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2372 else if (HasFlag(wxSIMPLE_BORDER
))
2374 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2378 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2380 #endif // __WXUNIVERSAL__
2382 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2384 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2385 m_acceptsFocus
= TRUE
;
2387 // I _really_ don't want scrollbars in the beginning
2388 m_vAdjust
->lower
= 0.0;
2389 m_vAdjust
->upper
= 1.0;
2390 m_vAdjust
->value
= 0.0;
2391 m_vAdjust
->step_increment
= 1.0;
2392 m_vAdjust
->page_increment
= 1.0;
2393 m_vAdjust
->page_size
= 5.0;
2394 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2395 m_hAdjust
->lower
= 0.0;
2396 m_hAdjust
->upper
= 1.0;
2397 m_hAdjust
->value
= 0.0;
2398 m_hAdjust
->step_increment
= 1.0;
2399 m_hAdjust
->page_increment
= 1.0;
2400 m_hAdjust
->page_size
= 5.0;
2401 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2403 // these handlers block mouse events to any window during scrolling such as
2404 // motion events and prevent GTK and wxWindows from fighting over where the
2407 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2408 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2410 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2411 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2413 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2414 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2416 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2417 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2419 // these handlers get notified when screen updates are required either when
2420 // scrolling or when the window size (and therefore scrollbar configuration)
2423 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2424 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2425 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2426 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2428 gtk_widget_show( m_wxwindow
);
2431 m_parent
->DoAddChild( this );
2433 m_focusWidget
= m_wxwindow
;
2442 wxWindowGTK::~wxWindowGTK()
2444 if (g_focusWindow
== this)
2445 g_focusWindow
= NULL
;
2447 if (g_activeFrame
== this)
2448 g_activeFrame
= NULL
;
2450 if ( g_delayedFocus
== this )
2451 g_delayedFocus
= NULL
;
2453 m_isBeingDeleted
= TRUE
;
2462 m_parent
->RemoveChild( this );
2466 gdk_ic_destroy (m_ic
);
2468 gdk_ic_attr_destroy (m_icattr
);
2473 #if DISABLE_STYLE_IF_BROKEN_THEME
2474 // don't delete if it's a pixmap theme style
2475 if (!m_widgetStyle
->engine_data
)
2476 gtk_style_unref( m_widgetStyle
);
2478 m_widgetStyle
= (GtkStyle
*) NULL
;
2483 gtk_widget_destroy( m_wxwindow
);
2484 m_wxwindow
= (GtkWidget
*) NULL
;
2489 gtk_widget_destroy( m_widget
);
2490 m_widget
= (GtkWidget
*) NULL
;
2494 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2496 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2498 // This turns -1 into 30 so that a minimal window is
2499 // visible even although -1,-1 has been given as the
2500 // size of the window. the same trick is used in other
2501 // ports and should make debugging easier.
2502 m_width
= WidthDefault(size
.x
) ;
2503 m_height
= HeightDefault(size
.y
);
2508 // some reasonable defaults
2513 m_x
= (gdk_screen_width () - m_width
) / 2;
2514 if (m_x
< 10) m_x
= 10;
2518 m_y
= (gdk_screen_height () - m_height
) / 2;
2519 if (m_y
< 10) m_y
= 10;
2526 void wxWindowGTK::PostCreation()
2528 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2534 // these get reported to wxWindows -> wxPaintEvent
2536 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2538 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2539 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2542 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2543 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2545 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2547 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2548 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2551 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2555 // these are called when the "sunken" or "raised" borders are drawn
2556 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2557 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2560 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2561 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2567 if (m_focusWidget
== NULL
)
2568 m_focusWidget
= m_widget
;
2570 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2571 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2573 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2574 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2576 // connect to the various key and mouse handlers
2578 GtkWidget
*connect_widget
= GetConnectWidget();
2580 ConnectWidget( connect_widget
);
2582 /* We cannot set colours, fonts and cursors before the widget has
2583 been realized, so we do this directly after realization */
2584 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2585 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2589 // Catch native resize events
2590 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2591 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2593 // Initialize XIM support
2594 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2595 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2597 // And resize XIM window
2598 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2599 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2602 if (!GTK_IS_COMBO(m_widget
))
2604 // This is needed if we want to add our windows into native
2605 // GTK control, such as the toolbar. With this callback, the
2606 // toolbar gets to know the correct size (the one set by the
2607 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2608 // when moving to GTK 2.0.
2609 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2610 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2616 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2618 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2619 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2621 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2622 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2624 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2625 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2627 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2628 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2630 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2631 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2633 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2634 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2636 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2637 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2639 // This keeps crashing on me. RR.
2641 // gtk_signal_connect( GTK_OBJECT(widget), "destroy",
2642 // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this );
2645 bool wxWindowGTK::Destroy()
2647 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2651 return wxWindowBase::Destroy();
2654 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2656 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2659 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2661 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2662 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2665 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2668 if (m_resizing
) return; /* I don't like recursions */
2671 int currentX
, currentY
;
2672 GetPosition(¤tX
, ¤tY
);
2677 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2679 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2681 /* don't set the size for children of wxNotebook, just take the values. */
2689 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2690 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2692 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2693 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2694 if (width
!= -1) m_width
= width
;
2695 if (height
!= -1) m_height
= height
;
2699 m_x
= x
+ pizza
->xoffset
;
2700 m_y
= y
+ pizza
->yoffset
;
2705 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2707 if (width
== -1) m_width
= 80;
2710 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2712 if (height
== -1) m_height
= 26;
2715 int minWidth
= GetMinWidth(),
2716 minHeight
= GetMinHeight(),
2717 maxWidth
= GetMaxWidth(),
2718 maxHeight
= GetMaxHeight();
2720 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2721 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2722 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2723 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2726 int bottom_border
= 0;
2729 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2731 /* the default button has a border around it */
2737 DoMoveWindow( m_x
-border
,
2740 m_height
+border
+bottom_border
);
2745 /* Sometimes the client area changes size without the
2746 whole windows's size changing, but if the whole
2747 windows's size doesn't change, no wxSizeEvent will
2748 normally be sent. Here we add an extra test if
2749 the client test has been changed and this will
2751 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2755 wxPrintf( "OnSize sent from " );
2756 if (GetClassInfo() && GetClassInfo()->GetClassName())
2757 wxPrintf( GetClassInfo()->GetClassName() );
2758 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2761 if (!m_nativeSizeEvent
)
2763 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2764 event
.SetEventObject( this );
2765 GetEventHandler()->ProcessEvent( event
);
2771 void wxWindowGTK::OnInternalIdle()
2773 // Update invalidated regions.
2776 // Synthetize activate events.
2777 if ( g_sendActivateEvent
!= -1 )
2779 bool activate
= g_sendActivateEvent
!= 0;
2782 g_sendActivateEvent
= -1;
2784 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2787 if ( g_activeFrameLostFocus
)
2789 if ( g_activeFrame
)
2791 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2792 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2793 event
.SetEventObject(g_activeFrame
);
2794 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2795 g_activeFrame
= NULL
;
2797 g_activeFrameLostFocus
= FALSE
;
2800 wxCursor cursor
= m_cursor
;
2801 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2805 /* I now set the cursor anew in every OnInternalIdle call
2806 as setting the cursor in a parent window also effects the
2807 windows above so that checking for the current cursor is
2812 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2814 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2816 if (!g_globalCursor
.Ok())
2817 cursor
= *wxSTANDARD_CURSOR
;
2819 window
= m_widget
->window
;
2820 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2821 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2827 GdkWindow
*window
= m_widget
->window
;
2828 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2829 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2837 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2839 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2841 if (width
) (*width
) = m_width
;
2842 if (height
) (*height
) = m_height
;
2845 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2847 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2851 SetSize( width
, height
);
2858 #ifndef __WXUNIVERSAL__
2859 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2861 /* when using GTK 1.2 we set the shadow border size to 2 */
2865 if (HasFlag(wxSIMPLE_BORDER
))
2867 /* when using GTK 1.2 we set the simple border size to 1 */
2871 #endif // __WXUNIVERSAL__
2875 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2877 GtkRequisition vscroll_req
;
2878 vscroll_req
.width
= 2;
2879 vscroll_req
.height
= 2;
2880 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2881 (scroll_window
->vscrollbar
, &vscroll_req
);
2883 GtkRequisition hscroll_req
;
2884 hscroll_req
.width
= 2;
2885 hscroll_req
.height
= 2;
2886 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2887 (scroll_window
->hscrollbar
, &hscroll_req
);
2889 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2891 if (scroll_window
->vscrollbar_visible
)
2893 dw
+= vscroll_req
.width
;
2894 dw
+= scroll_class
->scrollbar_spacing
;
2897 if (scroll_window
->hscrollbar_visible
)
2899 dh
+= hscroll_req
.height
;
2900 dh
+= scroll_class
->scrollbar_spacing
;
2904 SetSize( width
+dw
, height
+dh
);
2908 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2910 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2914 if (width
) (*width
) = m_width
;
2915 if (height
) (*height
) = m_height
;
2922 #ifndef __WXUNIVERSAL__
2923 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2925 /* when using GTK 1.2 we set the shadow border size to 2 */
2929 if (HasFlag(wxSIMPLE_BORDER
))
2931 /* when using GTK 1.2 we set the simple border size to 1 */
2935 #endif // __WXUNIVERSAL__
2939 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2941 GtkRequisition vscroll_req
;
2942 vscroll_req
.width
= 2;
2943 vscroll_req
.height
= 2;
2944 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2945 (scroll_window
->vscrollbar
, &vscroll_req
);
2947 GtkRequisition hscroll_req
;
2948 hscroll_req
.width
= 2;
2949 hscroll_req
.height
= 2;
2950 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2951 (scroll_window
->hscrollbar
, &hscroll_req
);
2953 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2955 if (scroll_window
->vscrollbar_visible
)
2957 dw
+= vscroll_req
.width
;
2958 dw
+= scroll_class
->scrollbar_spacing
;
2961 if (scroll_window
->hscrollbar_visible
)
2963 dh
+= hscroll_req
.height
;
2964 dh
+= scroll_class
->scrollbar_spacing
;
2968 if (width
) (*width
) = m_width
- dw
;
2969 if (height
) (*height
) = m_height
- dh
;
2973 printf( "GetClientSize, name %s ", GetName().c_str() );
2974 if (width) printf( " width = %d", (*width) );
2975 if (height) printf( " height = %d", (*height) );
2980 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2982 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2986 if (m_parent
&& m_parent
->m_wxwindow
)
2988 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2989 dx
= pizza
->xoffset
;
2990 dy
= pizza
->yoffset
;
2993 if (x
) (*x
) = m_x
- dx
;
2994 if (y
) (*y
) = m_y
- dy
;
2997 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2999 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3001 if (!m_widget
->window
) return;
3003 GdkWindow
*source
= (GdkWindow
*) NULL
;
3005 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3007 source
= m_widget
->window
;
3011 gdk_window_get_origin( source
, &org_x
, &org_y
);
3015 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3017 org_x
+= m_widget
->allocation
.x
;
3018 org_y
+= m_widget
->allocation
.y
;
3026 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3028 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3030 if (!m_widget
->window
) return;
3032 GdkWindow
*source
= (GdkWindow
*) NULL
;
3034 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3036 source
= m_widget
->window
;
3040 gdk_window_get_origin( source
, &org_x
, &org_y
);
3044 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3046 org_x
+= m_widget
->allocation
.x
;
3047 org_y
+= m_widget
->allocation
.y
;
3055 bool wxWindowGTK::Show( bool show
)
3057 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3059 if (!wxWindowBase::Show(show
))
3066 gtk_widget_show( m_widget
);
3068 gtk_widget_hide( m_widget
);
3073 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3075 win
->OnParentEnable(enable
);
3077 // Recurse, so that children have the opportunity to Do The Right Thing
3078 // and reset colours that have been messed up by a parent's (really ancestor's)
3080 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3082 node
= node
->GetNext() )
3084 wxWindow
*child
= node
->GetData();
3085 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3086 wxWindowNotifyEnable(child
, enable
);
3090 bool wxWindowGTK::Enable( bool enable
)
3092 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3094 if (!wxWindowBase::Enable(enable
))
3100 gtk_widget_set_sensitive( m_widget
, enable
);
3102 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3104 wxWindowNotifyEnable(this, enable
);
3109 int wxWindowGTK::GetCharHeight() const
3111 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3113 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3115 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3117 return font
->ascent
+ font
->descent
;
3120 int wxWindowGTK::GetCharWidth() const
3122 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3124 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3126 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3128 return gdk_string_width( font
, "H" );
3131 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3135 int *externalLeading
,
3136 const wxFont
*theFont
) const
3138 wxFont fontToUse
= m_font
;
3139 if (theFont
) fontToUse
= *theFont
;
3141 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3143 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3144 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3145 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3146 if (descent
) (*descent
) = font
->descent
;
3147 if (externalLeading
) (*externalLeading
) = 0; // ??
3150 void wxWindowGTK::SetFocus()
3152 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3156 // don't do anything if we already have focus
3162 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3164 gtk_widget_grab_focus (m_wxwindow
);
3169 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3171 if (!GTK_WIDGET_REALIZED(m_widget
))
3173 // we can't set the focus to the widget now so we remember that
3174 // it should be focused and will do it later, during the idle
3175 // time, as soon as we can
3176 wxLogTrace(TRACE_FOCUS
,
3177 _T("Delaying setting focus to %s(%s)"),
3178 GetClassInfo()->GetClassName(), GetLabel().c_str());
3180 g_delayedFocus
= this;
3184 wxLogTrace(TRACE_FOCUS
,
3185 _T("Setting focus to %s(%s)"),
3186 GetClassInfo()->GetClassName(), GetLabel().c_str());
3188 gtk_widget_grab_focus (m_widget
);
3191 else if (GTK_IS_CONTAINER(m_widget
))
3193 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3197 wxLogTrace(TRACE_FOCUS
,
3198 _T("Can't set focus to %s(%s)"),
3199 GetClassInfo()->GetClassName(), GetLabel().c_str());
3204 bool wxWindowGTK::AcceptsFocus() const
3206 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3209 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3211 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3213 wxWindowGTK
*oldParent
= m_parent
,
3214 *newParent
= (wxWindowGTK
*)newParentBase
;
3216 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3218 if ( !wxWindowBase::Reparent(newParent
) )
3221 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3223 /* prevent GTK from deleting the widget arbitrarily */
3224 gtk_widget_ref( m_widget
);
3228 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3231 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3235 /* insert GTK representation */
3236 (*(newParent
->m_insertCallback
))(newParent
, this);
3239 /* reverse: prevent GTK from deleting the widget arbitrarily */
3240 gtk_widget_unref( m_widget
);
3245 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3247 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3249 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3251 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3256 /* insert GTK representation */
3257 (*m_insertCallback
)(this, child
);
3260 void wxWindowGTK::Raise()
3262 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3264 if (!m_widget
->window
) return;
3266 gdk_window_raise( m_widget
->window
);
3269 void wxWindowGTK::Lower()
3271 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3273 if (!m_widget
->window
) return;
3275 gdk_window_lower( m_widget
->window
);
3278 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3280 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3282 if (cursor
== m_cursor
)
3286 wxapp_install_idle_handler();
3288 if (cursor
== wxNullCursor
)
3289 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3291 return wxWindowBase::SetCursor( cursor
);
3294 void wxWindowGTK::WarpPointer( int x
, int y
)
3296 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3298 // We provide this function ourselves as it is
3299 // missing in GDK (top of this file).
3301 GdkWindow
*window
= (GdkWindow
*) NULL
;
3303 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3305 window
= GetConnectWidget()->window
;
3308 gdk_window_warp_pointer( window
, x
, y
);
3312 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3314 if (!m_widget
) return;
3315 if (!m_widget
->window
) return;
3319 wxapp_install_idle_handler();
3321 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3325 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3326 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3330 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3331 m_clearRegion
.Clear();
3332 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3340 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3341 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3345 GdkRectangle gdk_rect
;
3346 gdk_rect
.x
= rect
->x
;
3347 gdk_rect
.y
= rect
->y
;
3348 gdk_rect
.width
= rect
->width
;
3349 gdk_rect
.height
= rect
->height
;
3350 gtk_widget_draw( m_widget
, &gdk_rect
);
3357 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3358 m_updateRegion
.Clear();
3359 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3363 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3371 GdkRectangle gdk_rect
;
3372 gdk_rect
.x
= rect
->x
;
3373 gdk_rect
.y
= rect
->y
;
3374 gdk_rect
.width
= rect
->width
;
3375 gdk_rect
.height
= rect
->height
;
3376 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3380 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3386 void wxWindowGTK::Update()
3391 void wxWindowGTK::GtkUpdate()
3394 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3395 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3398 if (!m_updateRegion
.IsEmpty())
3399 GtkSendPaintEvents();
3402 void wxWindowGTK::GtkSendPaintEvents()
3406 m_clearRegion
.Clear();
3407 m_updateRegion
.Clear();
3411 // widget to draw on
3412 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3414 // Clip to paint region in wxClientDC
3415 m_clipPaintRegion
= TRUE
;
3417 if (GetThemeEnabled())
3419 // find ancestor from which to steal background
3420 wxWindow
*parent
= GetParent();
3421 while (parent
&& !parent
->IsTopLevel())
3422 parent
= parent
->GetParent();
3424 parent
= (wxWindow
*)this;
3426 wxRegionIterator
upd( m_updateRegion
);
3430 rect
.x
= upd
.GetX();
3431 rect
.y
= upd
.GetY();
3432 rect
.width
= upd
.GetWidth();
3433 rect
.height
= upd
.GetHeight();
3435 gtk_paint_flat_box( parent
->m_widget
->style
,
3448 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3450 wxWindowDC
dc( (wxWindow
*)this );
3451 if (m_clearRegion
.IsEmpty())
3452 dc
.SetClippingRegion( m_updateRegion
);
3454 dc
.SetClippingRegion( m_clearRegion
);
3456 wxEraseEvent
erase_event( GetId(), &dc
);
3457 erase_event
.SetEventObject( this );
3459 if (!GetEventHandler()->ProcessEvent(erase_event
))
3463 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3464 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3466 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3468 wxRegionIterator
upd( m_clearRegion
);
3471 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3472 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3476 m_clearRegion
.Clear();
3479 wxNcPaintEvent
nc_paint_event( GetId() );
3480 nc_paint_event
.SetEventObject( this );
3481 GetEventHandler()->ProcessEvent( nc_paint_event
);
3483 wxPaintEvent
paint_event( GetId() );
3484 paint_event
.SetEventObject( this );
3485 GetEventHandler()->ProcessEvent( paint_event
);
3487 m_clipPaintRegion
= FALSE
;
3489 #ifndef __WXUNIVERSAL__
3491 // The following code will result in all window-less widgets
3492 // being redrawn because the wxWindows class is allowed to
3493 // paint over the window-less widgets.
3495 GList
*children
= pizza
->children
;
3498 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3499 children
= children
->next
;
3501 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3502 GTK_WIDGET_DRAWABLE (child
->widget
))
3504 // Get intersection of widget area and update region
3505 wxRegion
region( m_updateRegion
);
3507 GdkEventExpose gdk_event
;
3508 gdk_event
.type
= GDK_EXPOSE
;
3509 gdk_event
.window
= pizza
->bin_window
;
3510 gdk_event
.count
= 0;
3512 wxRegionIterator
upd( m_updateRegion
);
3516 rect
.x
= upd
.GetX();
3517 rect
.y
= upd
.GetY();
3518 rect
.width
= upd
.GetWidth();
3519 rect
.height
= upd
.GetHeight();
3521 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3523 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3533 m_updateRegion
.Clear();
3536 void wxWindowGTK::Clear()
3538 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3540 if (m_wxwindow
&& m_wxwindow
->window
)
3542 m_clearRegion
.Clear();
3543 wxSize
size( GetClientSize() );
3544 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3546 // Better do this in idle?
3552 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3554 wxWindowBase::DoSetToolTip(tip
);
3557 m_tooltip
->Apply( (wxWindow
*)this );
3560 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3562 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3564 #endif // wxUSE_TOOLTIPS
3566 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3568 GdkWindow
*window
= (GdkWindow
*) NULL
;
3570 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3572 window
= GetConnectWidget()->window
;
3576 // We need the pixel value e.g. for background clearing.
3577 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3581 // wxMSW doesn't clear the window here, either.
3582 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3588 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3590 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3592 if (!wxWindowBase::SetBackgroundColour(colour
))
3595 GdkWindow
*window
= (GdkWindow
*) NULL
;
3597 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3599 window
= GetConnectWidget()->window
;
3603 // indicate that a new style has been set
3604 // but it couldn't get applied as the
3605 // widget hasn't been realized yet.
3606 m_delayedBackgroundColour
= TRUE
;
3611 GtkSetBackgroundColour( colour
);
3617 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3619 GdkWindow
*window
= (GdkWindow
*) NULL
;
3621 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3623 window
= GetConnectWidget()->window
;
3630 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3632 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3634 if (!wxWindowBase::SetForegroundColour(colour
))
3636 // don't leave if the GTK widget has just
3638 if (!m_delayedForegroundColour
) return FALSE
;
3641 GdkWindow
*window
= (GdkWindow
*) NULL
;
3643 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3645 window
= GetConnectWidget()->window
;
3649 // indicate that a new style has been set
3650 // but it couldn't get applied as the
3651 // widget hasn't been realized yet.
3652 m_delayedForegroundColour
= TRUE
;
3656 GtkSetForegroundColour( colour
);
3662 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3666 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3668 // FIXME: no more klass in 2.0
3670 remake
->klass
= m_widgetStyle
->klass
;
3673 gtk_style_unref( m_widgetStyle
);
3674 m_widgetStyle
= remake
;
3678 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3681 def
= gtk_widget_get_default_style();
3683 m_widgetStyle
= gtk_style_copy( def
);
3685 // FIXME: no more klass in 2.0
3687 m_widgetStyle
->klass
= def
->klass
;
3691 return m_widgetStyle
;
3694 void wxWindowGTK::SetWidgetStyle()
3696 #if DISABLE_STYLE_IF_BROKEN_THEME
3697 if (m_widget
->style
->engine_data
)
3699 static bool s_warningPrinted
= FALSE
;
3700 if (!s_warningPrinted
)
3702 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3703 s_warningPrinted
= TRUE
;
3705 m_widgetStyle
= m_widget
->style
;
3710 GtkStyle
*style
= GetWidgetStyle();
3712 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3714 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3717 if (m_foregroundColour
.Ok())
3719 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3720 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3722 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3723 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3724 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3728 // Try to restore the gtk default style. This is still a little
3729 // oversimplified for what is probably really needed here for controls
3730 // other than buttons, but is better than not being able to (re)set a
3731 // control's foreground colour to *wxBLACK -- RL
3732 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3735 def
= gtk_widget_get_default_style();
3737 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3738 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3739 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3743 if (m_backgroundColour
.Ok())
3745 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3746 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3748 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3749 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3750 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3751 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3752 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3753 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3754 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3755 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3759 // Try to restore the gtk default style. This is still a little
3760 // oversimplified for what is probably really needed here for controls
3761 // other than buttons, but is better than not being able to (re)set a
3762 // control's background colour to default grey and means resetting a
3763 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3765 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3768 def
= gtk_widget_get_default_style();
3770 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3771 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3772 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3773 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3774 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3775 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3776 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3777 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3782 void wxWindowGTK::ApplyWidgetStyle()
3786 //-----------------------------------------------------------------------------
3787 // Pop-up menu stuff
3788 //-----------------------------------------------------------------------------
3790 #if wxUSE_MENUS_NATIVE
3793 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3795 *is_waiting
= FALSE
;
3798 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3800 menu
->SetInvokingWindow( win
);
3801 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3804 wxMenuItem
*menuitem
= node
->GetData();
3805 if (menuitem
->IsSubMenu())
3807 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3810 node
= node
->GetNext();
3814 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3815 // wxPopupMenuPositionCallback()
3817 // should be safe even in the MT case as the user can hardly popup 2 menus
3818 // simultaneously, can he?
3819 static gint gs_pop_x
= 0;
3820 static gint gs_pop_y
= 0;
3822 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3825 gboolean
* WXUNUSED(whatever
),
3827 gpointer
WXUNUSED(user_data
) )
3829 // ensure that the menu appears entirely on screen
3831 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3833 wxSize sizeScreen
= wxGetDisplaySize();
3835 gint xmax
= sizeScreen
.x
- req
.width
,
3836 ymax
= sizeScreen
.y
- req
.height
;
3838 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3839 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3842 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3844 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3846 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3848 SetInvokingWindow( menu
, this );
3854 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3856 bool is_waiting
= TRUE
;
3858 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3860 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3861 (gpointer
)&is_waiting
);
3864 GTK_MENU(menu
->m_menu
),
3865 (GtkWidget
*) NULL
, // parent menu shell
3866 (GtkWidget
*) NULL
, // parent menu item
3867 wxPopupMenuPositionCallback
, // function to position it
3868 NULL
, // client data
3869 0, // button used to activate it
3870 gs_timeLastClick
// the time of activation
3875 while (gtk_events_pending())
3876 gtk_main_iteration();
3882 #endif // wxUSE_MENUS_NATIVE
3884 #if wxUSE_DRAG_AND_DROP
3886 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3888 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3890 GtkWidget
*dnd_widget
= GetConnectWidget();
3892 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3894 if (m_dropTarget
) delete m_dropTarget
;
3895 m_dropTarget
= dropTarget
;
3897 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3900 #endif // wxUSE_DRAG_AND_DROP
3902 GtkWidget
* wxWindowGTK::GetConnectWidget()
3904 GtkWidget
*connect_widget
= m_widget
;
3905 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3907 return connect_widget
;
3910 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3913 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3915 return (window
== m_widget
->window
);
3918 bool wxWindowGTK::SetFont( const wxFont
&font
)
3920 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3922 if (!wxWindowBase::SetFont(font
))
3927 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3928 if ( sysbg
== m_backgroundColour
)
3930 m_backgroundColour
= wxNullColour
;
3932 m_backgroundColour
= sysbg
;
3942 void wxWindowGTK::DoCaptureMouse()
3944 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3946 GdkWindow
*window
= (GdkWindow
*) NULL
;
3948 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3950 window
= GetConnectWidget()->window
;
3952 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3954 wxCursor
* cursor
= & m_cursor
;
3956 cursor
= wxSTANDARD_CURSOR
;
3958 gdk_pointer_grab( window
, FALSE
,
3960 (GDK_BUTTON_PRESS_MASK
|
3961 GDK_BUTTON_RELEASE_MASK
|
3962 GDK_POINTER_MOTION_HINT_MASK
|
3963 GDK_POINTER_MOTION_MASK
),
3965 cursor
->GetCursor(),
3966 (guint32
)GDK_CURRENT_TIME
);
3967 g_captureWindow
= this;
3968 g_captureWindowHasMouse
= TRUE
;
3971 void wxWindowGTK::DoReleaseMouse()
3973 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3975 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3977 g_captureWindow
= (wxWindowGTK
*) NULL
;
3979 GdkWindow
*window
= (GdkWindow
*) NULL
;
3981 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3983 window
= GetConnectWidget()->window
;
3988 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3992 wxWindow
*wxWindowBase::GetCapture()
3994 return (wxWindow
*)g_captureWindow
;
3997 bool wxWindowGTK::IsRetained() const
4002 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4003 int range
, bool refresh
)
4005 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4007 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4009 m_hasScrolling
= TRUE
;
4011 if (orient
== wxHORIZONTAL
)
4013 float fpos
= (float)pos
;
4014 float frange
= (float)range
;
4015 float fthumb
= (float)thumbVisible
;
4016 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4017 if (fpos
< 0.0) fpos
= 0.0;
4019 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4020 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4022 SetScrollPos( orient
, pos
, refresh
);
4026 m_oldHorizontalPos
= fpos
;
4028 m_hAdjust
->lower
= 0.0;
4029 m_hAdjust
->upper
= frange
;
4030 m_hAdjust
->value
= fpos
;
4031 m_hAdjust
->step_increment
= 1.0;
4032 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4033 m_hAdjust
->page_size
= fthumb
;
4037 float fpos
= (float)pos
;
4038 float frange
= (float)range
;
4039 float fthumb
= (float)thumbVisible
;
4040 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4041 if (fpos
< 0.0) fpos
= 0.0;
4043 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4044 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4046 SetScrollPos( orient
, pos
, refresh
);
4050 m_oldVerticalPos
= fpos
;
4052 m_vAdjust
->lower
= 0.0;
4053 m_vAdjust
->upper
= frange
;
4054 m_vAdjust
->value
= fpos
;
4055 m_vAdjust
->step_increment
= 1.0;
4056 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4057 m_vAdjust
->page_size
= fthumb
;
4060 if (orient
== wxHORIZONTAL
)
4061 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4063 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4066 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4068 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4070 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4072 if (orient
== wxHORIZONTAL
)
4074 float fpos
= (float)pos
;
4075 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4076 if (fpos
< 0.0) fpos
= 0.0;
4077 m_oldHorizontalPos
= fpos
;
4079 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4080 m_hAdjust
->value
= fpos
;
4084 float fpos
= (float)pos
;
4085 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4086 if (fpos
< 0.0) fpos
= 0.0;
4087 m_oldVerticalPos
= fpos
;
4089 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4090 m_vAdjust
->value
= fpos
;
4093 if (m_wxwindow
->window
)
4095 if (orient
== wxHORIZONTAL
)
4097 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4098 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4100 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4102 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4103 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4107 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4108 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4110 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4112 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4113 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4118 int wxWindowGTK::GetScrollThumb( int orient
) const
4120 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4122 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4124 if (orient
== wxHORIZONTAL
)
4125 return (int)(m_hAdjust
->page_size
+0.5);
4127 return (int)(m_vAdjust
->page_size
+0.5);
4130 int wxWindowGTK::GetScrollPos( int orient
) const
4132 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4134 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4136 if (orient
== wxHORIZONTAL
)
4137 return (int)(m_hAdjust
->value
+0.5);
4139 return (int)(m_vAdjust
->value
+0.5);
4142 int wxWindowGTK::GetScrollRange( int orient
) const
4144 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4146 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4148 if (orient
== wxHORIZONTAL
)
4149 return (int)(m_hAdjust
->upper
+0.5);
4151 return (int)(m_vAdjust
->upper
+0.5);
4154 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4156 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4158 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4160 // No scrolling requested.
4161 if ((dx
== 0) && (dy
== 0)) return;
4164 if (!m_updateRegion
.IsEmpty())
4166 m_updateRegion
.Offset( dx
, dy
);
4170 GetClientSize( &cw
, &ch
);
4171 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4174 if (!m_clearRegion
.IsEmpty())
4176 m_clearRegion
.Offset( dx
, dy
);
4180 GetClientSize( &cw
, &ch
);
4181 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4183 m_clipPaintRegion
= TRUE
;
4185 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4187 m_clipPaintRegion
= FALSE
;
4190 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4192 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4193 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4200 // Find the wxWindow at the current mouse position, also returning the mouse
4202 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4204 pt
= wxGetMousePosition();
4205 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4209 // Get the current mouse position.
4210 wxPoint
wxGetMousePosition()
4212 /* This crashes when used within wxHelpContext,
4213 so we have to use the X-specific implementation below.
4215 GdkModifierType *mask;
4216 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4218 return wxPoint(x, y);
4222 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4224 return wxPoint(-999, -999);
4226 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4227 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4228 Window rootReturn
, childReturn
;
4229 int rootX
, rootY
, winX
, winY
;
4230 unsigned int maskReturn
;
4232 XQueryPointer (display
,
4236 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4237 return wxPoint(rootX
, rootY
);
4241 // ----------------------------------------------------------------------------
4243 // ----------------------------------------------------------------------------
4245 class wxWinModule
: public wxModule
4252 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4255 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4257 bool wxWinModule::OnInit()
4259 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4260 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4265 void wxWinModule::OnExit()
4268 gdk_gc_unref( g_eraseGC
);