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 we detect that the app has got/lost the focus, we set this variable to
243 // either TRUE or FALSE and an activate event will be sent during the next
244 // OnIdle() call and it is reset to -1: this value means that we shouldn't
245 // send any activate events at all
246 static int g_sendActivateEvent
= -1;
248 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
249 the last click here */
250 static guint32 gs_timeLastClick
= 0;
252 extern bool g_mainThreadLocked
;
254 //-----------------------------------------------------------------------------
256 //-----------------------------------------------------------------------------
259 #define DISABLE_STYLE_IF_BROKEN_THEME 1
265 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
267 # define DEBUG_MAIN_THREAD
270 static gint
gtk_debug_focus_in_callback( GtkWidget
*WXUNUSED(widget
),
271 GdkEvent
*WXUNUSED(event
),
272 const wxChar
*WXUNUSED(name
) )
275 static bool s_done = FALSE;
278 wxLog::AddTraceMask("focus");
281 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
287 void debug_focus_in( GtkWidget
* widget
, const wxChar
* name
, const wxChar
*window
)
289 // suppress warnings about gtk_debug_focus_in_callback being unused with
294 tmp
+= wxT(" FROM ");
297 wxChar
*s
= new wxChar
[tmp
.Length()+1];
301 gtk_signal_connect( GTK_OBJECT(widget
), "focus_in_event",
302 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback
), (gpointer
)s
);
307 #define DEBUG_MAIN_THREAD
310 //-----------------------------------------------------------------------------
311 // missing gdk functions
312 //-----------------------------------------------------------------------------
315 gdk_window_warp_pointer (GdkWindow
*window
,
320 GdkWindowPrivate
*priv
;
324 window
= GDK_ROOT_PARENT();
327 if (!GDK_WINDOW_DESTROYED(window
))
329 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
330 None
, /* not source window -> move from anywhere */
331 GDK_WINDOW_XID(window
), /* dest window */
332 0, 0, 0, 0, /* not source window -> move from anywhere */
336 priv
= (GdkWindowPrivate
*) window
;
338 if (!priv
->destroyed
)
340 XWarpPointer (priv
->xdisplay
,
341 None
, /* not source window -> move from anywhere */
342 priv
->xwindow
, /* dest window */
343 0, 0, 0, 0, /* not source window -> move from anywhere */
349 //-----------------------------------------------------------------------------
351 //-----------------------------------------------------------------------------
353 extern void wxapp_install_idle_handler();
354 extern bool g_isIdle
;
356 //-----------------------------------------------------------------------------
357 // local code (see below)
358 //-----------------------------------------------------------------------------
360 // returns the child of win which currently has focus or NULL if not found
362 // Note: can't be static, needed by textctrl.cpp.
363 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
365 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
367 return (wxWindow
*)NULL
;
369 if ( winFocus
== win
)
370 return (wxWindow
*)win
;
372 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
374 node
= node
->GetNext() )
376 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
381 return (wxWindow
*)NULL
;
384 // Returns toplevel grandparent of given window:
385 static wxWindowGTK
* wxGetTopLevelParent(wxWindowGTK
*win
)
387 wxWindowGTK
*p
= win
;
388 while (p
&& !p
->IsTopLevel())
393 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
395 // wxUniversal widgets draw the borders and scrollbars themselves
396 #ifndef __WXUNIVERSAL__
403 if (win
->m_hasScrolling
)
405 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
407 GtkRequisition vscroll_req
;
408 vscroll_req
.width
= 2;
409 vscroll_req
.height
= 2;
410 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
411 (scroll_window
->vscrollbar
, &vscroll_req
);
413 GtkRequisition hscroll_req
;
414 hscroll_req
.width
= 2;
415 hscroll_req
.height
= 2;
416 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
417 (scroll_window
->hscrollbar
, &hscroll_req
);
419 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
421 if (scroll_window
->vscrollbar_visible
)
423 dw
+= vscroll_req
.width
;
424 dw
+= scroll_class
->scrollbar_spacing
;
427 if (scroll_window
->hscrollbar_visible
)
429 dh
+= hscroll_req
.height
;
430 dh
+= scroll_class
->scrollbar_spacing
;
436 if (GTK_WIDGET_NO_WINDOW (widget
))
438 dx
+= widget
->allocation
.x
;
439 dy
+= widget
->allocation
.y
;
442 if (win
->HasFlag(wxRAISED_BORDER
))
444 gtk_draw_shadow( widget
->style
,
449 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
453 if (win
->HasFlag(wxSUNKEN_BORDER
))
455 gtk_draw_shadow( widget
->style
,
460 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
464 if (win
->HasFlag(wxSIMPLE_BORDER
))
467 gc
= gdk_gc_new( widget
->window
);
468 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
469 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
471 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
475 #endif // __WXUNIVERSAL__
478 //-----------------------------------------------------------------------------
479 // "expose_event" of m_widget
480 //-----------------------------------------------------------------------------
482 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
484 if (gdk_event
->count
> 0) return FALSE
;
486 draw_frame( widget
, win
);
490 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
496 //-----------------------------------------------------------------------------
497 // "draw" of m_widget
498 //-----------------------------------------------------------------------------
502 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
504 draw_frame( widget
, win
);
509 //-----------------------------------------------------------------------------
510 // "size_request" of m_widget
511 //-----------------------------------------------------------------------------
513 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
516 win
->GetSize( &w
, &h
);
520 requisition
->height
= h
;
521 requisition
->width
= w
;
524 //-----------------------------------------------------------------------------
525 // "expose_event" of m_wxwindow
526 //-----------------------------------------------------------------------------
528 static int gtk_window_expose_callback( GtkWidget
*widget
,
529 GdkEventExpose
*gdk_event
,
535 wxapp_install_idle_handler();
538 if (win->GetName() == wxT("panel"))
540 wxPrintf( wxT("OnExpose from ") );
541 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
542 wxPrintf( win->GetClassInfo()->GetClassName() );
543 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
544 (int)gdk_event->area.y,
545 (int)gdk_event->area.width,
546 (int)gdk_event->area.height );
550 #ifndef __WXUNIVERSAL__
551 GtkPizza
*pizza
= GTK_PIZZA (widget
);
553 if (win
->GetThemeEnabled())
555 wxWindow
*parent
= win
->GetParent();
556 while (parent
&& !parent
->IsTopLevel())
557 parent
= parent
->GetParent();
561 gtk_paint_flat_box (parent
->m_widget
->style
,
572 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
574 gdk_event
->area
.width
,
575 gdk_event
->area
.height
);
577 // Actual redrawing takes place in idle time.
582 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
589 //-----------------------------------------------------------------------------
590 // "event" of m_wxwindow
591 //-----------------------------------------------------------------------------
593 // GTK thinks it is clever and filters out a certain amount of "unneeded"
594 // expose events. We need them, of course, so we override the main event
595 // procedure in GtkWidget by giving our own handler for all system events.
596 // There, we look for expose events ourselves whereas all other events are
599 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
600 GdkEventExpose
*event
,
603 if (event
->type
== GDK_EXPOSE
)
605 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
612 //-----------------------------------------------------------------------------
613 // "draw" of m_wxwindow
614 //-----------------------------------------------------------------------------
618 // This callback is a complete replacement of the gtk_pizza_draw() function,
619 // which is disabled.
621 static void gtk_window_draw_callback( GtkWidget
*widget
,
628 wxapp_install_idle_handler();
630 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
631 // there are no child windows.
632 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
633 (win
->GetChildren().GetCount() == 0))
639 if (win->GetName() == wxT("panel"))
641 wxPrintf( wxT("OnDraw from ") );
642 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
643 wxPrintf( win->GetClassInfo()->GetClassName() );
644 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
651 #ifndef __WXUNIVERSAL__
652 GtkPizza
*pizza
= GTK_PIZZA (widget
);
654 if (win
->GetThemeEnabled())
656 wxWindow
*parent
= win
->GetParent();
657 while (parent
&& !parent
->IsTopLevel())
658 parent
= parent
->GetParent();
662 gtk_paint_flat_box (parent
->m_widget
->style
,
673 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
674 (pizza
->clear_on_draw
))
676 gdk_window_clear_area( pizza
->bin_window
,
677 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
681 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
683 // Actual redrawing takes place in idle time.
687 #ifndef __WXUNIVERSAL__
688 // Redraw child widgets
689 GList
*children
= pizza
->children
;
692 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
693 children
= children
->next
;
695 GdkRectangle child_area
;
696 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
698 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
706 //-----------------------------------------------------------------------------
707 // "key_press_event" from any window
708 //-----------------------------------------------------------------------------
710 // set WXTRACE to this to see the key event codes on the console
711 #define TRACE_KEYS _T("keyevent")
713 // translates an X key symbol to WXK_XXX value
715 // if isChar is true it means that the value returned will be used for EVT_CHAR
716 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
717 // for example, while if it is false it means that the value is going to be
718 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
720 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
726 // Shift, Control and Alt don't generate the CHAR events at all
729 key_code
= isChar
? 0 : WXK_SHIFT
;
733 key_code
= isChar
? 0 : WXK_CONTROL
;
741 key_code
= isChar
? 0 : WXK_ALT
;
744 // neither do the toggle modifies
745 case GDK_Scroll_Lock
:
746 key_code
= isChar
? 0 : WXK_SCROLL
;
750 key_code
= isChar
? 0 : WXK_CAPITAL
;
754 key_code
= isChar
? 0 : WXK_NUMLOCK
;
758 // various other special keys
771 case GDK_ISO_Left_Tab
:
778 key_code
= WXK_RETURN
;
782 key_code
= WXK_CLEAR
;
786 key_code
= WXK_PAUSE
;
790 key_code
= WXK_SELECT
;
794 key_code
= WXK_PRINT
;
798 key_code
= WXK_EXECUTE
;
802 key_code
= WXK_ESCAPE
;
805 // cursor and other extended keyboard keys
807 key_code
= WXK_DELETE
;
823 key_code
= WXK_RIGHT
;
830 case GDK_Prior
: // == GDK_Page_Up
831 key_code
= WXK_PRIOR
;
834 case GDK_Next
: // == GDK_Page_Down
847 key_code
= WXK_INSERT
;
862 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
866 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
870 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
874 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
878 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
882 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
886 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
890 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
894 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
898 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
902 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
906 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
910 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
913 case GDK_KP_Prior
: // == GDK_KP_Page_Up
914 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
917 case GDK_KP_Next
: // == GDK_KP_Page_Down
918 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
922 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
926 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
930 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
934 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
938 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
941 case GDK_KP_Multiply
:
942 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
946 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
949 case GDK_KP_Separator
:
950 // FIXME: what is this?
951 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
954 case GDK_KP_Subtract
:
955 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
959 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
963 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
980 key_code
= WXK_F1
+ keysym
- GDK_F1
;
990 static inline bool wxIsAsciiKeysym(KeySym ks
)
996 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
998 GdkEventKey
*gdk_event
)
1000 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
1001 // but only event->keyval which is quite useless to us, so remember
1002 // the last character from GDK_KEY_PRESS and reuse it as last resort
1004 // NB: should be MT-safe as we're always called from the main thread only
1009 } s_lastKeyPress
= { 0, 0 };
1011 KeySym keysym
= gdk_event
->keyval
;
1012 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
1016 // do we have the translation or is it a plain ASCII character?
1017 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1019 // we should use keysym if it is ASCII as X does some translations
1020 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1021 // which we don't want here (but which we do use for OnChar())
1022 if ( !wxIsAsciiKeysym(keysym
) )
1024 keysym
= (KeySym
)gdk_event
->string
[0];
1027 // we want to always get the same key code when the same key is
1028 // pressed regardless of the state of the modifies, i.e. on a
1029 // standard US keyboard pressing '5' or '%' ('5' key with
1030 // Shift) should result in the same key code in OnKeyDown():
1031 // '5' (although OnChar() will get either '5' or '%').
1033 // to do it we first translate keysym to keycode (== scan code)
1034 // and then back but always using the lower register
1035 Display
*dpy
= (Display
*)wxGetDisplay();
1036 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1037 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1039 // use the normalized, i.e. lower register, keysym if we've
1041 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1043 // as explained above, we want to have lower register key codes
1044 // normally but for the letter keys we want to have the upper ones
1046 // NB: don't use XConvertCase() here, we want to do it for letters
1048 key_code
= toupper(key_code
);
1050 else // non ASCII key, what to do?
1052 // by default, ignore it
1055 // but if we have cached information from the last KEY_PRESS
1056 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1059 if ( keysym
== s_lastKeyPress
.keysym
)
1061 key_code
= s_lastKeyPress
.keycode
;
1066 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1068 // remember it to be reused for KEY_UP event later
1069 s_lastKeyPress
.keysym
= keysym
;
1070 s_lastKeyPress
.keycode
= key_code
;
1074 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %d => keycode = %ld"),
1075 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
1077 gdk_event
->keyval
, key_code
);
1079 // sending unknown key events doesn't really make sense
1083 // now fill all the other fields
1086 GdkModifierType state
;
1087 if (gdk_event
->window
)
1088 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1090 event
.SetTimestamp( gdk_event
->time
);
1091 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1092 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1093 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1094 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1095 event
.m_keyCode
= key_code
;
1096 event
.m_scanCode
= gdk_event
->keyval
;
1097 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1098 event
.m_rawFlags
= 0;
1101 event
.SetEventObject( win
);
1106 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1107 GdkEventKey
*gdk_event
,
1113 wxapp_install_idle_handler();
1117 if (g_blockEventsOnDrag
)
1120 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1121 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1123 // unknown key pressed, ignore (the event would be useless anyhow)
1127 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1132 wxWindowGTK
*ancestor
= win
;
1135 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1138 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1139 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1142 if (ancestor
->IsTopLevel())
1144 ancestor
= ancestor
->GetParent();
1147 #endif // wxUSE_ACCEL
1149 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1150 will only be sent if it is not in an accelerator table. */
1153 KeySym keysym
= gdk_event
->keyval
;
1154 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1157 if ( gdk_event
->length
== 1 )
1159 key_code
= (unsigned char)gdk_event
->string
[0];
1161 else if ( wxIsAsciiKeysym(keysym
) )
1164 key_code
= (unsigned char)keysym
;
1170 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1172 // reuse the same event object, just change its type and use the
1173 // translated keycode instead of the raw one
1174 event
.SetEventType(wxEVT_CHAR
);
1175 event
.m_keyCode
= key_code
;
1177 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1181 /* win is a control: tab can be propagated up */
1183 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1184 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1185 // have this style, yet choose not to process this particular TAB in which
1186 // case TAB must still work as a navigational character
1188 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1190 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1192 wxNavigationKeyEvent new_event
;
1193 new_event
.SetEventObject( win
->GetParent() );
1194 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1195 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1196 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1197 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1198 new_event
.SetCurrentFocus( win
);
1199 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1202 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1204 (gdk_event
->keyval
== GDK_Escape
) )
1206 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1207 new_event
.SetEventObject( win
);
1208 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1212 #if 0 // (GTK_MINOR_VERSION > 0)
1213 /* Pressing F10 will activate the menu bar of the top frame. */
1215 (gdk_event
->keyval
== GDK_F10
) )
1217 wxWindowGTK
*ancestor
= win
;
1220 if (wxIsKindOf(ancestor
,wxFrame
))
1222 wxFrame
*frame
= (wxFrame
*) ancestor
;
1223 wxMenuBar
*menubar
= frame
->GetMenuBar();
1226 wxNode
*node
= menubar
->GetMenus().First();
1229 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1230 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1236 ancestor
= ancestor
->GetParent();
1243 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1250 //-----------------------------------------------------------------------------
1251 // "key_release_event" from any window
1252 //-----------------------------------------------------------------------------
1254 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1255 GdkEventKey
*gdk_event
,
1261 wxapp_install_idle_handler();
1266 if (g_blockEventsOnDrag
)
1269 wxKeyEvent
event( wxEVT_KEY_UP
);
1270 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1272 // unknown key pressed, ignore (the event would be useless anyhow
1276 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1279 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1283 // ============================================================================
1285 // ============================================================================
1287 // init wxMouseEvent with the info from gdk_event
1288 #define InitMouseEvent(win, event, gdk_event) \
1290 event.SetTimestamp( gdk_event->time ); \
1291 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1292 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1293 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1294 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1295 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1296 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1297 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1299 wxPoint pt = win->GetClientAreaOrigin(); \
1300 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1301 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1304 // ----------------------------------------------------------------------------
1305 // mouse event processing helper
1306 // ----------------------------------------------------------------------------
1308 static void AdjustEventButtonState(wxMouseEvent
& event
)
1310 // GDK reports the old state of the button for a button press event, but
1311 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1312 // for a LEFT_DOWN event, not FALSE, so we will invert
1313 // left/right/middleDown for the corresponding click events
1315 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1316 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1317 (event
.GetEventType() == wxEVT_LEFT_UP
))
1319 event
.m_leftDown
= !event
.m_leftDown
;
1323 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1324 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1325 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1327 event
.m_middleDown
= !event
.m_middleDown
;
1331 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1332 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1333 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1335 event
.m_rightDown
= !event
.m_rightDown
;
1340 //-----------------------------------------------------------------------------
1341 // "button_press_event"
1342 //-----------------------------------------------------------------------------
1344 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1349 wxapp_install_idle_handler();
1352 wxPrintf( wxT("1) OnButtonPress from ") );
1353 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1354 wxPrintf( win->GetClassInfo()->GetClassName() );
1355 wxPrintf( wxT(".\n") );
1357 if (!win
->m_hasVMT
) return FALSE
;
1358 if (g_blockEventsOnDrag
) return TRUE
;
1359 if (g_blockEventsOnScroll
) return TRUE
;
1361 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1363 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1365 gtk_widget_grab_focus( win
->m_wxwindow
);
1367 wxPrintf( wxT("GrabFocus from ") );
1368 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1369 wxPrintf( win->GetClassInfo()->GetClassName() );
1370 wxPrintf( wxT(".\n") );
1374 wxEventType event_type
= wxEVT_NULL
;
1376 if (gdk_event
->button
== 1)
1378 switch (gdk_event
->type
)
1380 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1381 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1385 else if (gdk_event
->button
== 2)
1387 switch (gdk_event
->type
)
1389 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1390 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1394 else if (gdk_event
->button
== 3)
1396 switch (gdk_event
->type
)
1398 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1399 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1404 if ( event_type
== wxEVT_NULL
)
1406 // unknown mouse button or click type
1410 wxMouseEvent
event( event_type
);
1411 InitMouseEvent( win
, event
, gdk_event
);
1413 AdjustEventButtonState(event
);
1415 // wxListBox actually get mouse events from the item
1417 if (win
->m_isListBox
)
1419 event
.m_x
+= widget
->allocation
.x
;
1420 event
.m_y
+= widget
->allocation
.y
;
1423 // Some control don't have their own X window and thus cannot get
1426 if (!g_captureWindow
)
1428 wxCoord x
= event
.m_x
;
1429 wxCoord y
= event
.m_y
;
1430 if (win
->m_wxwindow
)
1432 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1433 x
+= pizza
->xoffset
;
1434 y
+= pizza
->yoffset
;
1437 wxNode
*node
= win
->GetChildren().First();
1440 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1442 node
= node
->Next();
1443 if (!child
->IsShown())
1446 if (child
->m_isStaticBox
)
1448 // wxStaticBox is transparent in the box itself
1449 int xx1
= child
->m_x
;
1450 int yy1
= child
->m_y
;
1451 int xx2
= child
->m_x
+ child
->m_width
;
1452 int yy2
= child
->m_x
+ child
->m_height
;
1455 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1457 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1459 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1461 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1464 event
.m_x
-= child
->m_x
;
1465 event
.m_y
-= child
->m_y
;
1472 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1473 (child
->m_x
<= x
) &&
1474 (child
->m_y
<= y
) &&
1475 (child
->m_x
+child
->m_width
>= x
) &&
1476 (child
->m_y
+child
->m_height
>= y
))
1479 event
.m_x
-= child
->m_x
;
1480 event
.m_y
-= child
->m_y
;
1487 event
.SetEventObject( win
);
1489 gs_timeLastClick
= gdk_event
->time
;
1492 wxPrintf( wxT("2) OnButtonPress from ") );
1493 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1494 wxPrintf( win->GetClassInfo()->GetClassName() );
1495 wxPrintf( wxT(".\n") );
1498 if (win
->GetEventHandler()->ProcessEvent( event
))
1500 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1507 //-----------------------------------------------------------------------------
1508 // "button_release_event"
1509 //-----------------------------------------------------------------------------
1511 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1516 wxapp_install_idle_handler();
1518 if (!win
->m_hasVMT
) return FALSE
;
1519 if (g_blockEventsOnDrag
) return FALSE
;
1520 if (g_blockEventsOnScroll
) return FALSE
;
1522 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1525 printf( "OnButtonRelease from " );
1526 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1527 printf( win->GetClassInfo()->GetClassName() );
1531 wxEventType event_type
= wxEVT_NULL
;
1533 switch (gdk_event
->button
)
1535 case 1: event_type
= wxEVT_LEFT_UP
; break;
1536 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1537 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1538 default: return FALSE
;
1541 wxMouseEvent
event( event_type
);
1542 InitMouseEvent( win
, event
, gdk_event
);
1544 AdjustEventButtonState(event
);
1546 // wxListBox actually get mouse events from the item
1548 if (win
->m_isListBox
)
1550 event
.m_x
+= widget
->allocation
.x
;
1551 event
.m_y
+= widget
->allocation
.y
;
1554 // Some control don't have their own X window and thus cannot get
1557 if (!g_captureWindow
)
1559 wxCoord x
= event
.m_x
;
1560 wxCoord y
= event
.m_y
;
1561 if (win
->m_wxwindow
)
1563 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1564 x
+= pizza
->xoffset
;
1565 y
+= pizza
->yoffset
;
1568 wxNode
*node
= win
->GetChildren().First();
1571 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1573 node
= node
->Next();
1574 if (!child
->IsShown())
1577 if (child
->m_isStaticBox
)
1579 // wxStaticBox is transparent in the box itself
1580 int xx1
= child
->m_x
;
1581 int yy1
= child
->m_y
;
1582 int xx2
= child
->m_x
+ child
->m_width
;
1583 int yy2
= child
->m_x
+ child
->m_height
;
1586 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1588 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1590 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1592 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1595 event
.m_x
-= child
->m_x
;
1596 event
.m_y
-= child
->m_y
;
1603 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1604 (child
->m_x
<= x
) &&
1605 (child
->m_y
<= y
) &&
1606 (child
->m_x
+child
->m_width
>= x
) &&
1607 (child
->m_y
+child
->m_height
>= y
))
1610 event
.m_x
-= child
->m_x
;
1611 event
.m_y
-= child
->m_y
;
1618 event
.SetEventObject( win
);
1620 if (win
->GetEventHandler()->ProcessEvent( event
))
1622 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1629 //-----------------------------------------------------------------------------
1630 // "motion_notify_event"
1631 //-----------------------------------------------------------------------------
1633 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1634 GdkEventMotion
*gdk_event
,
1640 wxapp_install_idle_handler();
1642 if (!win
->m_hasVMT
) return FALSE
;
1643 if (g_blockEventsOnDrag
) return FALSE
;
1644 if (g_blockEventsOnScroll
) return FALSE
;
1646 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1648 if (gdk_event
->is_hint
)
1652 GdkModifierType state
;
1653 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1659 printf( "OnMotion from " );
1660 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1661 printf( win->GetClassInfo()->GetClassName() );
1665 wxMouseEvent
event( wxEVT_MOTION
);
1666 InitMouseEvent(win
, event
, gdk_event
);
1668 if ( g_captureWindow
)
1670 // synthetize a mouse enter or leave event if needed
1671 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1672 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1673 if ( hasMouse
!= g_captureWindowHasMouse
)
1675 // the mouse changed window
1676 g_captureWindowHasMouse
= hasMouse
;
1678 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1679 : wxEVT_LEAVE_WINDOW
);
1680 InitMouseEvent(win
, event
, gdk_event
);
1681 event
.SetEventObject(win
);
1682 win
->GetEventHandler()->ProcessEvent(event
);
1687 // Some control don't have their own X window and thus cannot get
1690 wxCoord x
= event
.m_x
;
1691 wxCoord y
= event
.m_y
;
1692 if (win
->m_wxwindow
)
1694 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1695 x
+= pizza
->xoffset
;
1696 y
+= pizza
->yoffset
;
1699 wxNode
*node
= win
->GetChildren().First();
1702 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1704 node
= node
->Next();
1705 if (!child
->IsShown())
1708 if (child
->m_isStaticBox
)
1710 // wxStaticBox is transparent in the box itself
1711 int xx1
= child
->m_x
;
1712 int yy1
= child
->m_y
;
1713 int xx2
= child
->m_x
+ child
->m_width
;
1714 int yy2
= child
->m_x
+ child
->m_height
;
1717 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1719 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1721 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1723 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1726 event
.m_x
-= child
->m_x
;
1727 event
.m_y
-= child
->m_y
;
1734 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1735 (child
->m_x
<= x
) &&
1736 (child
->m_y
<= y
) &&
1737 (child
->m_x
+child
->m_width
>= x
) &&
1738 (child
->m_y
+child
->m_height
>= y
))
1741 event
.m_x
-= child
->m_x
;
1742 event
.m_y
-= child
->m_y
;
1749 event
.SetEventObject( win
);
1751 if (win
->GetEventHandler()->ProcessEvent( event
))
1753 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1760 //-----------------------------------------------------------------------------
1762 //-----------------------------------------------------------------------------
1764 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1765 GdkEvent
*WXUNUSED(event
),
1771 wxapp_install_idle_handler();
1773 if (!win
->m_hasVMT
) return FALSE
;
1774 if (g_blockEventsOnDrag
) return FALSE
;
1776 switch ( g_sendActivateEvent
)
1779 // we've got focus from outside, synthetize wxActivateEvent
1780 g_sendActivateEvent
= 1;
1784 // another our window just lost focus, it was already ours before
1785 // - don't send any wxActivateEvent
1786 g_sendActivateEvent
= -1;
1791 g_focusWindow
= win
;
1794 wxLogDebug( wxT("OnSetFocus from %s\n"), win
->GetName().c_str() );
1797 // notify the parent keeping track of focus for the kbd navigation
1798 // purposes that we got it
1799 wxChildFocusEvent
eventFocus(win
);
1800 (void)win
->GetEventHandler()->ProcessEvent(eventFocus
);
1804 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1808 // caret needs to be informed about focus change
1809 wxCaret
*caret
= win
->GetCaret();
1812 caret
->OnSetFocus();
1814 #endif // wxUSE_CARET
1816 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1817 if ( active
!= g_activeFrame
)
1819 if ( g_activeFrame
)
1821 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1822 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1823 event
.SetEventObject(g_activeFrame
);
1824 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1827 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1828 g_activeFrame
= active
;
1829 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1830 event
.SetEventObject(g_activeFrame
);
1831 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1833 g_activeFrameLostFocus
= FALSE
;
1836 wxFocusEvent
event( wxEVT_SET_FOCUS
, win
->GetId() );
1837 event
.SetEventObject( win
);
1839 if (win
->GetEventHandler()->ProcessEvent( event
))
1841 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1849 //-----------------------------------------------------------------------------
1850 // "focus_out_event"
1851 //-----------------------------------------------------------------------------
1853 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1858 wxapp_install_idle_handler();
1860 if (!win
->m_hasVMT
) return FALSE
;
1861 if (g_blockEventsOnDrag
) return FALSE
;
1864 wxLogDebug( wxT("OnKillFocus from %s"), win
->GetName().c_str() );
1867 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1869 // VZ: commenting this out because it does happen (although not easy
1870 // to reproduce, I only see it when using wxMiniFrame and not
1871 // always) and makes using Mahogany quite annoying
1873 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1874 wxT("unfocusing window that hasn't gained focus properly") )
1877 g_activeFrameLostFocus
= TRUE
;
1880 // if the focus goes out of our app alltogether, OnIdle() will send
1881 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1882 // g_sendActivateEvent to -1
1883 g_sendActivateEvent
= 0;
1885 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1889 g_focusWindow
= (wxWindowGTK
*)NULL
;
1897 // caret needs to be informed about focus change
1898 wxCaret
*caret
= win
->GetCaret();
1901 caret
->OnKillFocus();
1903 #endif // wxUSE_CARET
1905 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1906 event
.SetEventObject( win
);
1908 if (win
->GetEventHandler()->ProcessEvent( event
))
1910 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1917 //-----------------------------------------------------------------------------
1918 // "enter_notify_event"
1919 //-----------------------------------------------------------------------------
1921 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1926 wxapp_install_idle_handler();
1928 if (!win
->m_hasVMT
) return FALSE
;
1929 if (g_blockEventsOnDrag
) return FALSE
;
1931 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1933 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1934 event
.SetTimestamp( gdk_event
->time
);
1935 event
.SetEventObject( win
);
1939 GdkModifierType state
= (GdkModifierType
)0;
1941 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1943 InitMouseEvent(win
, event
, gdk_event
);
1944 wxPoint pt
= win
->GetClientAreaOrigin();
1945 event
.m_x
= x
+ pt
.x
;
1946 event
.m_y
= y
+ pt
.y
;
1948 if (win
->GetEventHandler()->ProcessEvent( event
))
1950 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1957 //-----------------------------------------------------------------------------
1958 // "leave_notify_event"
1959 //-----------------------------------------------------------------------------
1961 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1966 wxapp_install_idle_handler();
1968 if (!win
->m_hasVMT
) return FALSE
;
1969 if (g_blockEventsOnDrag
) return FALSE
;
1971 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1973 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1974 event
.SetTimestamp( gdk_event
->time
);
1975 event
.SetEventObject( win
);
1979 GdkModifierType state
= (GdkModifierType
)0;
1981 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1983 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1984 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1985 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1986 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1987 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1988 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1989 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1991 wxPoint pt
= win
->GetClientAreaOrigin();
1992 event
.m_x
= x
+ pt
.x
;
1993 event
.m_y
= y
+ pt
.y
;
1995 if (win
->GetEventHandler()->ProcessEvent( event
))
1997 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2004 //-----------------------------------------------------------------------------
2005 // "value_changed" from m_vAdjust
2006 //-----------------------------------------------------------------------------
2008 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2015 wxapp_install_idle_handler();
2017 if (g_blockEventsOnDrag
) return;
2019 if (!win
->m_hasVMT
) return;
2021 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2022 if (fabs(diff
) < 0.2) return;
2024 win
->m_oldVerticalPos
= adjust
->value
;
2026 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
2028 int value
= (int)(adjust
->value
+0.5);
2030 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2031 event
.SetEventObject( win
);
2032 win
->GetEventHandler()->ProcessEvent( event
);
2035 //-----------------------------------------------------------------------------
2036 // "value_changed" from m_hAdjust
2037 //-----------------------------------------------------------------------------
2039 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2046 wxapp_install_idle_handler();
2048 if (g_blockEventsOnDrag
) return;
2049 if (!win
->m_hasVMT
) return;
2051 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2052 if (fabs(diff
) < 0.2) return;
2054 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
2056 win
->m_oldHorizontalPos
= adjust
->value
;
2058 int value
= (int)(adjust
->value
+0.5);
2060 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2061 event
.SetEventObject( win
);
2062 win
->GetEventHandler()->ProcessEvent( event
);
2065 //-----------------------------------------------------------------------------
2066 // "button_press_event" from scrollbar
2067 //-----------------------------------------------------------------------------
2069 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2070 GdkEventButton
*gdk_event
,
2076 wxapp_install_idle_handler();
2079 g_blockEventsOnScroll
= TRUE
;
2081 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2083 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2089 //-----------------------------------------------------------------------------
2090 // "button_release_event" from scrollbar
2091 //-----------------------------------------------------------------------------
2093 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2094 GdkEventButton
*WXUNUSED(gdk_event
),
2099 // don't test here as we can release the mouse while being over
2100 // a different window than the slider
2102 // if (gdk_event->window != widget->slider) return FALSE;
2104 g_blockEventsOnScroll
= FALSE
;
2106 if (win
->m_isScrolling
)
2108 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2112 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2113 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2115 value
= (int)(win
->m_hAdjust
->value
+0.5);
2118 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2120 value
= (int)(win
->m_vAdjust
->value
+0.5);
2124 wxScrollWinEvent
event( command
, value
, dir
);
2125 event
.SetEventObject( win
);
2126 win
->GetEventHandler()->ProcessEvent( event
);
2129 win
->m_isScrolling
= FALSE
;
2134 // ----------------------------------------------------------------------------
2135 // this wxWindowBase function is implemented here (in platform-specific file)
2136 // because it is static and so couldn't be made virtual
2137 // ----------------------------------------------------------------------------
2139 wxWindow
*wxWindowBase::FindFocus()
2141 // the cast is necessary when we compile in wxUniversal mode
2142 return (wxWindow
*)g_focusWindow
;
2145 //-----------------------------------------------------------------------------
2146 // "realize" from m_widget
2147 //-----------------------------------------------------------------------------
2149 /* We cannot set colours and fonts before the widget has
2150 been realized, so we do this directly after realization. */
2153 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2158 wxapp_install_idle_handler();
2160 if (win
->m_delayedBackgroundColour
)
2161 win
->SetBackgroundColour( win
->GetBackgroundColour() );
2163 if (win
->m_delayedForegroundColour
)
2164 win
->SetForegroundColour( win
->GetForegroundColour() );
2166 wxWindowCreateEvent
event( win
);
2167 event
.SetEventObject( win
);
2168 win
->GetEventHandler()->ProcessEvent( event
);
2173 //-----------------------------------------------------------------------------
2175 //-----------------------------------------------------------------------------
2178 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2179 GtkAllocation
*WXUNUSED(alloc
),
2183 wxapp_install_idle_handler();
2185 if (!win
->m_hasScrolling
) return;
2187 int client_width
= 0;
2188 int client_height
= 0;
2189 win
->GetClientSize( &client_width
, &client_height
);
2190 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2193 win
->m_oldClientWidth
= client_width
;
2194 win
->m_oldClientHeight
= client_height
;
2196 if (!win
->m_nativeSizeEvent
)
2198 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2199 event
.SetEventObject( win
);
2200 win
->GetEventHandler()->ProcessEvent( event
);
2206 #define WXUNUSED_UNLESS_XIM(param) param
2208 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2211 /* Resize XIM window */
2214 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2215 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2216 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2219 wxapp_install_idle_handler();
2225 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2229 gdk_window_get_size (widget
->window
, &width
, &height
);
2230 win
->m_icattr
->preedit_area
.width
= width
;
2231 win
->m_icattr
->preedit_area
.height
= height
;
2232 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2237 //-----------------------------------------------------------------------------
2238 // "realize" from m_wxwindow
2239 //-----------------------------------------------------------------------------
2241 /* Initialize XIM support */
2244 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2245 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2248 wxapp_install_idle_handler();
2251 if (win
->m_ic
) return FALSE
;
2252 if (!widget
) return FALSE
;
2253 if (!gdk_im_ready()) return FALSE
;
2255 win
->m_icattr
= gdk_ic_attr_new();
2256 if (!win
->m_icattr
) return FALSE
;
2260 GdkColormap
*colormap
;
2261 GdkICAttr
*attr
= win
->m_icattr
;
2262 unsigned attrmask
= GDK_IC_ALL_REQ
;
2264 GdkIMStyle supported_style
= (GdkIMStyle
)
2265 (GDK_IM_PREEDIT_NONE
|
2266 GDK_IM_PREEDIT_NOTHING
|
2267 GDK_IM_PREEDIT_POSITION
|
2268 GDK_IM_STATUS_NONE
|
2269 GDK_IM_STATUS_NOTHING
);
2271 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2272 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2274 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2275 attr
->client_window
= widget
->window
;
2277 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2278 gtk_widget_get_default_colormap ())
2280 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2281 attr
->preedit_colormap
= colormap
;
2284 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2285 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2286 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2287 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2289 switch (style
& GDK_IM_PREEDIT_MASK
)
2291 case GDK_IM_PREEDIT_POSITION
:
2292 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2294 g_warning ("over-the-spot style requires fontset");
2298 gdk_window_get_size (widget
->window
, &width
, &height
);
2300 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2301 attr
->spot_location
.x
= 0;
2302 attr
->spot_location
.y
= height
;
2303 attr
->preedit_area
.x
= 0;
2304 attr
->preedit_area
.y
= 0;
2305 attr
->preedit_area
.width
= width
;
2306 attr
->preedit_area
.height
= height
;
2307 attr
->preedit_fontset
= widget
->style
->font
;
2312 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2314 if (win
->m_ic
== NULL
)
2315 g_warning ("Can't create input context.");
2318 mask
= gdk_window_get_events (widget
->window
);
2319 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2320 gdk_window_set_events (widget
->window
, mask
);
2322 if (GTK_WIDGET_HAS_FOCUS(widget
))
2323 gdk_im_begin (win
->m_ic
, widget
->window
);
2330 //-----------------------------------------------------------------------------
2331 // InsertChild for wxWindowGTK.
2332 //-----------------------------------------------------------------------------
2334 /* Callback for wxWindowGTK. This very strange beast has to be used because
2335 * C++ has no virtual methods in a constructor. We have to emulate a
2336 * virtual function here as wxNotebook requires a different way to insert
2337 * a child in it. I had opted for creating a wxNotebookPage window class
2338 * which would have made this superfluous (such in the MDI window system),
2339 * but no-one was listening to me... */
2341 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2343 /* the window might have been scrolled already, do we
2344 have to adapt the position */
2345 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2346 child
->m_x
+= pizza
->xoffset
;
2347 child
->m_y
+= pizza
->yoffset
;
2349 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2350 GTK_WIDGET(child
->m_widget
),
2357 //-----------------------------------------------------------------------------
2359 //-----------------------------------------------------------------------------
2361 wxWindow
*wxGetActiveWindow()
2363 // the cast is necessary when we compile in wxUniversal mode
2364 return (wxWindow
*)g_focusWindow
;
2367 //-----------------------------------------------------------------------------
2369 //-----------------------------------------------------------------------------
2371 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2373 #ifdef __WXUNIVERSAL__
2374 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2376 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2377 #endif // __WXUNIVERSAL__/__WXGTK__
2379 void wxWindowGTK::Init()
2385 m_widget
= (GtkWidget
*) NULL
;
2386 m_wxwindow
= (GtkWidget
*) NULL
;
2387 m_focusWidget
= (GtkWidget
*) NULL
;
2397 m_needParent
= TRUE
;
2398 m_isBeingDeleted
= FALSE
;
2401 m_nativeSizeEvent
= FALSE
;
2403 m_hasScrolling
= FALSE
;
2404 m_isScrolling
= FALSE
;
2406 m_hAdjust
= (GtkAdjustment
*) NULL
;
2407 m_vAdjust
= (GtkAdjustment
*) NULL
;
2408 m_oldHorizontalPos
= 0.0;
2409 m_oldVerticalPos
= 0.0;
2412 m_widgetStyle
= (GtkStyle
*) NULL
;
2414 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2416 m_isStaticBox
= FALSE
;
2417 m_isRadioButton
= FALSE
;
2418 m_isListBox
= FALSE
;
2420 m_acceptsFocus
= FALSE
;
2422 m_clipPaintRegion
= FALSE
;
2424 m_cursor
= *wxSTANDARD_CURSOR
;
2426 m_delayedForegroundColour
= FALSE
;
2427 m_delayedBackgroundColour
= FALSE
;
2430 m_ic
= (GdkIC
*) NULL
;
2431 m_icattr
= (GdkICAttr
*) NULL
;
2435 wxWindowGTK::wxWindowGTK()
2440 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2445 const wxString
&name
)
2449 Create( parent
, id
, pos
, size
, style
, name
);
2452 bool wxWindowGTK::Create( wxWindow
*parent
,
2457 const wxString
&name
)
2459 if (!PreCreation( parent
, pos
, size
) ||
2460 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2462 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2466 m_insertCallback
= wxInsertChildInWindow
;
2468 // always needed for background clearing
2469 m_delayedBackgroundColour
= TRUE
;
2471 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2472 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2474 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2476 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2477 scroll_class
->scrollbar_spacing
= 0;
2479 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2481 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2482 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2484 m_wxwindow
= gtk_pizza_new();
2486 #ifndef __WXUNIVERSAL__
2487 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2489 if (HasFlag(wxRAISED_BORDER
))
2491 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2493 else if (HasFlag(wxSUNKEN_BORDER
))
2495 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2497 else if (HasFlag(wxSIMPLE_BORDER
))
2499 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2503 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2505 #endif // __WXUNIVERSAL__
2507 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2509 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2510 m_acceptsFocus
= TRUE
;
2512 // I _really_ don't want scrollbars in the beginning
2513 m_vAdjust
->lower
= 0.0;
2514 m_vAdjust
->upper
= 1.0;
2515 m_vAdjust
->value
= 0.0;
2516 m_vAdjust
->step_increment
= 1.0;
2517 m_vAdjust
->page_increment
= 1.0;
2518 m_vAdjust
->page_size
= 5.0;
2519 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2520 m_hAdjust
->lower
= 0.0;
2521 m_hAdjust
->upper
= 1.0;
2522 m_hAdjust
->value
= 0.0;
2523 m_hAdjust
->step_increment
= 1.0;
2524 m_hAdjust
->page_increment
= 1.0;
2525 m_hAdjust
->page_size
= 5.0;
2526 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2528 // these handlers block mouse events to any window during scrolling such as
2529 // motion events and prevent GTK and wxWindows from fighting over where the
2532 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2533 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2535 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2536 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2538 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2539 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2541 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2542 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2544 // these handlers get notified when screen updates are required either when
2545 // scrolling or when the window size (and therefore scrollbar configuration)
2548 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2549 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2550 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2551 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2553 gtk_widget_show( m_wxwindow
);
2556 m_parent
->DoAddChild( this );
2558 m_focusWidget
= m_wxwindow
;
2567 wxWindowGTK::~wxWindowGTK()
2569 if (g_focusWindow
== this)
2570 g_focusWindow
= NULL
;
2572 if (g_activeFrame
== this)
2573 g_activeFrame
= NULL
;
2575 m_isBeingDeleted
= TRUE
;
2584 m_parent
->RemoveChild( this );
2588 gdk_ic_destroy (m_ic
);
2590 gdk_ic_attr_destroy (m_icattr
);
2595 #if DISABLE_STYLE_IF_BROKEN_THEME
2596 // don't delete if it's a pixmap theme style
2597 if (!m_widgetStyle
->engine_data
)
2598 gtk_style_unref( m_widgetStyle
);
2600 m_widgetStyle
= (GtkStyle
*) NULL
;
2605 gtk_widget_destroy( m_wxwindow
);
2606 m_wxwindow
= (GtkWidget
*) NULL
;
2611 gtk_widget_destroy( m_widget
);
2612 m_widget
= (GtkWidget
*) NULL
;
2616 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2618 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2620 /* this turns -1 into 20 so that a minimal window is
2621 visible even although -1,-1 has been given as the
2622 size of the window. the same trick is used in other
2623 ports and should make debugging easier */
2624 m_width
= WidthDefault(size
.x
);
2625 m_height
= HeightDefault(size
.y
);
2630 /* some reasonable defaults */
2635 m_x
= (gdk_screen_width () - m_width
) / 2;
2636 if (m_x
< 10) m_x
= 10;
2640 m_y
= (gdk_screen_height () - m_height
) / 2;
2641 if (m_y
< 10) m_y
= 10;
2648 void wxWindowGTK::PostCreation()
2650 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2656 // these get reported to wxWindows -> wxPaintEvent
2658 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2660 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2661 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2664 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2665 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2667 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2669 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2670 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2673 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2677 // these are called when the "sunken" or "raised" borders are drawn
2678 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2679 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2682 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2683 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2689 if (m_focusWidget
== NULL
)
2690 m_focusWidget
= m_widget
;
2692 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2693 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2695 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2696 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2698 // connect to the various key and mouse handlers
2700 GtkWidget
*connect_widget
= GetConnectWidget();
2702 ConnectWidget( connect_widget
);
2704 /* We cannot set colours, fonts and cursors before the widget has
2705 been realized, so we do this directly after realization */
2706 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2707 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2711 // Catch native resize events
2712 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2713 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2715 // Initialize XIM support
2716 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2717 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2719 // And resize XIM window
2720 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2721 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2724 if (!GTK_IS_COMBO(m_widget
))
2726 // This is needed if we want to add our windows into native
2727 // GTK control, such as the toolbar. With this callback, the
2728 // toolbar gets to know the correct size (the one set by the
2729 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2730 // when moving to GTK 2.0.
2731 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2732 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2738 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2740 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2741 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2743 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2744 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2746 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2747 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2749 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2750 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2752 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2753 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2755 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2756 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2758 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2759 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2762 bool wxWindowGTK::Destroy()
2764 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2768 return wxWindowBase::Destroy();
2771 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2773 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2776 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2778 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2779 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2782 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2785 if (m_resizing
) return; /* I don't like recursions */
2788 int currentX
, currentY
;
2789 GetPosition(¤tX
, ¤tY
);
2794 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2796 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2798 /* don't set the size for children of wxNotebook, just take the values. */
2806 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2807 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2809 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2810 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2811 if (width
!= -1) m_width
= width
;
2812 if (height
!= -1) m_height
= height
;
2816 m_x
= x
+ pizza
->xoffset
;
2817 m_y
= y
+ pizza
->yoffset
;
2822 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2824 if (width
== -1) m_width
= 80;
2827 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2829 if (height
== -1) m_height
= 26;
2832 int minWidth
= GetMinWidth(),
2833 minHeight
= GetMinHeight(),
2834 maxWidth
= GetMaxWidth(),
2835 maxHeight
= GetMaxHeight();
2837 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2838 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2839 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2840 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2843 int bottom_border
= 0;
2846 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2848 /* the default button has a border around it */
2854 DoMoveWindow( m_x
-border
,
2857 m_height
+border
+bottom_border
);
2862 /* Sometimes the client area changes size without the
2863 whole windows's size changing, but if the whole
2864 windows's size doesn't change, no wxSizeEvent will
2865 normally be sent. Here we add an extra test if
2866 the client test has been changed and this will
2868 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2872 wxPrintf( "OnSize sent from " );
2873 if (GetClassInfo() && GetClassInfo()->GetClassName())
2874 wxPrintf( GetClassInfo()->GetClassName() );
2875 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2878 if (!m_nativeSizeEvent
)
2880 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2881 event
.SetEventObject( this );
2882 GetEventHandler()->ProcessEvent( event
);
2888 void wxWindowGTK::OnInternalIdle()
2890 // Update invalidated regions.
2893 // Synthetize activate events.
2894 if ( g_sendActivateEvent
!= -1 )
2896 bool activate
= g_sendActivateEvent
!= 0;
2899 g_sendActivateEvent
= -1;
2901 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2904 if ( g_activeFrameLostFocus
)
2906 if ( g_activeFrame
)
2908 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2909 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2910 event
.SetEventObject(g_activeFrame
);
2911 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2912 g_activeFrame
= NULL
;
2914 g_activeFrameLostFocus
= FALSE
;
2917 wxCursor cursor
= m_cursor
;
2918 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2922 /* I now set the cursor anew in every OnInternalIdle call
2923 as setting the cursor in a parent window also effects the
2924 windows above so that checking for the current cursor is
2929 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2931 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2933 if (!g_globalCursor
.Ok())
2934 cursor
= *wxSTANDARD_CURSOR
;
2936 window
= m_widget
->window
;
2937 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2938 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2944 GdkWindow
*window
= m_widget
->window
;
2945 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2946 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2954 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2956 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2958 if (width
) (*width
) = m_width
;
2959 if (height
) (*height
) = m_height
;
2962 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2964 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2968 SetSize( width
, height
);
2975 #ifndef __WXUNIVERSAL__
2976 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2978 /* when using GTK 1.2 we set the shadow border size to 2 */
2982 if (HasFlag(wxSIMPLE_BORDER
))
2984 /* when using GTK 1.2 we set the simple border size to 1 */
2988 #endif // __WXUNIVERSAL__
2992 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2994 GtkRequisition vscroll_req
;
2995 vscroll_req
.width
= 2;
2996 vscroll_req
.height
= 2;
2997 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2998 (scroll_window
->vscrollbar
, &vscroll_req
);
3000 GtkRequisition hscroll_req
;
3001 hscroll_req
.width
= 2;
3002 hscroll_req
.height
= 2;
3003 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3004 (scroll_window
->hscrollbar
, &hscroll_req
);
3006 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3008 if (scroll_window
->vscrollbar_visible
)
3010 dw
+= vscroll_req
.width
;
3011 dw
+= scroll_class
->scrollbar_spacing
;
3014 if (scroll_window
->hscrollbar_visible
)
3016 dh
+= hscroll_req
.height
;
3017 dh
+= scroll_class
->scrollbar_spacing
;
3021 SetSize( width
+dw
, height
+dh
);
3025 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3027 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3031 if (width
) (*width
) = m_width
;
3032 if (height
) (*height
) = m_height
;
3039 #ifndef __WXUNIVERSAL__
3040 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3042 /* when using GTK 1.2 we set the shadow border size to 2 */
3046 if (HasFlag(wxSIMPLE_BORDER
))
3048 /* when using GTK 1.2 we set the simple border size to 1 */
3052 #endif // __WXUNIVERSAL__
3056 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3058 GtkRequisition vscroll_req
;
3059 vscroll_req
.width
= 2;
3060 vscroll_req
.height
= 2;
3061 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3062 (scroll_window
->vscrollbar
, &vscroll_req
);
3064 GtkRequisition hscroll_req
;
3065 hscroll_req
.width
= 2;
3066 hscroll_req
.height
= 2;
3067 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3068 (scroll_window
->hscrollbar
, &hscroll_req
);
3070 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3072 if (scroll_window
->vscrollbar_visible
)
3074 dw
+= vscroll_req
.width
;
3075 dw
+= scroll_class
->scrollbar_spacing
;
3078 if (scroll_window
->hscrollbar_visible
)
3080 dh
+= hscroll_req
.height
;
3081 dh
+= scroll_class
->scrollbar_spacing
;
3085 if (width
) (*width
) = m_width
- dw
;
3086 if (height
) (*height
) = m_height
- dh
;
3090 printf( "GetClientSize, name %s ", GetName().c_str() );
3091 if (width) printf( " width = %d", (*width) );
3092 if (height) printf( " height = %d", (*height) );
3097 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3099 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3103 if (m_parent
&& m_parent
->m_wxwindow
)
3105 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3106 dx
= pizza
->xoffset
;
3107 dy
= pizza
->yoffset
;
3110 if (x
) (*x
) = m_x
- dx
;
3111 if (y
) (*y
) = m_y
- dy
;
3114 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3116 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3118 if (!m_widget
->window
) return;
3120 GdkWindow
*source
= (GdkWindow
*) NULL
;
3122 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3124 source
= m_widget
->window
;
3128 gdk_window_get_origin( source
, &org_x
, &org_y
);
3132 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3134 org_x
+= m_widget
->allocation
.x
;
3135 org_y
+= m_widget
->allocation
.y
;
3143 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3145 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3147 if (!m_widget
->window
) return;
3149 GdkWindow
*source
= (GdkWindow
*) NULL
;
3151 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3153 source
= m_widget
->window
;
3157 gdk_window_get_origin( source
, &org_x
, &org_y
);
3161 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3163 org_x
+= m_widget
->allocation
.x
;
3164 org_y
+= m_widget
->allocation
.y
;
3172 bool wxWindowGTK::Show( bool show
)
3174 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3176 if (!wxWindowBase::Show(show
))
3183 gtk_widget_show( m_widget
);
3185 gtk_widget_hide( m_widget
);
3190 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3192 win
->OnParentEnable(enable
);
3194 // Recurse, so that children have the opportunity to Do The Right Thing
3195 // and reset colours that have been messed up by a parent's (really ancestor's)
3197 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3199 node
= node
->GetNext() )
3201 wxWindow
*child
= node
->GetData();
3202 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3203 wxWindowNotifyEnable(child
, enable
);
3207 bool wxWindowGTK::Enable( bool enable
)
3209 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3211 if (!wxWindowBase::Enable(enable
))
3217 gtk_widget_set_sensitive( m_widget
, enable
);
3219 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3221 wxWindowNotifyEnable(this, enable
);
3226 int wxWindowGTK::GetCharHeight() const
3228 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3230 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3232 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3234 return font
->ascent
+ font
->descent
;
3237 int wxWindowGTK::GetCharWidth() const
3239 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3241 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3243 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3245 return gdk_string_width( font
, "H" );
3248 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3252 int *externalLeading
,
3253 const wxFont
*theFont
) const
3255 wxFont fontToUse
= m_font
;
3256 if (theFont
) fontToUse
= *theFont
;
3258 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3260 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3261 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3262 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3263 if (descent
) (*descent
) = font
->descent
;
3264 if (externalLeading
) (*externalLeading
) = 0; // ??
3267 void wxWindowGTK::SetFocus()
3269 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3272 wxPrintf( "SetFocus from " );
3273 if (GetClassInfo() && GetClassInfo()->GetClassName())
3274 wxPrintf( GetClassInfo()->GetClassName() );
3280 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3282 gtk_widget_grab_focus (m_wxwindow
);
3287 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3289 gtk_widget_grab_focus (m_widget
);
3291 else if (GTK_IS_CONTAINER(m_widget
))
3293 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3302 bool wxWindowGTK::AcceptsFocus() const
3304 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3307 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3309 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3311 wxWindowGTK
*oldParent
= m_parent
,
3312 *newParent
= (wxWindowGTK
*)newParentBase
;
3314 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3316 if ( !wxWindowBase::Reparent(newParent
) )
3319 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3321 /* prevent GTK from deleting the widget arbitrarily */
3322 gtk_widget_ref( m_widget
);
3326 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3329 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3333 /* insert GTK representation */
3334 (*(newParent
->m_insertCallback
))(newParent
, this);
3337 /* reverse: prevent GTK from deleting the widget arbitrarily */
3338 gtk_widget_unref( m_widget
);
3343 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3345 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3347 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3349 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3354 /* insert GTK representation */
3355 (*m_insertCallback
)(this, child
);
3358 void wxWindowGTK::Raise()
3360 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3362 if (!m_widget
->window
) return;
3364 gdk_window_raise( m_widget
->window
);
3367 void wxWindowGTK::Lower()
3369 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3371 if (!m_widget
->window
) return;
3373 gdk_window_lower( m_widget
->window
);
3376 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3378 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3380 if (cursor
== m_cursor
)
3384 wxapp_install_idle_handler();
3386 if (cursor
== wxNullCursor
)
3387 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3389 return wxWindowBase::SetCursor( cursor
);
3392 void wxWindowGTK::WarpPointer( int x
, int y
)
3394 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3396 // We provide this function ourselves as it is
3397 // missing in GDK (top of this file).
3399 GdkWindow
*window
= (GdkWindow
*) NULL
;
3401 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3403 window
= GetConnectWidget()->window
;
3406 gdk_window_warp_pointer( window
, x
, y
);
3409 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3411 if (!m_widget
) return;
3412 if (!m_widget
->window
) return;
3415 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3419 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3420 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3424 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3425 m_clearRegion
.Clear();
3426 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3434 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3435 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3439 GdkRectangle gdk_rect
;
3440 gdk_rect
.x
= rect
->x
;
3441 gdk_rect
.y
= rect
->y
;
3442 gdk_rect
.width
= rect
->width
;
3443 gdk_rect
.height
= rect
->height
;
3444 gtk_widget_draw( m_widget
, &gdk_rect
);
3451 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3452 m_updateRegion
.Clear();
3453 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3457 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3465 GdkRectangle gdk_rect
;
3466 gdk_rect
.x
= rect
->x
;
3467 gdk_rect
.y
= rect
->y
;
3468 gdk_rect
.width
= rect
->width
;
3469 gdk_rect
.height
= rect
->height
;
3470 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3474 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3480 void wxWindowGTK::Update()
3483 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3484 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3487 if (!m_updateRegion
.IsEmpty())
3488 GtkSendPaintEvents();
3491 void wxWindowGTK::GtkSendPaintEvents()
3495 m_clearRegion
.Clear();
3496 m_updateRegion
.Clear();
3500 m_clipPaintRegion
= TRUE
;
3502 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3504 wxWindowDC
dc( (wxWindow
*)this );
3505 dc
.SetClippingRegion( m_clearRegion
);
3507 wxEraseEvent
erase_event( GetId(), &dc
);
3508 erase_event
.SetEventObject( this );
3510 if (!GetEventHandler()->ProcessEvent(erase_event
))
3514 g_eraseGC
= gdk_gc_new( GTK_PIZZA(m_wxwindow
)->bin_window
);
3515 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3517 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3519 wxRegionIterator
upd( m_clearRegion
);
3522 gdk_draw_rectangle( GTK_PIZZA(m_wxwindow
)->bin_window
, g_eraseGC
, 1,
3523 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3527 m_clearRegion
.Clear();
3530 wxNcPaintEvent
nc_paint_event( GetId() );
3531 nc_paint_event
.SetEventObject( this );
3532 GetEventHandler()->ProcessEvent( nc_paint_event
);
3534 wxPaintEvent
paint_event( GetId() );
3535 paint_event
.SetEventObject( this );
3536 GetEventHandler()->ProcessEvent( paint_event
);
3538 m_clipPaintRegion
= FALSE
;
3540 #ifndef __WXUNIVERSAL__
3542 // The following code will result in all window-less widgets
3543 // being redrawn because the wxWindows class is allowed to
3544 // paint over the window-less widgets.
3546 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3548 GList
*children
= pizza
->children
;
3551 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3552 children
= children
->next
;
3554 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3555 GTK_WIDGET_DRAWABLE (child
->widget
))
3557 // Get intersection of widget area and update region
3558 wxRegion
region( m_updateRegion
);
3560 GdkEventExpose gdk_event
;
3561 gdk_event
.type
= GDK_EXPOSE
;
3562 gdk_event
.window
= pizza
->bin_window
;
3563 gdk_event
.count
= 0;
3565 wxRegionIterator
upd( m_updateRegion
);
3569 rect
.x
= upd
.GetX();
3570 rect
.y
= upd
.GetY();
3571 rect
.width
= upd
.GetWidth();
3572 rect
.height
= upd
.GetHeight();
3574 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3576 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3586 m_updateRegion
.Clear();
3589 void wxWindowGTK::Clear()
3591 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3593 if (!m_widget
->window
) return;
3595 if (m_wxwindow
&& m_wxwindow
->window
)
3597 gdk_window_clear( m_wxwindow
->window
);
3602 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3604 wxWindowBase::DoSetToolTip(tip
);
3607 m_tooltip
->Apply( (wxWindow
*)this );
3610 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3612 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3614 #endif // wxUSE_TOOLTIPS
3616 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3618 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3620 if (!wxWindowBase::SetBackgroundColour(colour
))
3622 // don't leave if the GTK widget has just
3624 if (!m_delayedBackgroundColour
) return FALSE
;
3627 GdkWindow
*window
= (GdkWindow
*) NULL
;
3629 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3631 window
= GetConnectWidget()->window
;
3635 // indicate that a new style has been set
3636 // but it couldn't get applied as the
3637 // widget hasn't been realized yet.
3638 m_delayedBackgroundColour
= TRUE
;
3643 // We need the pixel value e.g. for background clearing.
3644 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3648 (m_wxwindow
->window
) &&
3649 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3651 /* wxMSW doesn't clear the window here. I don't do that either to
3652 provide compatibility. call Clear() to do the job. */
3654 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3662 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3664 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3666 if (!wxWindowBase::SetForegroundColour(colour
))
3668 // don't leave if the GTK widget has just
3670 if (!m_delayedForegroundColour
) return FALSE
;
3673 GdkWindow
*window
= (GdkWindow
*) NULL
;
3675 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3677 window
= GetConnectWidget()->window
;
3681 // indicate that a new style has been set
3682 // but it couldn't get applied as the
3683 // widget hasn't been realized yet.
3684 m_delayedForegroundColour
= TRUE
;
3692 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3696 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3698 // FIXME: no more klass in 2.0
3700 remake
->klass
= m_widgetStyle
->klass
;
3703 gtk_style_unref( m_widgetStyle
);
3704 m_widgetStyle
= remake
;
3708 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3711 def
= gtk_widget_get_default_style();
3713 m_widgetStyle
= gtk_style_copy( def
);
3715 // FIXME: no more klass in 2.0
3717 m_widgetStyle
->klass
= def
->klass
;
3721 return m_widgetStyle
;
3724 void wxWindowGTK::SetWidgetStyle()
3726 #if DISABLE_STYLE_IF_BROKEN_THEME
3727 if (m_widget
->style
->engine_data
)
3729 static bool s_warningPrinted
= FALSE
;
3730 if (!s_warningPrinted
)
3732 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3733 s_warningPrinted
= TRUE
;
3735 m_widgetStyle
= m_widget
->style
;
3740 GtkStyle
*style
= GetWidgetStyle();
3742 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3744 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3747 if (m_foregroundColour
.Ok())
3749 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3750 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3752 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3753 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3754 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3758 // Try to restore the gtk default style. This is still a little
3759 // oversimplified for what is probably really needed here for controls
3760 // other than buttons, but is better than not being able to (re)set a
3761 // control's foreground colour to *wxBLACK -- RL
3762 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3765 def
= gtk_widget_get_default_style();
3767 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3768 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3769 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3773 if (m_backgroundColour
.Ok())
3775 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3776 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3778 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3779 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3780 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3781 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3782 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3783 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3784 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3785 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3789 // Try to restore the gtk default style. This is still a little
3790 // oversimplified for what is probably really needed here for controls
3791 // other than buttons, but is better than not being able to (re)set a
3792 // control's background colour to default grey and means resetting a
3793 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3795 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3798 def
= gtk_widget_get_default_style();
3800 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3801 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3802 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3803 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3804 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3805 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3806 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3807 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3812 void wxWindowGTK::ApplyWidgetStyle()
3816 //-----------------------------------------------------------------------------
3817 // Pop-up menu stuff
3818 //-----------------------------------------------------------------------------
3820 #if wxUSE_MENUS_NATIVE
3823 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3825 *is_waiting
= FALSE
;
3828 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3830 menu
->SetInvokingWindow( win
);
3831 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3834 wxMenuItem
*menuitem
= node
->GetData();
3835 if (menuitem
->IsSubMenu())
3837 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3840 node
= node
->GetNext();
3844 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3845 // wxPopupMenuPositionCallback()
3847 // should be safe even in the MT case as the user can hardly popup 2 menus
3848 // simultaneously, can he?
3849 static gint gs_pop_x
= 0;
3850 static gint gs_pop_y
= 0;
3852 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3855 gboolean
* WXUNUSED(whatever
),
3857 gpointer
WXUNUSED(user_data
) )
3859 // ensure that the menu appears entirely on screen
3861 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3863 wxSize sizeScreen
= wxGetDisplaySize();
3865 gint xmax
= sizeScreen
.x
- req
.width
,
3866 ymax
= sizeScreen
.y
- req
.height
;
3868 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3869 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3872 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3874 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3876 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3878 SetInvokingWindow( menu
, this );
3884 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3886 bool is_waiting
= TRUE
;
3888 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3890 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3891 (gpointer
)&is_waiting
);
3894 GTK_MENU(menu
->m_menu
),
3895 (GtkWidget
*) NULL
, // parent menu shell
3896 (GtkWidget
*) NULL
, // parent menu item
3897 wxPopupMenuPositionCallback
, // function to position it
3898 NULL
, // client data
3899 0, // button used to activate it
3900 gs_timeLastClick
// the time of activation
3905 while (gtk_events_pending())
3906 gtk_main_iteration();
3912 #endif // wxUSE_MENUS_NATIVE
3914 #if wxUSE_DRAG_AND_DROP
3916 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3918 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3920 GtkWidget
*dnd_widget
= GetConnectWidget();
3922 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3924 if (m_dropTarget
) delete m_dropTarget
;
3925 m_dropTarget
= dropTarget
;
3927 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3930 #endif // wxUSE_DRAG_AND_DROP
3932 GtkWidget
* wxWindowGTK::GetConnectWidget()
3934 GtkWidget
*connect_widget
= m_widget
;
3935 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3937 return connect_widget
;
3940 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3943 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3945 return (window
== m_widget
->window
);
3948 bool wxWindowGTK::SetFont( const wxFont
&font
)
3950 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3952 if (!wxWindowBase::SetFont(font
))
3957 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3958 if ( sysbg
== m_backgroundColour
)
3960 m_backgroundColour
= wxNullColour
;
3962 m_backgroundColour
= sysbg
;
3972 void wxWindowGTK::DoCaptureMouse()
3974 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3976 GdkWindow
*window
= (GdkWindow
*) NULL
;
3978 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3980 window
= GetConnectWidget()->window
;
3982 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3984 wxCursor
* cursor
= & m_cursor
;
3986 cursor
= wxSTANDARD_CURSOR
;
3988 gdk_pointer_grab( window
, FALSE
,
3990 (GDK_BUTTON_PRESS_MASK
|
3991 GDK_BUTTON_RELEASE_MASK
|
3992 GDK_POINTER_MOTION_HINT_MASK
|
3993 GDK_POINTER_MOTION_MASK
),
3995 cursor
->GetCursor(),
3996 (guint32
)GDK_CURRENT_TIME
);
3997 g_captureWindow
= this;
3998 g_captureWindowHasMouse
= TRUE
;
4001 void wxWindowGTK::DoReleaseMouse()
4003 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4005 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4007 g_captureWindow
= (wxWindowGTK
*) NULL
;
4009 GdkWindow
*window
= (GdkWindow
*) NULL
;
4011 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4013 window
= GetConnectWidget()->window
;
4018 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4022 wxWindow
*wxWindowBase::GetCapture()
4024 return (wxWindow
*)g_captureWindow
;
4027 bool wxWindowGTK::IsRetained() const
4032 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4033 int range
, bool refresh
)
4035 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4037 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4039 m_hasScrolling
= TRUE
;
4041 if (orient
== wxHORIZONTAL
)
4043 float fpos
= (float)pos
;
4044 float frange
= (float)range
;
4045 float fthumb
= (float)thumbVisible
;
4046 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4047 if (fpos
< 0.0) fpos
= 0.0;
4049 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4050 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4052 SetScrollPos( orient
, pos
, refresh
);
4056 m_oldHorizontalPos
= fpos
;
4058 m_hAdjust
->lower
= 0.0;
4059 m_hAdjust
->upper
= frange
;
4060 m_hAdjust
->value
= fpos
;
4061 m_hAdjust
->step_increment
= 1.0;
4062 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4063 m_hAdjust
->page_size
= fthumb
;
4067 float fpos
= (float)pos
;
4068 float frange
= (float)range
;
4069 float fthumb
= (float)thumbVisible
;
4070 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4071 if (fpos
< 0.0) fpos
= 0.0;
4073 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4074 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4076 SetScrollPos( orient
, pos
, refresh
);
4080 m_oldVerticalPos
= fpos
;
4082 m_vAdjust
->lower
= 0.0;
4083 m_vAdjust
->upper
= frange
;
4084 m_vAdjust
->value
= fpos
;
4085 m_vAdjust
->step_increment
= 1.0;
4086 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4087 m_vAdjust
->page_size
= fthumb
;
4090 if (orient
== wxHORIZONTAL
)
4091 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4093 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4096 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4098 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4100 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4102 if (orient
== wxHORIZONTAL
)
4104 float fpos
= (float)pos
;
4105 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4106 if (fpos
< 0.0) fpos
= 0.0;
4107 m_oldHorizontalPos
= fpos
;
4109 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4110 m_hAdjust
->value
= fpos
;
4114 float fpos
= (float)pos
;
4115 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4116 if (fpos
< 0.0) fpos
= 0.0;
4117 m_oldVerticalPos
= fpos
;
4119 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4120 m_vAdjust
->value
= fpos
;
4123 if (m_wxwindow
->window
)
4125 if (orient
== wxHORIZONTAL
)
4127 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4128 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4130 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4132 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4133 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4137 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4138 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4140 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4142 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4143 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4148 int wxWindowGTK::GetScrollThumb( int orient
) const
4150 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4152 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4154 if (orient
== wxHORIZONTAL
)
4155 return (int)(m_hAdjust
->page_size
+0.5);
4157 return (int)(m_vAdjust
->page_size
+0.5);
4160 int wxWindowGTK::GetScrollPos( int orient
) const
4162 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4164 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4166 if (orient
== wxHORIZONTAL
)
4167 return (int)(m_hAdjust
->value
+0.5);
4169 return (int)(m_vAdjust
->value
+0.5);
4172 int wxWindowGTK::GetScrollRange( int orient
) const
4174 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4176 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4178 if (orient
== wxHORIZONTAL
)
4179 return (int)(m_hAdjust
->upper
+0.5);
4181 return (int)(m_vAdjust
->upper
+0.5);
4184 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4186 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4188 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4190 // No scrolling requested.
4191 if ((dx
== 0) && (dy
== 0)) return;
4194 if (!m_updateRegion
.IsEmpty())
4196 m_updateRegion
.Offset( dx
, dy
);
4200 GetClientSize( &cw
, &ch
);
4201 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4204 if (!m_clearRegion
.IsEmpty())
4206 m_clearRegion
.Offset( dx
, dy
);
4210 GetClientSize( &cw
, &ch
);
4211 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4214 m_clipPaintRegion
= TRUE
;
4216 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4218 m_clipPaintRegion
= FALSE
;
4221 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4223 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4224 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4231 // Find the wxWindow at the current mouse position, also returning the mouse
4233 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4235 pt
= wxGetMousePosition();
4236 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4240 // Get the current mouse position.
4241 wxPoint
wxGetMousePosition()
4243 /* This crashes when used within wxHelpContext,
4244 so we have to use the X-specific implementation below.
4246 GdkModifierType *mask;
4247 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4249 return wxPoint(x, y);
4253 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4255 return wxPoint(-999, -999);
4257 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4258 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4259 Window rootReturn
, childReturn
;
4260 int rootX
, rootY
, winX
, winY
;
4261 unsigned int maskReturn
;
4263 XQueryPointer (display
,
4267 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4268 return wxPoint(rootX
, rootY
);
4272 // ----------------------------------------------------------------------------
4274 // ----------------------------------------------------------------------------
4276 class wxWinModule
: public wxModule
4283 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4286 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4288 bool wxWinModule::OnInit()
4290 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4291 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4296 void wxWinModule::OnExit()
4299 gdk_gc_unref( g_eraseGC
);