1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "window.h"
16 #define XWarpPointer XWARPPOINTER
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
24 #include "wx/layout.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28 #include "wx/module.h"
30 #if wxUSE_DRAG_AND_DROP
35 #include "wx/tooltip.h"
43 #include "wx/textctrl.h"
47 #include "wx/statusbr.h"
49 #include "wx/settings.h"
53 #include "wx/thread.h"
58 #include "wx/gtk/private.h"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
69 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
71 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
81 extern GtkContainerClass
*pizza_parent_class
;
84 //-----------------------------------------------------------------------------
85 // documentation on internals
86 //-----------------------------------------------------------------------------
89 I have been asked several times about writing some documentation about
90 the GTK port of wxWindows, especially its internal structures. Obviously,
91 you cannot understand wxGTK without knowing a little about the GTK, but
92 some more information about what the wxWindow, which is the base class
93 for all other window classes, does seems required as well.
97 What does wxWindow do? It contains the common interface for the following
98 jobs of its descendants:
100 1) Define the rudimentary behaviour common to all window classes, such as
101 resizing, intercepting user input (so as to make it possible to use these
102 events for special purposes in a derived class), window names etc.
104 2) Provide the possibility to contain and manage children, if the derived
105 class is allowed to contain children, which holds true for those window
106 classes which do not display a native GTK widget. To name them, these
107 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
108 work classes are a special case and are handled a bit differently from
109 the rest. The same holds true for the wxNotebook class.
111 3) Provide the possibility to draw into a client area of a window. This,
112 too, only holds true for classes that do not display a native GTK widget
115 4) Provide the entire mechanism for scrolling widgets. This actual inter-
116 face for this is usually in wxScrolledWindow, but the GTK implementation
119 5) A multitude of helper or extra methods for special purposes, such as
120 Drag'n'Drop, managing validators etc.
122 6) Display a border (sunken, raised, simple or none).
124 Normally one might expect, that one wxWindows window would always correspond
125 to one GTK widget. Under GTK, there is no such allround widget that has all
126 the functionality. Moreover, the GTK defines a client area as a different
127 widget from the actual widget you are handling. Last but not least some
128 special classes (e.g. wxFrame) handle different categories of widgets and
129 still have the possibility to draw something in the client area.
130 It was therefore required to write a special purpose GTK widget, that would
131 represent a client area in the sense of wxWindows capable to do the jobs
132 2), 3) and 4). I have written this class and it resides in win_gtk.c of
135 All windows must have a widget, with which they interact with other under-
136 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
137 thw wxWindow class has a member variable called m_widget which holds a
138 pointer to this widget. When the window class represents a GTK native widget,
139 this is (in most cases) the only GTK widget the class manages. E.g. the
140 wxStatitText class handles only a GtkLabel widget a pointer to which you
141 can find in m_widget (defined in wxWindow)
143 When the class has a client area for drawing into and for containing children
144 it has to handle the client area widget (of the type GtkPizza, defined in
145 win_gtk.c), but there could be any number of widgets, handled by a class
146 The common rule for all windows is only, that the widget that interacts with
147 the rest of GTK must be referenced in m_widget and all other widgets must be
148 children of this widget on the GTK level. The top-most widget, which also
149 represents the client area, must be in the m_wxwindow field and must be of
152 As I said, the window classes that display a GTK native widget only have
153 one widget, so in the case of e.g. the wxButton class m_widget holds a
154 pointer to a GtkButton widget. But windows with client areas (for drawing
155 and children) have a m_widget field that is a pointer to a GtkScrolled-
156 Window and a m_wxwindow field that is pointer to a GtkPizza and this
157 one is (in the GTK sense) a child of the GtkScrolledWindow.
159 If the m_wxwindow field is set, then all input to this widget is inter-
160 cepted and sent to the wxWindows class. If not, all input to the widget
161 that gets pointed to by m_widget gets intercepted and sent to the class.
165 The design of scrolling in wxWindows is markedly different from that offered
166 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
167 clicking on a scrollbar belonging to scrolled window will inevitably move
168 the window. In wxWindows, the scrollbar will only emit an event, send this
169 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
170 which actually moves the window and its subchildren. Note that GtkPizza
171 memorizes how much it has been scrolled but that wxWindows forgets this
172 so that the two coordinates systems have to be kept in synch. This is done
173 in various places using the pizza->xoffset and pizza->yoffset values.
177 Singularily the most broken code in GTK is the code that is supposes to
178 inform subwindows (child windows) about new positions. Very often, duplicate
179 events are sent without changes in size or position, equally often no
180 events are sent at all (All this is due to a bug in the GtkContainer code
181 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
182 GTK's own system and it simply waits for size events for toplevel windows
183 and then iterates down the respective size events to all window. This has
184 the disadvantage, that windows might get size events before the GTK widget
185 actually has the reported size. This doesn't normally pose any problem, but
186 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
187 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
188 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
189 window that is used for OpenGl output really has that size (as reported by
194 If someone at some point of time feels the immense desire to have a look at,
195 change or attempt to optimse the Refresh() logic, this person will need an
196 intimate understanding of what a "draw" and what an "expose" events are and
197 what there are used for, in particular when used in connection with GTK's
198 own windowless widgets. Beware.
202 Cursors, too, have been a constant source of pleasure. The main difficulty
203 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
204 for the parent. To prevent this from doing too much harm, I use idle time
205 to set the cursor over and over again, starting from the toplevel windows
206 and ending with the youngest generation (speaking of parent and child windows).
207 Also don't forget that cursors (like much else) are connected to GdkWindows,
208 not GtkWidgets and that the "window" field of a GtkWidget might very well
209 point to the GdkWindow of the parent widget (-> "window less widget") and
210 that the two obviously have very different meanings.
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 extern wxList wxPendingDelete
;
219 extern bool g_blockEventsOnDrag
;
220 extern bool g_blockEventsOnScroll
;
221 extern wxCursor g_globalCursor
;
223 static GdkGC
*g_eraseGC
= NULL
;
225 // mouse capture state: the window which has it and if the mouse is currently
227 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
228 static bool g_captureWindowHasMouse
= FALSE
;
230 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
232 // the last window which had the focus - this is normally never NULL (except
233 // if we never had focus at all) as even when g_focusWindow is NULL it still
234 // keeps its previous value
235 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
237 // the frame that is currently active (i.e. its child has focus). It is
238 // used to generate wxActivateEvents
239 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
240 static bool g_activeFrameLostFocus
= FALSE
;
242 // If a window get the focus set but has not been realized
243 // yet, defer setting the focus to idle time.
244 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
246 // if we detect that the app has got/lost the focus, we set this variable to
247 // either TRUE or FALSE and an activate event will be sent during the next
248 // OnIdle() call and it is reset to -1: this value means that we shouldn't
249 // send any activate events at all
250 static int g_sendActivateEvent
= -1;
252 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
253 the last click here */
254 static guint32 gs_timeLastClick
= 0;
256 extern bool g_mainThreadLocked
;
258 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
263 #define DISABLE_STYLE_IF_BROKEN_THEME 1
269 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
271 # define DEBUG_MAIN_THREAD
274 #define DEBUG_MAIN_THREAD
277 // the trace mask used for the focus debugging messages
278 #define TRACE_FOCUS _T("focus")
280 //-----------------------------------------------------------------------------
281 // missing gdk functions
282 //-----------------------------------------------------------------------------
285 gdk_window_warp_pointer (GdkWindow
*window
,
290 GdkWindowPrivate
*priv
;
294 window
= GDK_ROOT_PARENT();
297 if (!GDK_WINDOW_DESTROYED(window
))
299 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
300 None
, /* not source window -> move from anywhere */
301 GDK_WINDOW_XID(window
), /* dest window */
302 0, 0, 0, 0, /* not source window -> move from anywhere */
306 priv
= (GdkWindowPrivate
*) window
;
308 if (!priv
->destroyed
)
310 XWarpPointer (priv
->xdisplay
,
311 None
, /* not source window -> move from anywhere */
312 priv
->xwindow
, /* dest window */
313 0, 0, 0, 0, /* not source window -> move from anywhere */
319 //-----------------------------------------------------------------------------
321 //-----------------------------------------------------------------------------
323 extern void wxapp_install_idle_handler();
324 extern bool g_isIdle
;
326 //-----------------------------------------------------------------------------
327 // local code (see below)
328 //-----------------------------------------------------------------------------
330 // returns the child of win which currently has focus or NULL if not found
332 // Note: can't be static, needed by textctrl.cpp.
333 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
335 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
337 return (wxWindow
*)NULL
;
339 if ( winFocus
== win
)
340 return (wxWindow
*)win
;
342 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
344 node
= node
->GetNext() )
346 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
351 return (wxWindow
*)NULL
;
354 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
356 // wxUniversal widgets draw the borders and scrollbars themselves
357 #ifndef __WXUNIVERSAL__
364 if (win
->m_hasScrolling
)
366 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
368 GtkRequisition vscroll_req
;
369 vscroll_req
.width
= 2;
370 vscroll_req
.height
= 2;
371 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
372 (scroll_window
->vscrollbar
, &vscroll_req
);
374 GtkRequisition hscroll_req
;
375 hscroll_req
.width
= 2;
376 hscroll_req
.height
= 2;
377 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
378 (scroll_window
->hscrollbar
, &hscroll_req
);
380 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
382 if (scroll_window
->vscrollbar_visible
)
384 dw
+= vscroll_req
.width
;
385 dw
+= scroll_class
->scrollbar_spacing
;
388 if (scroll_window
->hscrollbar_visible
)
390 dh
+= hscroll_req
.height
;
391 dh
+= scroll_class
->scrollbar_spacing
;
397 if (GTK_WIDGET_NO_WINDOW (widget
))
399 dx
+= widget
->allocation
.x
;
400 dy
+= widget
->allocation
.y
;
403 if (win
->HasFlag(wxRAISED_BORDER
))
405 gtk_draw_shadow( widget
->style
,
410 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
414 if (win
->HasFlag(wxSUNKEN_BORDER
))
416 gtk_draw_shadow( widget
->style
,
421 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
425 if (win
->HasFlag(wxSIMPLE_BORDER
))
428 gc
= gdk_gc_new( widget
->window
);
429 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
430 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
432 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
436 #endif // __WXUNIVERSAL__
439 //-----------------------------------------------------------------------------
440 // "expose_event" of m_widget
441 //-----------------------------------------------------------------------------
443 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
445 if (gdk_event
->count
> 0) return FALSE
;
447 draw_frame( widget
, win
);
451 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
457 //-----------------------------------------------------------------------------
458 // "draw" of m_widget
459 //-----------------------------------------------------------------------------
463 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
465 draw_frame( widget
, win
);
470 //-----------------------------------------------------------------------------
471 // "size_request" of m_widget
472 //-----------------------------------------------------------------------------
474 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
477 win
->GetSize( &w
, &h
);
481 requisition
->height
= h
;
482 requisition
->width
= w
;
485 //-----------------------------------------------------------------------------
486 // "expose_event" of m_wxwindow
487 //-----------------------------------------------------------------------------
489 static int gtk_window_expose_callback( GtkWidget
*widget
,
490 GdkEventExpose
*gdk_event
,
496 wxapp_install_idle_handler();
501 wxPrintf( wxT("OnExpose from ") );
502 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
503 wxPrintf( win
->GetClassInfo()->GetClassName() );
504 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
505 (int)gdk_event
->area
.y
,
506 (int)gdk_event
->area
.width
,
507 (int)gdk_event
->area
.height
);
511 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
513 gdk_event
->area
.width
,
514 gdk_event
->area
.height
);
515 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
517 gdk_event
->area
.width
,
518 gdk_event
->area
.height
);
520 // Actual redrawing takes place in idle time.
525 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
532 //-----------------------------------------------------------------------------
533 // "event" of m_wxwindow
534 //-----------------------------------------------------------------------------
536 // GTK thinks it is clever and filters out a certain amount of "unneeded"
537 // expose events. We need them, of course, so we override the main event
538 // procedure in GtkWidget by giving our own handler for all system events.
539 // There, we look for expose events ourselves whereas all other events are
542 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
543 GdkEventExpose
*event
,
546 if (event
->type
== GDK_EXPOSE
)
548 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
555 //-----------------------------------------------------------------------------
556 // "draw" of m_wxwindow
557 //-----------------------------------------------------------------------------
561 // This callback is a complete replacement of the gtk_pizza_draw() function,
562 // which is disabled.
564 static void gtk_window_draw_callback( GtkWidget
*widget
,
571 wxapp_install_idle_handler();
573 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
574 // there are no child windows.
575 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
576 (win
->GetChildren().GetCount() == 0))
584 wxPrintf( wxT("OnDraw from ") );
585 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
586 wxPrintf( win
->GetClassInfo()->GetClassName() );
587 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
594 #ifndef __WXUNIVERSAL__
595 GtkPizza
*pizza
= GTK_PIZZA (widget
);
597 if (win
->GetThemeEnabled())
599 wxWindow
*parent
= win
->GetParent();
600 while (parent
&& !parent
->IsTopLevel())
601 parent
= parent
->GetParent();
605 gtk_paint_flat_box (parent
->m_widget
->style
,
616 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
617 (pizza
->clear_on_draw
))
619 gdk_window_clear_area( pizza
->bin_window
,
620 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
624 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
626 // Actual redrawing takes place in idle time.
630 #ifndef __WXUNIVERSAL__
631 // Redraw child widgets
632 GList
*children
= pizza
->children
;
635 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
636 children
= children
->next
;
638 GdkRectangle child_area
;
639 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
641 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
649 //-----------------------------------------------------------------------------
650 // "key_press_event" from any window
651 //-----------------------------------------------------------------------------
653 // set WXTRACE to this to see the key event codes on the console
654 #define TRACE_KEYS _T("keyevent")
656 // translates an X key symbol to WXK_XXX value
658 // if isChar is true it means that the value returned will be used for EVT_CHAR
659 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
660 // for example, while if it is false it means that the value is going to be
661 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
663 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
669 // Shift, Control and Alt don't generate the CHAR events at all
672 key_code
= isChar
? 0 : WXK_SHIFT
;
676 key_code
= isChar
? 0 : WXK_CONTROL
;
684 key_code
= isChar
? 0 : WXK_ALT
;
687 // neither do the toggle modifies
688 case GDK_Scroll_Lock
:
689 key_code
= isChar
? 0 : WXK_SCROLL
;
693 key_code
= isChar
? 0 : WXK_CAPITAL
;
697 key_code
= isChar
? 0 : WXK_NUMLOCK
;
701 // various other special keys
714 case GDK_ISO_Left_Tab
:
721 key_code
= WXK_RETURN
;
725 key_code
= WXK_CLEAR
;
729 key_code
= WXK_PAUSE
;
733 key_code
= WXK_SELECT
;
737 key_code
= WXK_PRINT
;
741 key_code
= WXK_EXECUTE
;
745 key_code
= WXK_ESCAPE
;
748 // cursor and other extended keyboard keys
750 key_code
= WXK_DELETE
;
766 key_code
= WXK_RIGHT
;
773 case GDK_Prior
: // == GDK_Page_Up
774 key_code
= WXK_PRIOR
;
777 case GDK_Next
: // == GDK_Page_Down
790 key_code
= WXK_INSERT
;
805 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
809 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
813 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
817 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
821 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
825 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
829 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
833 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
837 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
841 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
845 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
849 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
853 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
856 case GDK_KP_Prior
: // == GDK_KP_Page_Up
857 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
860 case GDK_KP_Next
: // == GDK_KP_Page_Down
861 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
865 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
869 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
873 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
877 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
881 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
884 case GDK_KP_Multiply
:
885 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
889 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
892 case GDK_KP_Separator
:
893 // FIXME: what is this?
894 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
897 case GDK_KP_Subtract
:
898 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
902 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
906 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
923 key_code
= WXK_F1
+ keysym
- GDK_F1
;
933 static inline bool wxIsAsciiKeysym(KeySym ks
)
939 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
941 GdkEventKey
*gdk_event
)
943 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
944 // but only event->keyval which is quite useless to us, so remember
945 // the last character from GDK_KEY_PRESS and reuse it as last resort
947 // NB: should be MT-safe as we're always called from the main thread only
952 } s_lastKeyPress
= { 0, 0 };
954 KeySym keysym
= gdk_event
->keyval
;
956 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %d"),
957 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
961 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
965 // do we have the translation or is it a plain ASCII character?
966 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
968 // we should use keysym if it is ASCII as X does some translations
969 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
970 // which we don't want here (but which we do use for OnChar())
971 if ( !wxIsAsciiKeysym(keysym
) )
973 keysym
= (KeySym
)gdk_event
->string
[0];
976 // we want to always get the same key code when the same key is
977 // pressed regardless of the state of the modifies, i.e. on a
978 // standard US keyboard pressing '5' or '%' ('5' key with
979 // Shift) should result in the same key code in OnKeyDown():
980 // '5' (although OnChar() will get either '5' or '%').
982 // to do it we first translate keysym to keycode (== scan code)
983 // and then back but always using the lower register
984 Display
*dpy
= (Display
*)wxGetDisplay();
985 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
987 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
989 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
991 // use the normalized, i.e. lower register, keysym if we've
993 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
995 // as explained above, we want to have lower register key codes
996 // normally but for the letter keys we want to have the upper ones
998 // NB: don't use XConvertCase() here, we want to do it for letters
1000 key_code
= toupper(key_code
);
1002 else // non ASCII key, what to do?
1004 // by default, ignore it
1007 // but if we have cached information from the last KEY_PRESS
1008 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1011 if ( keysym
== s_lastKeyPress
.keysym
)
1013 key_code
= s_lastKeyPress
.keycode
;
1018 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1020 // remember it to be reused for KEY_UP event later
1021 s_lastKeyPress
.keysym
= keysym
;
1022 s_lastKeyPress
.keycode
= key_code
;
1026 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %d"), key_code
);
1028 // sending unknown key events doesn't really make sense
1032 // now fill all the other fields
1035 GdkModifierType state
;
1036 if (gdk_event
->window
)
1037 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1039 event
.SetTimestamp( gdk_event
->time
);
1040 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1041 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1042 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1043 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1044 event
.m_keyCode
= key_code
;
1045 event
.m_scanCode
= gdk_event
->keyval
;
1046 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1047 event
.m_rawFlags
= 0;
1050 event
.SetEventObject( win
);
1055 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1056 GdkEventKey
*gdk_event
,
1062 wxapp_install_idle_handler();
1066 if (g_blockEventsOnDrag
)
1069 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1070 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1072 // unknown key pressed, ignore (the event would be useless anyhow)
1076 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1081 wxWindowGTK
*ancestor
= win
;
1084 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1087 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1088 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1091 if (ancestor
->IsTopLevel())
1093 ancestor
= ancestor
->GetParent();
1096 #endif // wxUSE_ACCEL
1098 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1099 will only be sent if it is not in an accelerator table. */
1102 KeySym keysym
= gdk_event
->keyval
;
1103 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1106 if ( gdk_event
->length
== 1 )
1108 key_code
= (unsigned char)gdk_event
->string
[0];
1110 else if ( wxIsAsciiKeysym(keysym
) )
1113 key_code
= (unsigned char)keysym
;
1119 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1121 // reuse the same event object, just change its type and use the
1122 // translated keycode instead of the raw one
1123 event
.SetEventType(wxEVT_CHAR
);
1124 event
.m_keyCode
= key_code
;
1126 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1130 /* win is a control: tab can be propagated up */
1132 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1133 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1134 // have this style, yet choose not to process this particular TAB in which
1135 // case TAB must still work as a navigational character
1137 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1139 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1141 wxNavigationKeyEvent new_event
;
1142 new_event
.SetEventObject( win
->GetParent() );
1143 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1144 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1145 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1146 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1147 new_event
.SetCurrentFocus( win
);
1148 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1151 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1153 (gdk_event
->keyval
== GDK_Escape
) )
1155 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1156 new_event
.SetEventObject( win
);
1157 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1161 #if 0 // (GTK_MINOR_VERSION > 0)
1162 /* Pressing F10 will activate the menu bar of the top frame. */
1164 (gdk_event
->keyval
== GDK_F10
) )
1166 wxWindowGTK
*ancestor
= win
;
1169 if (wxIsKindOf(ancestor
,wxFrame
))
1171 wxFrame
*frame
= (wxFrame
*) ancestor
;
1172 wxMenuBar
*menubar
= frame
->GetMenuBar();
1175 wxNode
*node
= menubar
->GetMenus().First();
1178 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1179 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1185 ancestor
= ancestor
->GetParent();
1192 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1199 //-----------------------------------------------------------------------------
1200 // "key_release_event" from any window
1201 //-----------------------------------------------------------------------------
1203 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1204 GdkEventKey
*gdk_event
,
1210 wxapp_install_idle_handler();
1215 if (g_blockEventsOnDrag
)
1218 wxKeyEvent
event( wxEVT_KEY_UP
);
1219 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1221 // unknown key pressed, ignore (the event would be useless anyhow
1225 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1228 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1232 // ============================================================================
1234 // ============================================================================
1236 // init wxMouseEvent with the info from gdk_event
1237 #define InitMouseEvent(win, event, gdk_event) \
1239 event.SetTimestamp( gdk_event->time ); \
1240 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1241 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1242 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1243 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1244 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1245 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1246 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1248 wxPoint pt = win->GetClientAreaOrigin(); \
1249 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1250 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1253 // ----------------------------------------------------------------------------
1254 // mouse event processing helper
1255 // ----------------------------------------------------------------------------
1257 static void AdjustEventButtonState(wxMouseEvent
& event
)
1259 // GDK reports the old state of the button for a button press event, but
1260 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1261 // for a LEFT_DOWN event, not FALSE, so we will invert
1262 // left/right/middleDown for the corresponding click events
1264 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1265 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1266 (event
.GetEventType() == wxEVT_LEFT_UP
))
1268 event
.m_leftDown
= !event
.m_leftDown
;
1272 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1273 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1274 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1276 event
.m_middleDown
= !event
.m_middleDown
;
1280 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1281 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1282 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1284 event
.m_rightDown
= !event
.m_rightDown
;
1289 //-----------------------------------------------------------------------------
1290 // "button_press_event"
1291 //-----------------------------------------------------------------------------
1293 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1298 wxapp_install_idle_handler();
1301 wxPrintf( wxT("1) OnButtonPress from ") );
1302 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1303 wxPrintf( win->GetClassInfo()->GetClassName() );
1304 wxPrintf( wxT(".\n") );
1306 if (!win
->m_hasVMT
) return FALSE
;
1307 if (g_blockEventsOnDrag
) return TRUE
;
1308 if (g_blockEventsOnScroll
) return TRUE
;
1310 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1312 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1314 gtk_widget_grab_focus( win
->m_wxwindow
);
1316 wxPrintf( wxT("GrabFocus from ") );
1317 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1318 wxPrintf( win->GetClassInfo()->GetClassName() );
1319 wxPrintf( wxT(".\n") );
1323 wxEventType event_type
= wxEVT_NULL
;
1325 if (gdk_event
->button
== 1)
1327 switch (gdk_event
->type
)
1329 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1330 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1334 else if (gdk_event
->button
== 2)
1336 switch (gdk_event
->type
)
1338 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1339 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1343 else if (gdk_event
->button
== 3)
1345 switch (gdk_event
->type
)
1347 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1348 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1353 if ( event_type
== wxEVT_NULL
)
1355 // unknown mouse button or click type
1359 wxMouseEvent
event( event_type
);
1360 InitMouseEvent( win
, event
, gdk_event
);
1362 AdjustEventButtonState(event
);
1364 // wxListBox actually get mouse events from the item, so we need to give it
1365 // a chance to correct this
1366 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1368 // Some control don't have their own X window and thus cannot get
1371 if (!g_captureWindow
)
1373 wxCoord x
= event
.m_x
;
1374 wxCoord y
= event
.m_y
;
1375 if (win
->m_wxwindow
)
1377 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1378 x
+= pizza
->xoffset
;
1379 y
+= pizza
->yoffset
;
1382 wxNode
*node
= win
->GetChildren().First();
1385 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1387 node
= node
->Next();
1388 if (!child
->IsShown())
1391 if (child
->m_isStaticBox
)
1393 // wxStaticBox is transparent in the box itself
1394 int xx1
= child
->m_x
;
1395 int yy1
= child
->m_y
;
1396 int xx2
= child
->m_x
+ child
->m_width
;
1397 int yy2
= child
->m_x
+ child
->m_height
;
1400 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1402 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1404 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1406 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1409 event
.m_x
-= child
->m_x
;
1410 event
.m_y
-= child
->m_y
;
1417 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1418 (child
->m_x
<= x
) &&
1419 (child
->m_y
<= y
) &&
1420 (child
->m_x
+child
->m_width
>= x
) &&
1421 (child
->m_y
+child
->m_height
>= y
))
1424 event
.m_x
-= child
->m_x
;
1425 event
.m_y
-= child
->m_y
;
1432 event
.SetEventObject( win
);
1434 gs_timeLastClick
= gdk_event
->time
;
1437 wxPrintf( wxT("2) OnButtonPress from ") );
1438 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1439 wxPrintf( win->GetClassInfo()->GetClassName() );
1440 wxPrintf( wxT(".\n") );
1443 if (win
->GetEventHandler()->ProcessEvent( event
))
1445 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1452 //-----------------------------------------------------------------------------
1453 // "button_release_event"
1454 //-----------------------------------------------------------------------------
1456 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1461 wxapp_install_idle_handler();
1463 if (!win
->m_hasVMT
) return FALSE
;
1464 if (g_blockEventsOnDrag
) return FALSE
;
1465 if (g_blockEventsOnScroll
) return FALSE
;
1467 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1470 printf( "OnButtonRelease from " );
1471 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1472 printf( win->GetClassInfo()->GetClassName() );
1476 wxEventType event_type
= wxEVT_NULL
;
1478 switch (gdk_event
->button
)
1480 case 1: event_type
= wxEVT_LEFT_UP
; break;
1481 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1482 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1483 default: return FALSE
;
1486 wxMouseEvent
event( event_type
);
1487 InitMouseEvent( win
, event
, gdk_event
);
1489 AdjustEventButtonState(event
);
1491 // same wxListBox hack as above
1492 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1494 // Some control don't have their own X window and thus cannot get
1497 if (!g_captureWindow
)
1499 wxCoord x
= event
.m_x
;
1500 wxCoord y
= event
.m_y
;
1501 if (win
->m_wxwindow
)
1503 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1504 x
+= pizza
->xoffset
;
1505 y
+= pizza
->yoffset
;
1508 wxNode
*node
= win
->GetChildren().First();
1511 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1513 node
= node
->Next();
1514 if (!child
->IsShown())
1517 if (child
->m_isStaticBox
)
1519 // wxStaticBox is transparent in the box itself
1520 int xx1
= child
->m_x
;
1521 int yy1
= child
->m_y
;
1522 int xx2
= child
->m_x
+ child
->m_width
;
1523 int yy2
= child
->m_x
+ child
->m_height
;
1526 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1528 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1530 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1532 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1535 event
.m_x
-= child
->m_x
;
1536 event
.m_y
-= child
->m_y
;
1543 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1544 (child
->m_x
<= x
) &&
1545 (child
->m_y
<= y
) &&
1546 (child
->m_x
+child
->m_width
>= x
) &&
1547 (child
->m_y
+child
->m_height
>= y
))
1550 event
.m_x
-= child
->m_x
;
1551 event
.m_y
-= child
->m_y
;
1558 event
.SetEventObject( win
);
1560 if (win
->GetEventHandler()->ProcessEvent( event
))
1562 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1569 //-----------------------------------------------------------------------------
1570 // "motion_notify_event"
1571 //-----------------------------------------------------------------------------
1573 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1574 GdkEventMotion
*gdk_event
,
1580 wxapp_install_idle_handler();
1582 if (!win
->m_hasVMT
) return FALSE
;
1583 if (g_blockEventsOnDrag
) return FALSE
;
1584 if (g_blockEventsOnScroll
) return FALSE
;
1586 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1588 if (gdk_event
->is_hint
)
1592 GdkModifierType state
;
1593 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1599 printf( "OnMotion from " );
1600 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1601 printf( win->GetClassInfo()->GetClassName() );
1605 wxMouseEvent
event( wxEVT_MOTION
);
1606 InitMouseEvent(win
, event
, gdk_event
);
1608 if ( g_captureWindow
)
1610 // synthetize a mouse enter or leave event if needed
1611 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1612 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1613 if ( hasMouse
!= g_captureWindowHasMouse
)
1615 // the mouse changed window
1616 g_captureWindowHasMouse
= hasMouse
;
1618 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1619 : wxEVT_LEAVE_WINDOW
);
1620 InitMouseEvent(win
, event
, gdk_event
);
1621 event
.SetEventObject(win
);
1622 win
->GetEventHandler()->ProcessEvent(event
);
1627 // Some control don't have their own X window and thus cannot get
1630 wxCoord x
= event
.m_x
;
1631 wxCoord y
= event
.m_y
;
1632 if (win
->m_wxwindow
)
1634 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1635 x
+= pizza
->xoffset
;
1636 y
+= pizza
->yoffset
;
1639 wxNode
*node
= win
->GetChildren().First();
1642 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1644 node
= node
->Next();
1645 if (!child
->IsShown())
1648 if (child
->m_isStaticBox
)
1650 // wxStaticBox is transparent in the box itself
1651 int xx1
= child
->m_x
;
1652 int yy1
= child
->m_y
;
1653 int xx2
= child
->m_x
+ child
->m_width
;
1654 int yy2
= child
->m_x
+ child
->m_height
;
1657 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1659 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1661 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1663 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1666 event
.m_x
-= child
->m_x
;
1667 event
.m_y
-= child
->m_y
;
1674 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1675 (child
->m_x
<= x
) &&
1676 (child
->m_y
<= y
) &&
1677 (child
->m_x
+child
->m_width
>= x
) &&
1678 (child
->m_y
+child
->m_height
>= y
))
1681 event
.m_x
-= child
->m_x
;
1682 event
.m_y
-= child
->m_y
;
1689 event
.SetEventObject( win
);
1691 if (win
->GetEventHandler()->ProcessEvent( event
))
1693 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1700 //-----------------------------------------------------------------------------
1702 //-----------------------------------------------------------------------------
1704 // send the wxChildFocusEvent and wxFocusEvent, common code of
1705 // gtk_window_focus_in_callback() and SetFocus()
1706 static bool DoSendFocusEvents(wxWindow
*win
)
1708 // Notify the parent keeping track of focus for the kbd navigation
1709 // purposes that we got it.
1710 wxChildFocusEvent
eventChildFocus(win
);
1711 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1713 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1714 eventFocus
.SetEventObject(win
);
1716 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1719 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1720 GdkEvent
*WXUNUSED(event
),
1726 wxapp_install_idle_handler();
1728 if (!win
->m_hasVMT
) return FALSE
;
1729 if (g_blockEventsOnDrag
) return FALSE
;
1731 switch ( g_sendActivateEvent
)
1734 // we've got focus from outside, synthetize wxActivateEvent
1735 g_sendActivateEvent
= 1;
1739 // another our window just lost focus, it was already ours before
1740 // - don't send any wxActivateEvent
1741 g_sendActivateEvent
= -1;
1746 g_focusWindow
= win
;
1748 wxLogTrace(TRACE_FOCUS
,
1749 _T("%s: focus in"), win
->GetName().c_str());
1753 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1757 // caret needs to be informed about focus change
1758 wxCaret
*caret
= win
->GetCaret();
1761 caret
->OnSetFocus();
1763 #endif // wxUSE_CARET
1765 g_activeFrameLostFocus
= FALSE
;
1767 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1768 if ( active
!= g_activeFrame
)
1770 if ( g_activeFrame
)
1772 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1773 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1774 event
.SetEventObject(g_activeFrame
);
1775 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1778 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1779 g_activeFrame
= active
;
1780 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1781 event
.SetEventObject(g_activeFrame
);
1782 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1784 // Don't send focus events in addition to activate
1785 // if (win == g_activeFrame)
1789 // does the window itself think that it has the focus?
1790 if ( !win
->m_hasFocus
)
1792 // not yet, notify it
1793 win
->m_hasFocus
= TRUE
;
1795 if ( DoSendFocusEvents(win
) )
1797 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1805 //-----------------------------------------------------------------------------
1806 // "focus_out_event"
1807 //-----------------------------------------------------------------------------
1809 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1814 wxapp_install_idle_handler();
1816 if (!win
->m_hasVMT
) return FALSE
;
1817 if (g_blockEventsOnDrag
) return FALSE
;
1819 wxLogTrace( TRACE_FOCUS
,
1820 _T("%s: focus out"), win
->GetName().c_str() );
1822 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1824 // VZ: commenting this out because it does happen (although not easy
1825 // to reproduce, I only see it when using wxMiniFrame and not
1826 // always) and makes using Mahogany quite annoying
1828 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1829 wxT("unfocusing window that hasn't gained focus properly") )
1832 g_activeFrameLostFocus
= TRUE
;
1835 // if the focus goes out of our app alltogether, OnIdle() will send
1836 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1837 // g_sendActivateEvent to -1
1838 g_sendActivateEvent
= 0;
1840 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1844 g_focusWindow
= (wxWindowGTK
*)NULL
;
1852 // caret needs to be informed about focus change
1853 wxCaret
*caret
= win
->GetCaret();
1856 caret
->OnKillFocus();
1858 #endif // wxUSE_CARET
1860 // don't send the window a kill focus event if it thinks that it doesn't
1861 // have focus already
1862 if ( win
->m_hasFocus
)
1864 win
->m_hasFocus
= FALSE
;
1866 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1867 event
.SetEventObject( win
);
1869 if (win
->GetEventHandler()->ProcessEvent( event
))
1871 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1879 //-----------------------------------------------------------------------------
1880 // "enter_notify_event"
1881 //-----------------------------------------------------------------------------
1883 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1888 wxapp_install_idle_handler();
1890 if (!win
->m_hasVMT
) return FALSE
;
1891 if (g_blockEventsOnDrag
) return FALSE
;
1893 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1895 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1896 event
.SetTimestamp( gdk_event
->time
);
1897 event
.SetEventObject( win
);
1901 GdkModifierType state
= (GdkModifierType
)0;
1903 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1905 InitMouseEvent(win
, event
, gdk_event
);
1906 wxPoint pt
= win
->GetClientAreaOrigin();
1907 event
.m_x
= x
+ pt
.x
;
1908 event
.m_y
= y
+ pt
.y
;
1910 if (win
->GetEventHandler()->ProcessEvent( event
))
1912 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1919 //-----------------------------------------------------------------------------
1920 // "leave_notify_event"
1921 //-----------------------------------------------------------------------------
1923 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1928 wxapp_install_idle_handler();
1930 if (!win
->m_hasVMT
) return FALSE
;
1931 if (g_blockEventsOnDrag
) return FALSE
;
1933 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1935 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1936 event
.SetTimestamp( gdk_event
->time
);
1937 event
.SetEventObject( win
);
1941 GdkModifierType state
= (GdkModifierType
)0;
1943 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1945 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1946 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1947 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1948 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1949 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1950 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1951 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1953 wxPoint pt
= win
->GetClientAreaOrigin();
1954 event
.m_x
= x
+ pt
.x
;
1955 event
.m_y
= y
+ pt
.y
;
1957 if (win
->GetEventHandler()->ProcessEvent( event
))
1959 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1966 //-----------------------------------------------------------------------------
1967 // "value_changed" from m_vAdjust
1968 //-----------------------------------------------------------------------------
1970 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1977 wxapp_install_idle_handler();
1979 if (g_blockEventsOnDrag
) return;
1981 if (!win
->m_hasVMT
) return;
1983 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1984 if (fabs(diff
) < 0.2) return;
1986 win
->m_oldVerticalPos
= adjust
->value
;
1988 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1989 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
1991 int value
= (int)(adjust
->value
+0.5);
1993 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1994 event
.SetEventObject( win
);
1995 win
->GetEventHandler()->ProcessEvent( event
);
1998 //-----------------------------------------------------------------------------
1999 // "value_changed" from m_hAdjust
2000 //-----------------------------------------------------------------------------
2002 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2009 wxapp_install_idle_handler();
2011 if (g_blockEventsOnDrag
) return;
2012 if (!win
->m_hasVMT
) return;
2014 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2015 if (fabs(diff
) < 0.2) return;
2017 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2018 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2020 win
->m_oldHorizontalPos
= adjust
->value
;
2022 int value
= (int)(adjust
->value
+0.5);
2024 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2025 event
.SetEventObject( win
);
2026 win
->GetEventHandler()->ProcessEvent( event
);
2029 //-----------------------------------------------------------------------------
2030 // "button_press_event" from scrollbar
2031 //-----------------------------------------------------------------------------
2033 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2034 GdkEventButton
*gdk_event
,
2040 wxapp_install_idle_handler();
2043 g_blockEventsOnScroll
= TRUE
;
2045 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2047 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2053 //-----------------------------------------------------------------------------
2054 // "button_release_event" from scrollbar
2055 //-----------------------------------------------------------------------------
2057 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2058 GdkEventButton
*WXUNUSED(gdk_event
),
2063 // don't test here as we can release the mouse while being over
2064 // a different window than the slider
2066 // if (gdk_event->window != widget->slider) return FALSE;
2068 g_blockEventsOnScroll
= FALSE
;
2070 if (win
->m_isScrolling
)
2072 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2076 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2077 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2079 value
= (int)(win
->m_hAdjust
->value
+0.5);
2082 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2084 value
= (int)(win
->m_vAdjust
->value
+0.5);
2088 wxScrollWinEvent
event( command
, value
, dir
);
2089 event
.SetEventObject( win
);
2090 win
->GetEventHandler()->ProcessEvent( event
);
2093 win
->m_isScrolling
= FALSE
;
2098 // ----------------------------------------------------------------------------
2099 // this wxWindowBase function is implemented here (in platform-specific file)
2100 // because it is static and so couldn't be made virtual
2101 // ----------------------------------------------------------------------------
2103 wxWindow
*wxWindowBase::FindFocus()
2105 // the cast is necessary when we compile in wxUniversal mode
2106 return (wxWindow
*)g_focusWindow
;
2109 //-----------------------------------------------------------------------------
2110 // "realize" from m_widget
2111 //-----------------------------------------------------------------------------
2113 /* We cannot set colours and fonts before the widget has
2114 been realized, so we do this directly after realization. */
2117 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2122 wxapp_install_idle_handler();
2124 if (win
->m_delayedBackgroundColour
)
2125 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2127 if (win
->m_delayedForegroundColour
)
2128 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2130 wxWindowCreateEvent
event( win
);
2131 event
.SetEventObject( win
);
2132 win
->GetEventHandler()->ProcessEvent( event
);
2137 //-----------------------------------------------------------------------------
2139 //-----------------------------------------------------------------------------
2142 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2143 GtkAllocation
*WXUNUSED(alloc
),
2147 wxapp_install_idle_handler();
2149 if (!win
->m_hasScrolling
) return;
2151 int client_width
= 0;
2152 int client_height
= 0;
2153 win
->GetClientSize( &client_width
, &client_height
);
2154 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2157 win
->m_oldClientWidth
= client_width
;
2158 win
->m_oldClientHeight
= client_height
;
2160 if (!win
->m_nativeSizeEvent
)
2162 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2163 event
.SetEventObject( win
);
2164 win
->GetEventHandler()->ProcessEvent( event
);
2170 #define WXUNUSED_UNLESS_XIM(param) param
2172 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2175 /* Resize XIM window */
2178 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2179 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2180 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2183 wxapp_install_idle_handler();
2189 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2193 gdk_window_get_size (widget
->window
, &width
, &height
);
2194 win
->m_icattr
->preedit_area
.width
= width
;
2195 win
->m_icattr
->preedit_area
.height
= height
;
2196 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2201 //-----------------------------------------------------------------------------
2202 // "realize" from m_wxwindow
2203 //-----------------------------------------------------------------------------
2205 /* Initialize XIM support */
2208 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2209 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2212 wxapp_install_idle_handler();
2215 if (win
->m_ic
) return FALSE
;
2216 if (!widget
) return FALSE
;
2217 if (!gdk_im_ready()) return FALSE
;
2219 win
->m_icattr
= gdk_ic_attr_new();
2220 if (!win
->m_icattr
) return FALSE
;
2224 GdkColormap
*colormap
;
2225 GdkICAttr
*attr
= win
->m_icattr
;
2226 unsigned attrmask
= GDK_IC_ALL_REQ
;
2228 GdkIMStyle supported_style
= (GdkIMStyle
)
2229 (GDK_IM_PREEDIT_NONE
|
2230 GDK_IM_PREEDIT_NOTHING
|
2231 GDK_IM_PREEDIT_POSITION
|
2232 GDK_IM_STATUS_NONE
|
2233 GDK_IM_STATUS_NOTHING
);
2235 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2236 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2238 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2239 attr
->client_window
= widget
->window
;
2241 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2242 gtk_widget_get_default_colormap ())
2244 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2245 attr
->preedit_colormap
= colormap
;
2248 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2249 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2250 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2251 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2253 switch (style
& GDK_IM_PREEDIT_MASK
)
2255 case GDK_IM_PREEDIT_POSITION
:
2256 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2258 g_warning ("over-the-spot style requires fontset");
2262 gdk_window_get_size (widget
->window
, &width
, &height
);
2264 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2265 attr
->spot_location
.x
= 0;
2266 attr
->spot_location
.y
= height
;
2267 attr
->preedit_area
.x
= 0;
2268 attr
->preedit_area
.y
= 0;
2269 attr
->preedit_area
.width
= width
;
2270 attr
->preedit_area
.height
= height
;
2271 attr
->preedit_fontset
= widget
->style
->font
;
2276 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2278 if (win
->m_ic
== NULL
)
2279 g_warning ("Can't create input context.");
2282 mask
= gdk_window_get_events (widget
->window
);
2283 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2284 gdk_window_set_events (widget
->window
, mask
);
2286 if (GTK_WIDGET_HAS_FOCUS(widget
))
2287 gdk_im_begin (win
->m_ic
, widget
->window
);
2294 //-----------------------------------------------------------------------------
2295 // InsertChild for wxWindowGTK.
2296 //-----------------------------------------------------------------------------
2298 /* Callback for wxWindowGTK. This very strange beast has to be used because
2299 * C++ has no virtual methods in a constructor. We have to emulate a
2300 * virtual function here as wxNotebook requires a different way to insert
2301 * a child in it. I had opted for creating a wxNotebookPage window class
2302 * which would have made this superfluous (such in the MDI window system),
2303 * but no-one was listening to me... */
2305 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2307 /* the window might have been scrolled already, do we
2308 have to adapt the position */
2309 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2310 child
->m_x
+= pizza
->xoffset
;
2311 child
->m_y
+= pizza
->yoffset
;
2313 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2314 GTK_WIDGET(child
->m_widget
),
2321 //-----------------------------------------------------------------------------
2323 //-----------------------------------------------------------------------------
2325 wxWindow
*wxGetActiveWindow()
2327 return wxWindow::FindFocus();
2330 //-----------------------------------------------------------------------------
2332 //-----------------------------------------------------------------------------
2334 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2336 #ifdef __WXUNIVERSAL__
2337 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2339 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2340 #endif // __WXUNIVERSAL__/__WXGTK__
2342 void wxWindowGTK::Init()
2348 m_widget
= (GtkWidget
*) NULL
;
2349 m_wxwindow
= (GtkWidget
*) NULL
;
2350 m_focusWidget
= (GtkWidget
*) NULL
;
2360 m_needParent
= TRUE
;
2361 m_isBeingDeleted
= FALSE
;
2364 m_nativeSizeEvent
= FALSE
;
2366 m_hasScrolling
= FALSE
;
2367 m_isScrolling
= FALSE
;
2369 m_hAdjust
= (GtkAdjustment
*) NULL
;
2370 m_vAdjust
= (GtkAdjustment
*) NULL
;
2371 m_oldHorizontalPos
= 0.0;
2372 m_oldVerticalPos
= 0.0;
2375 m_widgetStyle
= (GtkStyle
*) NULL
;
2377 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2379 m_isStaticBox
= FALSE
;
2380 m_isRadioButton
= FALSE
;
2382 m_acceptsFocus
= FALSE
;
2385 m_clipPaintRegion
= FALSE
;
2387 m_cursor
= *wxSTANDARD_CURSOR
;
2389 m_delayedForegroundColour
= FALSE
;
2390 m_delayedBackgroundColour
= FALSE
;
2393 m_ic
= (GdkIC
*) NULL
;
2394 m_icattr
= (GdkICAttr
*) NULL
;
2398 wxWindowGTK::wxWindowGTK()
2403 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2408 const wxString
&name
)
2412 Create( parent
, id
, pos
, size
, style
, name
);
2415 bool wxWindowGTK::Create( wxWindow
*parent
,
2420 const wxString
&name
)
2422 if (!PreCreation( parent
, pos
, size
) ||
2423 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2425 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2429 m_insertCallback
= wxInsertChildInWindow
;
2431 // always needed for background clearing
2432 m_delayedBackgroundColour
= TRUE
;
2434 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2435 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2437 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2439 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2440 scroll_class
->scrollbar_spacing
= 0;
2442 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2444 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2445 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2447 m_wxwindow
= gtk_pizza_new();
2449 #ifndef __WXUNIVERSAL__
2450 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2452 if (HasFlag(wxRAISED_BORDER
))
2454 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2456 else if (HasFlag(wxSUNKEN_BORDER
))
2458 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2460 else if (HasFlag(wxSIMPLE_BORDER
))
2462 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2466 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2468 #endif // __WXUNIVERSAL__
2470 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2472 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2473 m_acceptsFocus
= TRUE
;
2475 // I _really_ don't want scrollbars in the beginning
2476 m_vAdjust
->lower
= 0.0;
2477 m_vAdjust
->upper
= 1.0;
2478 m_vAdjust
->value
= 0.0;
2479 m_vAdjust
->step_increment
= 1.0;
2480 m_vAdjust
->page_increment
= 1.0;
2481 m_vAdjust
->page_size
= 5.0;
2482 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2483 m_hAdjust
->lower
= 0.0;
2484 m_hAdjust
->upper
= 1.0;
2485 m_hAdjust
->value
= 0.0;
2486 m_hAdjust
->step_increment
= 1.0;
2487 m_hAdjust
->page_increment
= 1.0;
2488 m_hAdjust
->page_size
= 5.0;
2489 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2491 // these handlers block mouse events to any window during scrolling such as
2492 // motion events and prevent GTK and wxWindows from fighting over where the
2495 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2496 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2498 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2499 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2501 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2502 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2504 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2505 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2507 // these handlers get notified when screen updates are required either when
2508 // scrolling or when the window size (and therefore scrollbar configuration)
2511 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2512 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2513 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2514 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2516 gtk_widget_show( m_wxwindow
);
2519 m_parent
->DoAddChild( this );
2521 m_focusWidget
= m_wxwindow
;
2530 wxWindowGTK::~wxWindowGTK()
2532 if (g_focusWindow
== this)
2533 g_focusWindow
= NULL
;
2535 if (g_activeFrame
== this)
2536 g_activeFrame
= NULL
;
2538 if ( g_delayedFocus
== this )
2539 g_delayedFocus
= NULL
;
2541 m_isBeingDeleted
= TRUE
;
2550 m_parent
->RemoveChild( this );
2554 gdk_ic_destroy (m_ic
);
2556 gdk_ic_attr_destroy (m_icattr
);
2561 #if DISABLE_STYLE_IF_BROKEN_THEME
2562 // don't delete if it's a pixmap theme style
2563 if (!m_widgetStyle
->engine_data
)
2564 gtk_style_unref( m_widgetStyle
);
2566 m_widgetStyle
= (GtkStyle
*) NULL
;
2571 gtk_widget_destroy( m_wxwindow
);
2572 m_wxwindow
= (GtkWidget
*) NULL
;
2577 gtk_widget_destroy( m_widget
);
2578 m_widget
= (GtkWidget
*) NULL
;
2582 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2584 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2586 /* this turns -1 into 20 so that a minimal window is
2587 visible even although -1,-1 has been given as the
2588 size of the window. the same trick is used in other
2589 ports and should make debugging easier */
2590 m_width
= WidthDefault(size
.x
);
2591 m_height
= HeightDefault(size
.y
);
2596 /* some reasonable defaults */
2601 m_x
= (gdk_screen_width () - m_width
) / 2;
2602 if (m_x
< 10) m_x
= 10;
2606 m_y
= (gdk_screen_height () - m_height
) / 2;
2607 if (m_y
< 10) m_y
= 10;
2614 void wxWindowGTK::PostCreation()
2616 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2622 // these get reported to wxWindows -> wxPaintEvent
2624 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2626 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2627 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2630 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2631 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2633 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2635 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2636 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2639 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2643 // these are called when the "sunken" or "raised" borders are drawn
2644 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2645 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2648 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2649 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2655 if (m_focusWidget
== NULL
)
2656 m_focusWidget
= m_widget
;
2658 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2659 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2661 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2662 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2664 // connect to the various key and mouse handlers
2666 GtkWidget
*connect_widget
= GetConnectWidget();
2668 ConnectWidget( connect_widget
);
2670 /* We cannot set colours, fonts and cursors before the widget has
2671 been realized, so we do this directly after realization */
2672 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2673 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2677 // Catch native resize events
2678 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2679 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2681 // Initialize XIM support
2682 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2683 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2685 // And resize XIM window
2686 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2687 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2690 if (!GTK_IS_COMBO(m_widget
))
2692 // This is needed if we want to add our windows into native
2693 // GTK control, such as the toolbar. With this callback, the
2694 // toolbar gets to know the correct size (the one set by the
2695 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2696 // when moving to GTK 2.0.
2697 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2698 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2704 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2706 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2707 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2709 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2710 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2712 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2713 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2715 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2716 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2718 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2719 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2721 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2722 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2724 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2725 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2728 bool wxWindowGTK::Destroy()
2730 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2734 return wxWindowBase::Destroy();
2737 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2739 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2742 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2744 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2745 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2748 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2751 if (m_resizing
) return; /* I don't like recursions */
2754 int currentX
, currentY
;
2755 GetPosition(¤tX
, ¤tY
);
2760 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2762 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2764 /* don't set the size for children of wxNotebook, just take the values. */
2772 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2773 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2775 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2776 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2777 if (width
!= -1) m_width
= width
;
2778 if (height
!= -1) m_height
= height
;
2782 m_x
= x
+ pizza
->xoffset
;
2783 m_y
= y
+ pizza
->yoffset
;
2788 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2790 if (width
== -1) m_width
= 80;
2793 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2795 if (height
== -1) m_height
= 26;
2798 int minWidth
= GetMinWidth(),
2799 minHeight
= GetMinHeight(),
2800 maxWidth
= GetMaxWidth(),
2801 maxHeight
= GetMaxHeight();
2803 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2804 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2805 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2806 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2809 int bottom_border
= 0;
2812 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2814 /* the default button has a border around it */
2820 DoMoveWindow( m_x
-border
,
2823 m_height
+border
+bottom_border
);
2828 /* Sometimes the client area changes size without the
2829 whole windows's size changing, but if the whole
2830 windows's size doesn't change, no wxSizeEvent will
2831 normally be sent. Here we add an extra test if
2832 the client test has been changed and this will
2834 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2838 wxPrintf( "OnSize sent from " );
2839 if (GetClassInfo() && GetClassInfo()->GetClassName())
2840 wxPrintf( GetClassInfo()->GetClassName() );
2841 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2844 if (!m_nativeSizeEvent
)
2846 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2847 event
.SetEventObject( this );
2848 GetEventHandler()->ProcessEvent( event
);
2854 void wxWindowGTK::OnInternalIdle()
2856 // Update invalidated regions.
2859 // Synthetize activate events.
2860 if ( g_sendActivateEvent
!= -1 )
2862 bool activate
= g_sendActivateEvent
!= 0;
2865 g_sendActivateEvent
= -1;
2867 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2870 if ( g_activeFrameLostFocus
)
2872 if ( g_activeFrame
)
2874 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2875 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2876 event
.SetEventObject(g_activeFrame
);
2877 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2878 g_activeFrame
= NULL
;
2880 g_activeFrameLostFocus
= FALSE
;
2883 wxCursor cursor
= m_cursor
;
2884 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2888 /* I now set the cursor anew in every OnInternalIdle call
2889 as setting the cursor in a parent window also effects the
2890 windows above so that checking for the current cursor is
2895 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2897 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2899 if (!g_globalCursor
.Ok())
2900 cursor
= *wxSTANDARD_CURSOR
;
2902 window
= m_widget
->window
;
2903 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2904 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2910 GdkWindow
*window
= m_widget
->window
;
2911 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2912 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2920 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2922 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2924 if (width
) (*width
) = m_width
;
2925 if (height
) (*height
) = m_height
;
2928 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2930 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2934 SetSize( width
, height
);
2941 #ifndef __WXUNIVERSAL__
2942 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2944 /* when using GTK 1.2 we set the shadow border size to 2 */
2948 if (HasFlag(wxSIMPLE_BORDER
))
2950 /* when using GTK 1.2 we set the simple border size to 1 */
2954 #endif // __WXUNIVERSAL__
2958 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2960 GtkRequisition vscroll_req
;
2961 vscroll_req
.width
= 2;
2962 vscroll_req
.height
= 2;
2963 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2964 (scroll_window
->vscrollbar
, &vscroll_req
);
2966 GtkRequisition hscroll_req
;
2967 hscroll_req
.width
= 2;
2968 hscroll_req
.height
= 2;
2969 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2970 (scroll_window
->hscrollbar
, &hscroll_req
);
2972 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2974 if (scroll_window
->vscrollbar_visible
)
2976 dw
+= vscroll_req
.width
;
2977 dw
+= scroll_class
->scrollbar_spacing
;
2980 if (scroll_window
->hscrollbar_visible
)
2982 dh
+= hscroll_req
.height
;
2983 dh
+= scroll_class
->scrollbar_spacing
;
2987 SetSize( width
+dw
, height
+dh
);
2991 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2993 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2997 if (width
) (*width
) = m_width
;
2998 if (height
) (*height
) = m_height
;
3005 #ifndef __WXUNIVERSAL__
3006 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3008 /* when using GTK 1.2 we set the shadow border size to 2 */
3012 if (HasFlag(wxSIMPLE_BORDER
))
3014 /* when using GTK 1.2 we set the simple border size to 1 */
3018 #endif // __WXUNIVERSAL__
3022 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3024 GtkRequisition vscroll_req
;
3025 vscroll_req
.width
= 2;
3026 vscroll_req
.height
= 2;
3027 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3028 (scroll_window
->vscrollbar
, &vscroll_req
);
3030 GtkRequisition hscroll_req
;
3031 hscroll_req
.width
= 2;
3032 hscroll_req
.height
= 2;
3033 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3034 (scroll_window
->hscrollbar
, &hscroll_req
);
3036 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3038 if (scroll_window
->vscrollbar_visible
)
3040 dw
+= vscroll_req
.width
;
3041 dw
+= scroll_class
->scrollbar_spacing
;
3044 if (scroll_window
->hscrollbar_visible
)
3046 dh
+= hscroll_req
.height
;
3047 dh
+= scroll_class
->scrollbar_spacing
;
3051 if (width
) (*width
) = m_width
- dw
;
3052 if (height
) (*height
) = m_height
- dh
;
3056 printf( "GetClientSize, name %s ", GetName().c_str() );
3057 if (width) printf( " width = %d", (*width) );
3058 if (height) printf( " height = %d", (*height) );
3063 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3065 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3069 if (m_parent
&& m_parent
->m_wxwindow
)
3071 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3072 dx
= pizza
->xoffset
;
3073 dy
= pizza
->yoffset
;
3076 if (x
) (*x
) = m_x
- dx
;
3077 if (y
) (*y
) = m_y
- dy
;
3080 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3082 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3084 if (!m_widget
->window
) return;
3086 GdkWindow
*source
= (GdkWindow
*) NULL
;
3088 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3090 source
= m_widget
->window
;
3094 gdk_window_get_origin( source
, &org_x
, &org_y
);
3098 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3100 org_x
+= m_widget
->allocation
.x
;
3101 org_y
+= m_widget
->allocation
.y
;
3109 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3111 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3113 if (!m_widget
->window
) return;
3115 GdkWindow
*source
= (GdkWindow
*) NULL
;
3117 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3119 source
= m_widget
->window
;
3123 gdk_window_get_origin( source
, &org_x
, &org_y
);
3127 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3129 org_x
+= m_widget
->allocation
.x
;
3130 org_y
+= m_widget
->allocation
.y
;
3138 bool wxWindowGTK::Show( bool show
)
3140 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3142 if (!wxWindowBase::Show(show
))
3149 gtk_widget_show( m_widget
);
3151 gtk_widget_hide( m_widget
);
3156 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3158 win
->OnParentEnable(enable
);
3160 // Recurse, so that children have the opportunity to Do The Right Thing
3161 // and reset colours that have been messed up by a parent's (really ancestor's)
3163 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3165 node
= node
->GetNext() )
3167 wxWindow
*child
= node
->GetData();
3168 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3169 wxWindowNotifyEnable(child
, enable
);
3173 bool wxWindowGTK::Enable( bool enable
)
3175 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3177 if (!wxWindowBase::Enable(enable
))
3183 gtk_widget_set_sensitive( m_widget
, enable
);
3185 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3187 wxWindowNotifyEnable(this, enable
);
3192 int wxWindowGTK::GetCharHeight() const
3194 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3196 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3198 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3200 return font
->ascent
+ font
->descent
;
3203 int wxWindowGTK::GetCharWidth() const
3205 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3207 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3209 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3211 return gdk_string_width( font
, "H" );
3214 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3218 int *externalLeading
,
3219 const wxFont
*theFont
) const
3221 wxFont fontToUse
= m_font
;
3222 if (theFont
) fontToUse
= *theFont
;
3224 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3226 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3227 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3228 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3229 if (descent
) (*descent
) = font
->descent
;
3230 if (externalLeading
) (*externalLeading
) = 0; // ??
3233 void wxWindowGTK::SetFocus()
3235 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3239 // don't do anything if we already have focus
3245 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3247 gtk_widget_grab_focus (m_wxwindow
);
3252 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3254 if (!GTK_WIDGET_REALIZED(m_widget
))
3256 // we can't set the focus to the widget now so we remember that
3257 // it should be focused and will do it later, during the idle
3258 // time, as soon as we can
3259 wxLogTrace(TRACE_FOCUS
,
3260 _T("Delaying setting focus to %s(%s)"),
3261 GetClassInfo()->GetClassName(), GetLabel().c_str());
3263 g_delayedFocus
= this;
3267 wxLogTrace(TRACE_FOCUS
,
3268 _T("Setting focus to %s(%s)"),
3269 GetClassInfo()->GetClassName(), GetLabel().c_str());
3271 gtk_widget_grab_focus (m_widget
);
3274 else if (GTK_IS_CONTAINER(m_widget
))
3276 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3280 wxLogTrace(TRACE_FOCUS
,
3281 _T("Can't set focus to %s(%s)"),
3282 GetClassInfo()->GetClassName(), GetLabel().c_str());
3287 bool wxWindowGTK::AcceptsFocus() const
3289 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3292 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3294 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3296 wxWindowGTK
*oldParent
= m_parent
,
3297 *newParent
= (wxWindowGTK
*)newParentBase
;
3299 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3301 if ( !wxWindowBase::Reparent(newParent
) )
3304 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3306 /* prevent GTK from deleting the widget arbitrarily */
3307 gtk_widget_ref( m_widget
);
3311 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3314 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3318 /* insert GTK representation */
3319 (*(newParent
->m_insertCallback
))(newParent
, this);
3322 /* reverse: prevent GTK from deleting the widget arbitrarily */
3323 gtk_widget_unref( m_widget
);
3328 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3330 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3332 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3334 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3339 /* insert GTK representation */
3340 (*m_insertCallback
)(this, child
);
3343 void wxWindowGTK::Raise()
3345 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3347 if (!m_widget
->window
) return;
3349 gdk_window_raise( m_widget
->window
);
3352 void wxWindowGTK::Lower()
3354 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3356 if (!m_widget
->window
) return;
3358 gdk_window_lower( m_widget
->window
);
3361 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3363 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3365 if (cursor
== m_cursor
)
3369 wxapp_install_idle_handler();
3371 if (cursor
== wxNullCursor
)
3372 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3374 return wxWindowBase::SetCursor( cursor
);
3377 void wxWindowGTK::WarpPointer( int x
, int y
)
3379 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3381 // We provide this function ourselves as it is
3382 // missing in GDK (top of this file).
3384 GdkWindow
*window
= (GdkWindow
*) NULL
;
3386 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3388 window
= GetConnectWidget()->window
;
3391 gdk_window_warp_pointer( window
, x
, y
);
3394 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3396 if (!m_widget
) return;
3397 if (!m_widget
->window
) return;
3401 wxapp_install_idle_handler();
3403 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3407 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3408 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3412 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3413 m_clearRegion
.Clear();
3414 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3422 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3423 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3427 GdkRectangle gdk_rect
;
3428 gdk_rect
.x
= rect
->x
;
3429 gdk_rect
.y
= rect
->y
;
3430 gdk_rect
.width
= rect
->width
;
3431 gdk_rect
.height
= rect
->height
;
3432 gtk_widget_draw( m_widget
, &gdk_rect
);
3439 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3440 m_updateRegion
.Clear();
3441 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3445 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3453 GdkRectangle gdk_rect
;
3454 gdk_rect
.x
= rect
->x
;
3455 gdk_rect
.y
= rect
->y
;
3456 gdk_rect
.width
= rect
->width
;
3457 gdk_rect
.height
= rect
->height
;
3458 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3462 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3468 void wxWindowGTK::Update()
3473 void wxWindowGTK::GtkUpdate()
3476 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3477 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3480 if (!m_updateRegion
.IsEmpty())
3481 GtkSendPaintEvents();
3484 void wxWindowGTK::GtkSendPaintEvents()
3488 m_clearRegion
.Clear();
3489 m_updateRegion
.Clear();
3493 // widget to draw on
3494 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3496 // Clip to paint region in wxClientDC
3497 m_clipPaintRegion
= TRUE
;
3499 if (GetThemeEnabled())
3501 // find ancestor from which to steal background
3502 wxWindow
*parent
= GetParent();
3503 while (parent
&& !parent
->IsTopLevel())
3504 parent
= parent
->GetParent();
3506 parent
= (wxWindow
*)this;
3508 wxRegionIterator
upd( m_updateRegion
);
3512 rect
.x
= upd
.GetX();
3513 rect
.y
= upd
.GetY();
3514 rect
.width
= upd
.GetWidth();
3515 rect
.height
= upd
.GetHeight();
3517 gtk_paint_flat_box( parent
->m_widget
->style
,
3530 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3532 wxWindowDC
dc( (wxWindow
*)this );
3533 dc
.SetClippingRegion( m_clearRegion
);
3535 wxEraseEvent
erase_event( GetId(), &dc
);
3536 erase_event
.SetEventObject( this );
3538 if (!GetEventHandler()->ProcessEvent(erase_event
))
3542 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3543 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3545 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3547 wxRegionIterator
upd( m_clearRegion
);
3550 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3551 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3555 m_clearRegion
.Clear();
3558 wxNcPaintEvent
nc_paint_event( GetId() );
3559 nc_paint_event
.SetEventObject( this );
3560 GetEventHandler()->ProcessEvent( nc_paint_event
);
3562 wxPaintEvent
paint_event( GetId() );
3563 paint_event
.SetEventObject( this );
3564 GetEventHandler()->ProcessEvent( paint_event
);
3566 m_clipPaintRegion
= FALSE
;
3568 #ifndef __WXUNIVERSAL__
3570 // The following code will result in all window-less widgets
3571 // being redrawn because the wxWindows class is allowed to
3572 // paint over the window-less widgets.
3574 GList
*children
= pizza
->children
;
3577 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3578 children
= children
->next
;
3580 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3581 GTK_WIDGET_DRAWABLE (child
->widget
))
3583 // Get intersection of widget area and update region
3584 wxRegion
region( m_updateRegion
);
3586 GdkEventExpose gdk_event
;
3587 gdk_event
.type
= GDK_EXPOSE
;
3588 gdk_event
.window
= pizza
->bin_window
;
3589 gdk_event
.count
= 0;
3591 wxRegionIterator
upd( m_updateRegion
);
3595 rect
.x
= upd
.GetX();
3596 rect
.y
= upd
.GetY();
3597 rect
.width
= upd
.GetWidth();
3598 rect
.height
= upd
.GetHeight();
3600 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3602 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3612 m_updateRegion
.Clear();
3615 void wxWindowGTK::Clear()
3617 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3619 if (m_wxwindow
&& m_wxwindow
->window
)
3621 m_clearRegion
.Clear();
3622 wxSize
size( GetClientSize() );
3623 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3625 // Better do this in idle?
3631 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3633 wxWindowBase::DoSetToolTip(tip
);
3636 m_tooltip
->Apply( (wxWindow
*)this );
3639 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3641 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3643 #endif // wxUSE_TOOLTIPS
3645 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3647 GdkWindow
*window
= (GdkWindow
*) NULL
;
3649 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3651 window
= GetConnectWidget()->window
;
3655 // We need the pixel value e.g. for background clearing.
3656 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3660 // wxMSW doesn't clear the window here, either.
3661 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3667 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3669 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3671 if (!wxWindowBase::SetBackgroundColour(colour
))
3674 GdkWindow
*window
= (GdkWindow
*) NULL
;
3676 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3678 window
= GetConnectWidget()->window
;
3682 // indicate that a new style has been set
3683 // but it couldn't get applied as the
3684 // widget hasn't been realized yet.
3685 m_delayedBackgroundColour
= TRUE
;
3690 GtkSetBackgroundColour( colour
);
3696 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3698 GdkWindow
*window
= (GdkWindow
*) NULL
;
3700 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3702 window
= GetConnectWidget()->window
;
3709 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3711 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3713 if (!wxWindowBase::SetForegroundColour(colour
))
3715 // don't leave if the GTK widget has just
3717 if (!m_delayedForegroundColour
) return FALSE
;
3720 GdkWindow
*window
= (GdkWindow
*) NULL
;
3722 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3724 window
= GetConnectWidget()->window
;
3728 // indicate that a new style has been set
3729 // but it couldn't get applied as the
3730 // widget hasn't been realized yet.
3731 m_delayedForegroundColour
= TRUE
;
3735 GtkSetForegroundColour( colour
);
3741 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3745 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3747 // FIXME: no more klass in 2.0
3749 remake
->klass
= m_widgetStyle
->klass
;
3752 gtk_style_unref( m_widgetStyle
);
3753 m_widgetStyle
= remake
;
3757 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3760 def
= gtk_widget_get_default_style();
3762 m_widgetStyle
= gtk_style_copy( def
);
3764 // FIXME: no more klass in 2.0
3766 m_widgetStyle
->klass
= def
->klass
;
3770 return m_widgetStyle
;
3773 void wxWindowGTK::SetWidgetStyle()
3775 #if DISABLE_STYLE_IF_BROKEN_THEME
3776 if (m_widget
->style
->engine_data
)
3778 static bool s_warningPrinted
= FALSE
;
3779 if (!s_warningPrinted
)
3781 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3782 s_warningPrinted
= TRUE
;
3784 m_widgetStyle
= m_widget
->style
;
3789 GtkStyle
*style
= GetWidgetStyle();
3791 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3793 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3796 if (m_foregroundColour
.Ok())
3798 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3799 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3801 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3802 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3803 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3807 // Try to restore the gtk default style. This is still a little
3808 // oversimplified for what is probably really needed here for controls
3809 // other than buttons, but is better than not being able to (re)set a
3810 // control's foreground colour to *wxBLACK -- RL
3811 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3814 def
= gtk_widget_get_default_style();
3816 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3817 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3818 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3822 if (m_backgroundColour
.Ok())
3824 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3825 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3827 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3828 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3829 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3830 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3831 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3832 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3833 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3834 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3838 // Try to restore the gtk default style. This is still a little
3839 // oversimplified for what is probably really needed here for controls
3840 // other than buttons, but is better than not being able to (re)set a
3841 // control's background colour to default grey and means resetting a
3842 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3844 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3847 def
= gtk_widget_get_default_style();
3849 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3850 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3851 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3852 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3853 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3854 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3855 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3856 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3861 void wxWindowGTK::ApplyWidgetStyle()
3865 //-----------------------------------------------------------------------------
3866 // Pop-up menu stuff
3867 //-----------------------------------------------------------------------------
3869 #if wxUSE_MENUS_NATIVE
3872 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3874 *is_waiting
= FALSE
;
3877 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3879 menu
->SetInvokingWindow( win
);
3880 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3883 wxMenuItem
*menuitem
= node
->GetData();
3884 if (menuitem
->IsSubMenu())
3886 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3889 node
= node
->GetNext();
3893 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3894 // wxPopupMenuPositionCallback()
3896 // should be safe even in the MT case as the user can hardly popup 2 menus
3897 // simultaneously, can he?
3898 static gint gs_pop_x
= 0;
3899 static gint gs_pop_y
= 0;
3901 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3904 gboolean
* WXUNUSED(whatever
),
3906 gpointer
WXUNUSED(user_data
) )
3908 // ensure that the menu appears entirely on screen
3910 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3912 wxSize sizeScreen
= wxGetDisplaySize();
3914 gint xmax
= sizeScreen
.x
- req
.width
,
3915 ymax
= sizeScreen
.y
- req
.height
;
3917 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3918 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3921 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3923 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3925 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3927 SetInvokingWindow( menu
, this );
3933 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3935 bool is_waiting
= TRUE
;
3937 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3939 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3940 (gpointer
)&is_waiting
);
3943 GTK_MENU(menu
->m_menu
),
3944 (GtkWidget
*) NULL
, // parent menu shell
3945 (GtkWidget
*) NULL
, // parent menu item
3946 wxPopupMenuPositionCallback
, // function to position it
3947 NULL
, // client data
3948 0, // button used to activate it
3949 gs_timeLastClick
// the time of activation
3954 while (gtk_events_pending())
3955 gtk_main_iteration();
3961 #endif // wxUSE_MENUS_NATIVE
3963 #if wxUSE_DRAG_AND_DROP
3965 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3967 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3969 GtkWidget
*dnd_widget
= GetConnectWidget();
3971 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3973 if (m_dropTarget
) delete m_dropTarget
;
3974 m_dropTarget
= dropTarget
;
3976 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3979 #endif // wxUSE_DRAG_AND_DROP
3981 GtkWidget
* wxWindowGTK::GetConnectWidget()
3983 GtkWidget
*connect_widget
= m_widget
;
3984 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3986 return connect_widget
;
3989 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3992 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3994 return (window
== m_widget
->window
);
3997 bool wxWindowGTK::SetFont( const wxFont
&font
)
3999 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4001 if (!wxWindowBase::SetFont(font
))
4006 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4007 if ( sysbg
== m_backgroundColour
)
4009 m_backgroundColour
= wxNullColour
;
4011 m_backgroundColour
= sysbg
;
4021 void wxWindowGTK::DoCaptureMouse()
4023 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4025 GdkWindow
*window
= (GdkWindow
*) NULL
;
4027 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4029 window
= GetConnectWidget()->window
;
4031 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4033 wxCursor
* cursor
= & m_cursor
;
4035 cursor
= wxSTANDARD_CURSOR
;
4037 gdk_pointer_grab( window
, FALSE
,
4039 (GDK_BUTTON_PRESS_MASK
|
4040 GDK_BUTTON_RELEASE_MASK
|
4041 GDK_POINTER_MOTION_HINT_MASK
|
4042 GDK_POINTER_MOTION_MASK
),
4044 cursor
->GetCursor(),
4045 (guint32
)GDK_CURRENT_TIME
);
4046 g_captureWindow
= this;
4047 g_captureWindowHasMouse
= TRUE
;
4050 void wxWindowGTK::DoReleaseMouse()
4052 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4054 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4056 g_captureWindow
= (wxWindowGTK
*) NULL
;
4058 GdkWindow
*window
= (GdkWindow
*) NULL
;
4060 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4062 window
= GetConnectWidget()->window
;
4067 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4071 wxWindow
*wxWindowBase::GetCapture()
4073 return (wxWindow
*)g_captureWindow
;
4076 bool wxWindowGTK::IsRetained() const
4081 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4082 int range
, bool refresh
)
4084 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4086 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4088 m_hasScrolling
= TRUE
;
4090 if (orient
== wxHORIZONTAL
)
4092 float fpos
= (float)pos
;
4093 float frange
= (float)range
;
4094 float fthumb
= (float)thumbVisible
;
4095 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4096 if (fpos
< 0.0) fpos
= 0.0;
4098 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4099 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4101 SetScrollPos( orient
, pos
, refresh
);
4105 m_oldHorizontalPos
= fpos
;
4107 m_hAdjust
->lower
= 0.0;
4108 m_hAdjust
->upper
= frange
;
4109 m_hAdjust
->value
= fpos
;
4110 m_hAdjust
->step_increment
= 1.0;
4111 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4112 m_hAdjust
->page_size
= fthumb
;
4116 float fpos
= (float)pos
;
4117 float frange
= (float)range
;
4118 float fthumb
= (float)thumbVisible
;
4119 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4120 if (fpos
< 0.0) fpos
= 0.0;
4122 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4123 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4125 SetScrollPos( orient
, pos
, refresh
);
4129 m_oldVerticalPos
= fpos
;
4131 m_vAdjust
->lower
= 0.0;
4132 m_vAdjust
->upper
= frange
;
4133 m_vAdjust
->value
= fpos
;
4134 m_vAdjust
->step_increment
= 1.0;
4135 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4136 m_vAdjust
->page_size
= fthumb
;
4139 if (orient
== wxHORIZONTAL
)
4140 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4142 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4145 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4147 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4149 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4151 if (orient
== wxHORIZONTAL
)
4153 float fpos
= (float)pos
;
4154 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4155 if (fpos
< 0.0) fpos
= 0.0;
4156 m_oldHorizontalPos
= fpos
;
4158 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4159 m_hAdjust
->value
= fpos
;
4163 float fpos
= (float)pos
;
4164 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4165 if (fpos
< 0.0) fpos
= 0.0;
4166 m_oldVerticalPos
= fpos
;
4168 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4169 m_vAdjust
->value
= fpos
;
4172 if (m_wxwindow
->window
)
4174 if (orient
== wxHORIZONTAL
)
4176 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4177 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4179 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4181 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4182 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4186 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4187 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4189 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4191 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4192 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4197 int wxWindowGTK::GetScrollThumb( int orient
) const
4199 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4201 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4203 if (orient
== wxHORIZONTAL
)
4204 return (int)(m_hAdjust
->page_size
+0.5);
4206 return (int)(m_vAdjust
->page_size
+0.5);
4209 int wxWindowGTK::GetScrollPos( int orient
) const
4211 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4213 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4215 if (orient
== wxHORIZONTAL
)
4216 return (int)(m_hAdjust
->value
+0.5);
4218 return (int)(m_vAdjust
->value
+0.5);
4221 int wxWindowGTK::GetScrollRange( int orient
) const
4223 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4225 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4227 if (orient
== wxHORIZONTAL
)
4228 return (int)(m_hAdjust
->upper
+0.5);
4230 return (int)(m_vAdjust
->upper
+0.5);
4233 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4235 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4237 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4239 // No scrolling requested.
4240 if ((dx
== 0) && (dy
== 0)) return;
4243 if (!m_updateRegion
.IsEmpty())
4245 m_updateRegion
.Offset( dx
, dy
);
4249 GetClientSize( &cw
, &ch
);
4250 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4253 if (!m_clearRegion
.IsEmpty())
4255 m_clearRegion
.Offset( dx
, dy
);
4259 GetClientSize( &cw
, &ch
);
4260 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4262 m_clipPaintRegion
= TRUE
;
4264 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4266 m_clipPaintRegion
= FALSE
;
4269 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4271 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4272 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4279 // Find the wxWindow at the current mouse position, also returning the mouse
4281 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4283 pt
= wxGetMousePosition();
4284 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4288 // Get the current mouse position.
4289 wxPoint
wxGetMousePosition()
4291 /* This crashes when used within wxHelpContext,
4292 so we have to use the X-specific implementation below.
4294 GdkModifierType *mask;
4295 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4297 return wxPoint(x, y);
4301 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4303 return wxPoint(-999, -999);
4305 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4306 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4307 Window rootReturn
, childReturn
;
4308 int rootX
, rootY
, winX
, winY
;
4309 unsigned int maskReturn
;
4311 XQueryPointer (display
,
4315 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4316 return wxPoint(rootX
, rootY
);
4320 // ----------------------------------------------------------------------------
4322 // ----------------------------------------------------------------------------
4324 class wxWinModule
: public wxModule
4331 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4334 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4336 bool wxWinModule::OnInit()
4338 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4339 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4344 void wxWinModule::OnExit()
4347 gdk_gc_unref( g_eraseGC
);