1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "window.h"
16 #define XWarpPointer XWARPPOINTER
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
24 #include "wx/layout.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28 #include "wx/module.h"
30 #if wxUSE_DRAG_AND_DROP
35 #include "wx/tooltip.h"
43 #include "wx/textctrl.h"
47 #include "wx/statusbr.h"
49 #include "wx/settings.h"
53 #include "wx/thread.h"
58 #include "wx/gtk/private.h"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
69 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
71 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
81 extern GtkContainerClass
*pizza_parent_class
;
84 //-----------------------------------------------------------------------------
85 // documentation on internals
86 //-----------------------------------------------------------------------------
89 I have been asked several times about writing some documentation about
90 the GTK port of wxWindows, especially its internal structures. Obviously,
91 you cannot understand wxGTK without knowing a little about the GTK, but
92 some more information about what the wxWindow, which is the base class
93 for all other window classes, does seems required as well.
97 What does wxWindow do? It contains the common interface for the following
98 jobs of its descendants:
100 1) Define the rudimentary behaviour common to all window classes, such as
101 resizing, intercepting user input (so as to make it possible to use these
102 events for special purposes in a derived class), window names etc.
104 2) Provide the possibility to contain and manage children, if the derived
105 class is allowed to contain children, which holds true for those window
106 classes which do not display a native GTK widget. To name them, these
107 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
108 work classes are a special case and are handled a bit differently from
109 the rest. The same holds true for the wxNotebook class.
111 3) Provide the possibility to draw into a client area of a window. This,
112 too, only holds true for classes that do not display a native GTK widget
115 4) Provide the entire mechanism for scrolling widgets. This actual inter-
116 face for this is usually in wxScrolledWindow, but the GTK implementation
119 5) A multitude of helper or extra methods for special purposes, such as
120 Drag'n'Drop, managing validators etc.
122 6) Display a border (sunken, raised, simple or none).
124 Normally one might expect, that one wxWindows window would always correspond
125 to one GTK widget. Under GTK, there is no such allround widget that has all
126 the functionality. Moreover, the GTK defines a client area as a different
127 widget from the actual widget you are handling. Last but not least some
128 special classes (e.g. wxFrame) handle different categories of widgets and
129 still have the possibility to draw something in the client area.
130 It was therefore required to write a special purpose GTK widget, that would
131 represent a client area in the sense of wxWindows capable to do the jobs
132 2), 3) and 4). I have written this class and it resides in win_gtk.c of
135 All windows must have a widget, with which they interact with other under-
136 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
137 thw wxWindow class has a member variable called m_widget which holds a
138 pointer to this widget. When the window class represents a GTK native widget,
139 this is (in most cases) the only GTK widget the class manages. E.g. the
140 wxStatitText class handles only a GtkLabel widget a pointer to which you
141 can find in m_widget (defined in wxWindow)
143 When the class has a client area for drawing into and for containing children
144 it has to handle the client area widget (of the type GtkPizza, defined in
145 win_gtk.c), but there could be any number of widgets, handled by a class
146 The common rule for all windows is only, that the widget that interacts with
147 the rest of GTK must be referenced in m_widget and all other widgets must be
148 children of this widget on the GTK level. The top-most widget, which also
149 represents the client area, must be in the m_wxwindow field and must be of
152 As I said, the window classes that display a GTK native widget only have
153 one widget, so in the case of e.g. the wxButton class m_widget holds a
154 pointer to a GtkButton widget. But windows with client areas (for drawing
155 and children) have a m_widget field that is a pointer to a GtkScrolled-
156 Window and a m_wxwindow field that is pointer to a GtkPizza and this
157 one is (in the GTK sense) a child of the GtkScrolledWindow.
159 If the m_wxwindow field is set, then all input to this widget is inter-
160 cepted and sent to the wxWindows class. If not, all input to the widget
161 that gets pointed to by m_widget gets intercepted and sent to the class.
165 The design of scrolling in wxWindows is markedly different from that offered
166 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
167 clicking on a scrollbar belonging to scrolled window will inevitably move
168 the window. In wxWindows, the scrollbar will only emit an event, send this
169 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
170 which actually moves the window and its subchildren. Note that GtkPizza
171 memorizes how much it has been scrolled but that wxWindows forgets this
172 so that the two coordinates systems have to be kept in synch. This is done
173 in various places using the pizza->xoffset and pizza->yoffset values.
177 Singularily the most broken code in GTK is the code that is supposes to
178 inform subwindows (child windows) about new positions. Very often, duplicate
179 events are sent without changes in size or position, equally often no
180 events are sent at all (All this is due to a bug in the GtkContainer code
181 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
182 GTK's own system and it simply waits for size events for toplevel windows
183 and then iterates down the respective size events to all window. This has
184 the disadvantage, that windows might get size events before the GTK widget
185 actually has the reported size. This doesn't normally pose any problem, but
186 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
187 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
188 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
189 window that is used for OpenGl output really has that size (as reported by
194 If someone at some point of time feels the immense desire to have a look at,
195 change or attempt to optimse the Refresh() logic, this person will need an
196 intimate understanding of what a "draw" and what an "expose" events are and
197 what there are used for, in particular when used in connection with GTK's
198 own windowless widgets. Beware.
202 Cursors, too, have been a constant source of pleasure. The main difficulty
203 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
204 for the parent. To prevent this from doing too much harm, I use idle time
205 to set the cursor over and over again, starting from the toplevel windows
206 and ending with the youngest generation (speaking of parent and child windows).
207 Also don't forget that cursors (like much else) are connected to GdkWindows,
208 not GtkWidgets and that the "window" field of a GtkWidget might very well
209 point to the GdkWindow of the parent widget (-> "window less widget") and
210 that the two obviously have very different meanings.
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 extern wxList wxPendingDelete
;
219 extern bool g_blockEventsOnDrag
;
220 extern bool g_blockEventsOnScroll
;
221 extern wxCursor g_globalCursor
;
223 static GdkGC
*g_eraseGC
= NULL
;
225 // mouse capture state: the window which has it and if the mouse is currently
227 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
228 static bool g_captureWindowHasMouse
= FALSE
;
230 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
232 // the last window which had the focus - this is normally never NULL (except
233 // if we never had focus at all) as even when g_focusWindow is NULL it still
234 // keeps its previous value
235 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
237 // the frame that is currently active (i.e. its child has focus). It is
238 // used to generate wxActivateEvents
239 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
240 static bool g_activeFrameLostFocus
= FALSE
;
242 // If a window get the focus set but has not been realized
243 // yet, defer setting the focus to idle time.
244 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
246 // if we detect that the app has got/lost the focus, we set this variable to
247 // either TRUE or FALSE and an activate event will be sent during the next
248 // OnIdle() call and it is reset to -1: this value means that we shouldn't
249 // send any activate events at all
250 static int g_sendActivateEvent
= -1;
252 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
253 the last click here */
254 static guint32 gs_timeLastClick
= 0;
256 extern bool g_mainThreadLocked
;
258 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
263 #define DISABLE_STYLE_IF_BROKEN_THEME 1
269 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
271 # define DEBUG_MAIN_THREAD
274 static gint
gtk_debug_focus_in_callback( GtkWidget
*WXUNUSED(widget
),
275 GdkEvent
*WXUNUSED(event
),
276 const wxChar
*WXUNUSED(name
) )
279 static bool s_done = FALSE;
282 wxLog::AddTraceMask("focus");
285 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
291 void debug_focus_in( GtkWidget
* widget
, const wxChar
* name
, const wxChar
*window
)
293 // suppress warnings about gtk_debug_focus_in_callback being unused with
298 tmp
+= wxT(" FROM ");
301 wxChar
*s
= new wxChar
[tmp
.Length()+1];
305 gtk_signal_connect( GTK_OBJECT(widget
), "focus_in_event",
306 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback
), (gpointer
)s
);
311 #define DEBUG_MAIN_THREAD
314 //-----------------------------------------------------------------------------
315 // missing gdk functions
316 //-----------------------------------------------------------------------------
319 gdk_window_warp_pointer (GdkWindow
*window
,
324 GdkWindowPrivate
*priv
;
328 window
= GDK_ROOT_PARENT();
331 if (!GDK_WINDOW_DESTROYED(window
))
333 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
334 None
, /* not source window -> move from anywhere */
335 GDK_WINDOW_XID(window
), /* dest window */
336 0, 0, 0, 0, /* not source window -> move from anywhere */
340 priv
= (GdkWindowPrivate
*) window
;
342 if (!priv
->destroyed
)
344 XWarpPointer (priv
->xdisplay
,
345 None
, /* not source window -> move from anywhere */
346 priv
->xwindow
, /* dest window */
347 0, 0, 0, 0, /* not source window -> move from anywhere */
353 //-----------------------------------------------------------------------------
355 //-----------------------------------------------------------------------------
357 extern void wxapp_install_idle_handler();
358 extern bool g_isIdle
;
360 //-----------------------------------------------------------------------------
361 // local code (see below)
362 //-----------------------------------------------------------------------------
364 // returns the child of win which currently has focus or NULL if not found
366 // Note: can't be static, needed by textctrl.cpp.
367 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
369 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
371 return (wxWindow
*)NULL
;
373 if ( winFocus
== win
)
374 return (wxWindow
*)win
;
376 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
378 node
= node
->GetNext() )
380 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
385 return (wxWindow
*)NULL
;
388 // Returns toplevel grandparent of given window:
389 static wxWindowGTK
* wxGetTopLevelParent(wxWindowGTK
*win
)
391 wxWindowGTK
*p
= win
;
392 while (p
&& !p
->IsTopLevel())
397 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
399 // wxUniversal widgets draw the borders and scrollbars themselves
400 #ifndef __WXUNIVERSAL__
407 if (win
->m_hasScrolling
)
409 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
411 GtkRequisition vscroll_req
;
412 vscroll_req
.width
= 2;
413 vscroll_req
.height
= 2;
414 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
415 (scroll_window
->vscrollbar
, &vscroll_req
);
417 GtkRequisition hscroll_req
;
418 hscroll_req
.width
= 2;
419 hscroll_req
.height
= 2;
420 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
421 (scroll_window
->hscrollbar
, &hscroll_req
);
423 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
425 if (scroll_window
->vscrollbar_visible
)
427 dw
+= vscroll_req
.width
;
428 dw
+= scroll_class
->scrollbar_spacing
;
431 if (scroll_window
->hscrollbar_visible
)
433 dh
+= hscroll_req
.height
;
434 dh
+= scroll_class
->scrollbar_spacing
;
440 if (GTK_WIDGET_NO_WINDOW (widget
))
442 dx
+= widget
->allocation
.x
;
443 dy
+= widget
->allocation
.y
;
446 if (win
->HasFlag(wxRAISED_BORDER
))
448 gtk_draw_shadow( widget
->style
,
453 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
457 if (win
->HasFlag(wxSUNKEN_BORDER
))
459 gtk_draw_shadow( widget
->style
,
464 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
468 if (win
->HasFlag(wxSIMPLE_BORDER
))
471 gc
= gdk_gc_new( widget
->window
);
472 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
473 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
475 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
479 #endif // __WXUNIVERSAL__
482 //-----------------------------------------------------------------------------
483 // "expose_event" of m_widget
484 //-----------------------------------------------------------------------------
486 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
488 if (gdk_event
->count
> 0) return FALSE
;
490 draw_frame( widget
, win
);
494 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
500 //-----------------------------------------------------------------------------
501 // "draw" of m_widget
502 //-----------------------------------------------------------------------------
506 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
508 draw_frame( widget
, win
);
513 //-----------------------------------------------------------------------------
514 // "size_request" of m_widget
515 //-----------------------------------------------------------------------------
517 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
520 win
->GetSize( &w
, &h
);
524 requisition
->height
= h
;
525 requisition
->width
= w
;
528 //-----------------------------------------------------------------------------
529 // "expose_event" of m_wxwindow
530 //-----------------------------------------------------------------------------
532 static int gtk_window_expose_callback( GtkWidget
*widget
,
533 GdkEventExpose
*gdk_event
,
539 wxapp_install_idle_handler();
544 wxPrintf( wxT("OnExpose from ") );
545 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
546 wxPrintf( win
->GetClassInfo()->GetClassName() );
547 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
548 (int)gdk_event
->area
.y
,
549 (int)gdk_event
->area
.width
,
550 (int)gdk_event
->area
.height
);
554 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
556 gdk_event
->area
.width
,
557 gdk_event
->area
.height
);
559 // Actual redrawing takes place in idle time.
564 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
571 //-----------------------------------------------------------------------------
572 // "event" of m_wxwindow
573 //-----------------------------------------------------------------------------
575 // GTK thinks it is clever and filters out a certain amount of "unneeded"
576 // expose events. We need them, of course, so we override the main event
577 // procedure in GtkWidget by giving our own handler for all system events.
578 // There, we look for expose events ourselves whereas all other events are
581 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
582 GdkEventExpose
*event
,
585 if (event
->type
== GDK_EXPOSE
)
587 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
594 //-----------------------------------------------------------------------------
595 // "draw" of m_wxwindow
596 //-----------------------------------------------------------------------------
600 // This callback is a complete replacement of the gtk_pizza_draw() function,
601 // which is disabled.
603 static void gtk_window_draw_callback( GtkWidget
*widget
,
610 wxapp_install_idle_handler();
612 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
613 // there are no child windows.
614 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
615 (win
->GetChildren().GetCount() == 0))
623 wxPrintf( wxT("OnDraw from ") );
624 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
625 wxPrintf( win
->GetClassInfo()->GetClassName() );
626 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
633 #ifndef __WXUNIVERSAL__
634 GtkPizza
*pizza
= GTK_PIZZA (widget
);
636 if (win
->GetThemeEnabled())
638 wxWindow
*parent
= win
->GetParent();
639 while (parent
&& !parent
->IsTopLevel())
640 parent
= parent
->GetParent();
644 gtk_paint_flat_box (parent
->m_widget
->style
,
655 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
656 (pizza
->clear_on_draw
))
658 gdk_window_clear_area( pizza
->bin_window
,
659 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
663 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
665 // Actual redrawing takes place in idle time.
669 #ifndef __WXUNIVERSAL__
670 // Redraw child widgets
671 GList
*children
= pizza
->children
;
674 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
675 children
= children
->next
;
677 GdkRectangle child_area
;
678 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
680 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
688 //-----------------------------------------------------------------------------
689 // "key_press_event" from any window
690 //-----------------------------------------------------------------------------
692 // set WXTRACE to this to see the key event codes on the console
693 #define TRACE_KEYS _T("keyevent")
695 // translates an X key symbol to WXK_XXX value
697 // if isChar is true it means that the value returned will be used for EVT_CHAR
698 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
699 // for example, while if it is false it means that the value is going to be
700 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
702 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
708 // Shift, Control and Alt don't generate the CHAR events at all
711 key_code
= isChar
? 0 : WXK_SHIFT
;
715 key_code
= isChar
? 0 : WXK_CONTROL
;
723 key_code
= isChar
? 0 : WXK_ALT
;
726 // neither do the toggle modifies
727 case GDK_Scroll_Lock
:
728 key_code
= isChar
? 0 : WXK_SCROLL
;
732 key_code
= isChar
? 0 : WXK_CAPITAL
;
736 key_code
= isChar
? 0 : WXK_NUMLOCK
;
740 // various other special keys
753 case GDK_ISO_Left_Tab
:
760 key_code
= WXK_RETURN
;
764 key_code
= WXK_CLEAR
;
768 key_code
= WXK_PAUSE
;
772 key_code
= WXK_SELECT
;
776 key_code
= WXK_PRINT
;
780 key_code
= WXK_EXECUTE
;
784 key_code
= WXK_ESCAPE
;
787 // cursor and other extended keyboard keys
789 key_code
= WXK_DELETE
;
805 key_code
= WXK_RIGHT
;
812 case GDK_Prior
: // == GDK_Page_Up
813 key_code
= WXK_PRIOR
;
816 case GDK_Next
: // == GDK_Page_Down
829 key_code
= WXK_INSERT
;
844 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
848 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
852 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
856 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
860 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
864 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
868 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
872 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
876 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
880 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
884 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
888 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
892 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
895 case GDK_KP_Prior
: // == GDK_KP_Page_Up
896 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
899 case GDK_KP_Next
: // == GDK_KP_Page_Down
900 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
904 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
908 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
912 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
916 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
920 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
923 case GDK_KP_Multiply
:
924 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
928 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
931 case GDK_KP_Separator
:
932 // FIXME: what is this?
933 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
936 case GDK_KP_Subtract
:
937 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
941 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
945 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
962 key_code
= WXK_F1
+ keysym
- GDK_F1
;
972 static inline bool wxIsAsciiKeysym(KeySym ks
)
978 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
980 GdkEventKey
*gdk_event
)
982 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
983 // but only event->keyval which is quite useless to us, so remember
984 // the last character from GDK_KEY_PRESS and reuse it as last resort
986 // NB: should be MT-safe as we're always called from the main thread only
991 } s_lastKeyPress
= { 0, 0 };
993 KeySym keysym
= gdk_event
->keyval
;
995 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %d"),
996 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
1000 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
1004 // do we have the translation or is it a plain ASCII character?
1005 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1007 // we should use keysym if it is ASCII as X does some translations
1008 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1009 // which we don't want here (but which we do use for OnChar())
1010 if ( !wxIsAsciiKeysym(keysym
) )
1012 keysym
= (KeySym
)gdk_event
->string
[0];
1015 // we want to always get the same key code when the same key is
1016 // pressed regardless of the state of the modifies, i.e. on a
1017 // standard US keyboard pressing '5' or '%' ('5' key with
1018 // Shift) should result in the same key code in OnKeyDown():
1019 // '5' (although OnChar() will get either '5' or '%').
1021 // to do it we first translate keysym to keycode (== scan code)
1022 // and then back but always using the lower register
1023 Display
*dpy
= (Display
*)wxGetDisplay();
1024 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1026 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1028 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1030 // use the normalized, i.e. lower register, keysym if we've
1032 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1034 // as explained above, we want to have lower register key codes
1035 // normally but for the letter keys we want to have the upper ones
1037 // NB: don't use XConvertCase() here, we want to do it for letters
1039 key_code
= toupper(key_code
);
1041 else // non ASCII key, what to do?
1043 // by default, ignore it
1046 // but if we have cached information from the last KEY_PRESS
1047 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1050 if ( keysym
== s_lastKeyPress
.keysym
)
1052 key_code
= s_lastKeyPress
.keycode
;
1057 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1059 // remember it to be reused for KEY_UP event later
1060 s_lastKeyPress
.keysym
= keysym
;
1061 s_lastKeyPress
.keycode
= key_code
;
1065 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %d"), key_code
);
1067 // sending unknown key events doesn't really make sense
1071 // now fill all the other fields
1074 GdkModifierType state
;
1075 if (gdk_event
->window
)
1076 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1078 event
.SetTimestamp( gdk_event
->time
);
1079 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1080 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1081 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1082 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1083 event
.m_keyCode
= key_code
;
1084 event
.m_scanCode
= gdk_event
->keyval
;
1085 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1086 event
.m_rawFlags
= 0;
1089 event
.SetEventObject( win
);
1094 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1095 GdkEventKey
*gdk_event
,
1101 wxapp_install_idle_handler();
1105 if (g_blockEventsOnDrag
)
1108 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1109 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1111 // unknown key pressed, ignore (the event would be useless anyhow)
1115 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1120 wxWindowGTK
*ancestor
= win
;
1123 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1126 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1127 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1130 if (ancestor
->IsTopLevel())
1132 ancestor
= ancestor
->GetParent();
1135 #endif // wxUSE_ACCEL
1137 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1138 will only be sent if it is not in an accelerator table. */
1141 KeySym keysym
= gdk_event
->keyval
;
1142 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1145 if ( gdk_event
->length
== 1 )
1147 key_code
= (unsigned char)gdk_event
->string
[0];
1149 else if ( wxIsAsciiKeysym(keysym
) )
1152 key_code
= (unsigned char)keysym
;
1158 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1160 // reuse the same event object, just change its type and use the
1161 // translated keycode instead of the raw one
1162 event
.SetEventType(wxEVT_CHAR
);
1163 event
.m_keyCode
= key_code
;
1165 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1169 /* win is a control: tab can be propagated up */
1171 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1172 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1173 // have this style, yet choose not to process this particular TAB in which
1174 // case TAB must still work as a navigational character
1176 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1178 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1180 wxNavigationKeyEvent new_event
;
1181 new_event
.SetEventObject( win
->GetParent() );
1182 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1183 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1184 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1185 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1186 new_event
.SetCurrentFocus( win
);
1187 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1190 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1192 (gdk_event
->keyval
== GDK_Escape
) )
1194 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1195 new_event
.SetEventObject( win
);
1196 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1200 #if 0 // (GTK_MINOR_VERSION > 0)
1201 /* Pressing F10 will activate the menu bar of the top frame. */
1203 (gdk_event
->keyval
== GDK_F10
) )
1205 wxWindowGTK
*ancestor
= win
;
1208 if (wxIsKindOf(ancestor
,wxFrame
))
1210 wxFrame
*frame
= (wxFrame
*) ancestor
;
1211 wxMenuBar
*menubar
= frame
->GetMenuBar();
1214 wxNode
*node
= menubar
->GetMenus().First();
1217 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1218 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1224 ancestor
= ancestor
->GetParent();
1231 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1238 //-----------------------------------------------------------------------------
1239 // "key_release_event" from any window
1240 //-----------------------------------------------------------------------------
1242 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1243 GdkEventKey
*gdk_event
,
1249 wxapp_install_idle_handler();
1254 if (g_blockEventsOnDrag
)
1257 wxKeyEvent
event( wxEVT_KEY_UP
);
1258 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1260 // unknown key pressed, ignore (the event would be useless anyhow
1264 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1267 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1271 // ============================================================================
1273 // ============================================================================
1275 // init wxMouseEvent with the info from gdk_event
1276 #define InitMouseEvent(win, event, gdk_event) \
1278 event.SetTimestamp( gdk_event->time ); \
1279 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1280 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1281 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1282 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1283 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1284 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1285 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1287 wxPoint pt = win->GetClientAreaOrigin(); \
1288 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1289 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1292 // ----------------------------------------------------------------------------
1293 // mouse event processing helper
1294 // ----------------------------------------------------------------------------
1296 static void AdjustEventButtonState(wxMouseEvent
& event
)
1298 // GDK reports the old state of the button for a button press event, but
1299 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1300 // for a LEFT_DOWN event, not FALSE, so we will invert
1301 // left/right/middleDown for the corresponding click events
1303 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1304 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1305 (event
.GetEventType() == wxEVT_LEFT_UP
))
1307 event
.m_leftDown
= !event
.m_leftDown
;
1311 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1312 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1313 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1315 event
.m_middleDown
= !event
.m_middleDown
;
1319 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1320 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1321 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1323 event
.m_rightDown
= !event
.m_rightDown
;
1328 //-----------------------------------------------------------------------------
1329 // "button_press_event"
1330 //-----------------------------------------------------------------------------
1332 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1337 wxapp_install_idle_handler();
1340 wxPrintf( wxT("1) OnButtonPress from ") );
1341 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1342 wxPrintf( win->GetClassInfo()->GetClassName() );
1343 wxPrintf( wxT(".\n") );
1345 if (!win
->m_hasVMT
) return FALSE
;
1346 if (g_blockEventsOnDrag
) return TRUE
;
1347 if (g_blockEventsOnScroll
) return TRUE
;
1349 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1351 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1353 gtk_widget_grab_focus( win
->m_wxwindow
);
1355 wxPrintf( wxT("GrabFocus from ") );
1356 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1357 wxPrintf( win->GetClassInfo()->GetClassName() );
1358 wxPrintf( wxT(".\n") );
1362 wxEventType event_type
= wxEVT_NULL
;
1364 if (gdk_event
->button
== 1)
1366 switch (gdk_event
->type
)
1368 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1369 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1373 else if (gdk_event
->button
== 2)
1375 switch (gdk_event
->type
)
1377 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1378 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1382 else if (gdk_event
->button
== 3)
1384 switch (gdk_event
->type
)
1386 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1387 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1392 if ( event_type
== wxEVT_NULL
)
1394 // unknown mouse button or click type
1398 wxMouseEvent
event( event_type
);
1399 InitMouseEvent( win
, event
, gdk_event
);
1401 AdjustEventButtonState(event
);
1403 // wxListBox actually get mouse events from the item
1405 if (win
->m_isListBox
)
1407 event
.m_x
+= widget
->allocation
.x
;
1408 event
.m_y
+= widget
->allocation
.y
;
1411 // Some control don't have their own X window and thus cannot get
1414 if (!g_captureWindow
)
1416 wxCoord x
= event
.m_x
;
1417 wxCoord y
= event
.m_y
;
1418 if (win
->m_wxwindow
)
1420 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1421 x
+= pizza
->xoffset
;
1422 y
+= pizza
->yoffset
;
1425 wxNode
*node
= win
->GetChildren().First();
1428 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1430 node
= node
->Next();
1431 if (!child
->IsShown())
1434 if (child
->m_isStaticBox
)
1436 // wxStaticBox is transparent in the box itself
1437 int xx1
= child
->m_x
;
1438 int yy1
= child
->m_y
;
1439 int xx2
= child
->m_x
+ child
->m_width
;
1440 int yy2
= child
->m_x
+ child
->m_height
;
1443 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1445 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1447 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1449 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1452 event
.m_x
-= child
->m_x
;
1453 event
.m_y
-= child
->m_y
;
1460 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1461 (child
->m_x
<= x
) &&
1462 (child
->m_y
<= y
) &&
1463 (child
->m_x
+child
->m_width
>= x
) &&
1464 (child
->m_y
+child
->m_height
>= y
))
1467 event
.m_x
-= child
->m_x
;
1468 event
.m_y
-= child
->m_y
;
1475 event
.SetEventObject( win
);
1477 gs_timeLastClick
= gdk_event
->time
;
1480 wxPrintf( wxT("2) OnButtonPress from ") );
1481 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1482 wxPrintf( win->GetClassInfo()->GetClassName() );
1483 wxPrintf( wxT(".\n") );
1486 if (win
->GetEventHandler()->ProcessEvent( event
))
1488 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1495 //-----------------------------------------------------------------------------
1496 // "button_release_event"
1497 //-----------------------------------------------------------------------------
1499 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1504 wxapp_install_idle_handler();
1506 if (!win
->m_hasVMT
) return FALSE
;
1507 if (g_blockEventsOnDrag
) return FALSE
;
1508 if (g_blockEventsOnScroll
) return FALSE
;
1510 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1513 printf( "OnButtonRelease from " );
1514 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1515 printf( win->GetClassInfo()->GetClassName() );
1519 wxEventType event_type
= wxEVT_NULL
;
1521 switch (gdk_event
->button
)
1523 case 1: event_type
= wxEVT_LEFT_UP
; break;
1524 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1525 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1526 default: return FALSE
;
1529 wxMouseEvent
event( event_type
);
1530 InitMouseEvent( win
, event
, gdk_event
);
1532 AdjustEventButtonState(event
);
1534 // wxListBox actually get mouse events from the item
1536 if (win
->m_isListBox
)
1538 event
.m_x
+= widget
->allocation
.x
;
1539 event
.m_y
+= widget
->allocation
.y
;
1542 // Some control don't have their own X window and thus cannot get
1545 if (!g_captureWindow
)
1547 wxCoord x
= event
.m_x
;
1548 wxCoord y
= event
.m_y
;
1549 if (win
->m_wxwindow
)
1551 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1552 x
+= pizza
->xoffset
;
1553 y
+= pizza
->yoffset
;
1556 wxNode
*node
= win
->GetChildren().First();
1559 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1561 node
= node
->Next();
1562 if (!child
->IsShown())
1565 if (child
->m_isStaticBox
)
1567 // wxStaticBox is transparent in the box itself
1568 int xx1
= child
->m_x
;
1569 int yy1
= child
->m_y
;
1570 int xx2
= child
->m_x
+ child
->m_width
;
1571 int yy2
= child
->m_x
+ child
->m_height
;
1574 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1576 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1578 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1580 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1583 event
.m_x
-= child
->m_x
;
1584 event
.m_y
-= child
->m_y
;
1591 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1592 (child
->m_x
<= x
) &&
1593 (child
->m_y
<= y
) &&
1594 (child
->m_x
+child
->m_width
>= x
) &&
1595 (child
->m_y
+child
->m_height
>= y
))
1598 event
.m_x
-= child
->m_x
;
1599 event
.m_y
-= child
->m_y
;
1606 event
.SetEventObject( win
);
1608 if (win
->GetEventHandler()->ProcessEvent( event
))
1610 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1617 //-----------------------------------------------------------------------------
1618 // "motion_notify_event"
1619 //-----------------------------------------------------------------------------
1621 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1622 GdkEventMotion
*gdk_event
,
1628 wxapp_install_idle_handler();
1630 if (!win
->m_hasVMT
) return FALSE
;
1631 if (g_blockEventsOnDrag
) return FALSE
;
1632 if (g_blockEventsOnScroll
) return FALSE
;
1634 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1636 if (gdk_event
->is_hint
)
1640 GdkModifierType state
;
1641 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1647 printf( "OnMotion from " );
1648 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1649 printf( win->GetClassInfo()->GetClassName() );
1653 wxMouseEvent
event( wxEVT_MOTION
);
1654 InitMouseEvent(win
, event
, gdk_event
);
1656 if ( g_captureWindow
)
1658 // synthetize a mouse enter or leave event if needed
1659 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1660 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1661 if ( hasMouse
!= g_captureWindowHasMouse
)
1663 // the mouse changed window
1664 g_captureWindowHasMouse
= hasMouse
;
1666 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1667 : wxEVT_LEAVE_WINDOW
);
1668 InitMouseEvent(win
, event
, gdk_event
);
1669 event
.SetEventObject(win
);
1670 win
->GetEventHandler()->ProcessEvent(event
);
1675 // Some control don't have their own X window and thus cannot get
1678 wxCoord x
= event
.m_x
;
1679 wxCoord y
= event
.m_y
;
1680 if (win
->m_wxwindow
)
1682 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1683 x
+= pizza
->xoffset
;
1684 y
+= pizza
->yoffset
;
1687 wxNode
*node
= win
->GetChildren().First();
1690 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1692 node
= node
->Next();
1693 if (!child
->IsShown())
1696 if (child
->m_isStaticBox
)
1698 // wxStaticBox is transparent in the box itself
1699 int xx1
= child
->m_x
;
1700 int yy1
= child
->m_y
;
1701 int xx2
= child
->m_x
+ child
->m_width
;
1702 int yy2
= child
->m_x
+ child
->m_height
;
1705 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1707 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1709 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1711 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1714 event
.m_x
-= child
->m_x
;
1715 event
.m_y
-= child
->m_y
;
1722 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1723 (child
->m_x
<= x
) &&
1724 (child
->m_y
<= y
) &&
1725 (child
->m_x
+child
->m_width
>= x
) &&
1726 (child
->m_y
+child
->m_height
>= y
))
1729 event
.m_x
-= child
->m_x
;
1730 event
.m_y
-= child
->m_y
;
1737 event
.SetEventObject( win
);
1739 if (win
->GetEventHandler()->ProcessEvent( event
))
1741 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1748 //-----------------------------------------------------------------------------
1750 //-----------------------------------------------------------------------------
1752 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1753 GdkEvent
*WXUNUSED(event
),
1759 wxapp_install_idle_handler();
1761 if (!win
->m_hasVMT
) return FALSE
;
1762 if (g_blockEventsOnDrag
) return FALSE
;
1764 switch ( g_sendActivateEvent
)
1767 // we've got focus from outside, synthetize wxActivateEvent
1768 g_sendActivateEvent
= 1;
1772 // another our window just lost focus, it was already ours before
1773 // - don't send any wxActivateEvent
1774 g_sendActivateEvent
= -1;
1779 g_focusWindow
= win
;
1782 printf( "OnSetFocus 2 from %s\n", win
->GetName().c_str() );
1785 // Notify the parent keeping track of focus for the kbd navigation
1786 // purposes that we got it.
1787 wxChildFocusEvent
eventFocus(win
);
1788 (void)win
->GetEventHandler()->ProcessEvent(eventFocus
);
1792 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1796 // caret needs to be informed about focus change
1797 wxCaret
*caret
= win
->GetCaret();
1800 caret
->OnSetFocus();
1802 #endif // wxUSE_CARET
1804 g_activeFrameLostFocus
= FALSE
;
1806 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1807 if ( active
!= g_activeFrame
)
1809 if ( g_activeFrame
)
1811 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1812 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1813 event
.SetEventObject(g_activeFrame
);
1814 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1817 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1818 g_activeFrame
= active
;
1819 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1820 event
.SetEventObject(g_activeFrame
);
1821 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1823 // Don't send focus events in addition to activate
1824 // if (win == g_activeFrame)
1829 wxFocusEvent
event( wxEVT_SET_FOCUS
, win
->GetId() );
1830 event
.SetEventObject( win
);
1832 if (win
->GetEventHandler()->ProcessEvent( event
))
1834 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1841 //-----------------------------------------------------------------------------
1842 // "focus_out_event"
1843 //-----------------------------------------------------------------------------
1845 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1850 wxapp_install_idle_handler();
1852 if (!win
->m_hasVMT
) return FALSE
;
1853 if (g_blockEventsOnDrag
) return FALSE
;
1856 wxLogDebug( wxT("OnKillFocus from %s"), win
->GetName().c_str() );
1859 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1861 // VZ: commenting this out because it does happen (although not easy
1862 // to reproduce, I only see it when using wxMiniFrame and not
1863 // always) and makes using Mahogany quite annoying
1865 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1866 wxT("unfocusing window that hasn't gained focus properly") )
1869 g_activeFrameLostFocus
= TRUE
;
1872 // if the focus goes out of our app alltogether, OnIdle() will send
1873 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1874 // g_sendActivateEvent to -1
1875 g_sendActivateEvent
= 0;
1877 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1881 g_focusWindow
= (wxWindowGTK
*)NULL
;
1889 // caret needs to be informed about focus change
1890 wxCaret
*caret
= win
->GetCaret();
1893 caret
->OnKillFocus();
1895 #endif // wxUSE_CARET
1897 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1898 event
.SetEventObject( win
);
1900 if (win
->GetEventHandler()->ProcessEvent( event
))
1902 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1909 //-----------------------------------------------------------------------------
1910 // "enter_notify_event"
1911 //-----------------------------------------------------------------------------
1913 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1918 wxapp_install_idle_handler();
1920 if (!win
->m_hasVMT
) return FALSE
;
1921 if (g_blockEventsOnDrag
) return FALSE
;
1923 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1925 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1926 event
.SetTimestamp( gdk_event
->time
);
1927 event
.SetEventObject( win
);
1931 GdkModifierType state
= (GdkModifierType
)0;
1933 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1935 InitMouseEvent(win
, event
, gdk_event
);
1936 wxPoint pt
= win
->GetClientAreaOrigin();
1937 event
.m_x
= x
+ pt
.x
;
1938 event
.m_y
= y
+ pt
.y
;
1940 if (win
->GetEventHandler()->ProcessEvent( event
))
1942 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1949 //-----------------------------------------------------------------------------
1950 // "leave_notify_event"
1951 //-----------------------------------------------------------------------------
1953 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1958 wxapp_install_idle_handler();
1960 if (!win
->m_hasVMT
) return FALSE
;
1961 if (g_blockEventsOnDrag
) return FALSE
;
1963 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1965 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1966 event
.SetTimestamp( gdk_event
->time
);
1967 event
.SetEventObject( win
);
1971 GdkModifierType state
= (GdkModifierType
)0;
1973 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1975 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1976 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1977 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1978 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1979 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1980 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1981 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1983 wxPoint pt
= win
->GetClientAreaOrigin();
1984 event
.m_x
= x
+ pt
.x
;
1985 event
.m_y
= y
+ pt
.y
;
1987 if (win
->GetEventHandler()->ProcessEvent( event
))
1989 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1996 //-----------------------------------------------------------------------------
1997 // "value_changed" from m_vAdjust
1998 //-----------------------------------------------------------------------------
2000 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2007 wxapp_install_idle_handler();
2009 if (g_blockEventsOnDrag
) return;
2011 if (!win
->m_hasVMT
) return;
2013 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2014 if (fabs(diff
) < 0.2) return;
2016 win
->m_oldVerticalPos
= adjust
->value
;
2018 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
2020 int value
= (int)(adjust
->value
+0.5);
2022 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2023 event
.SetEventObject( win
);
2024 win
->GetEventHandler()->ProcessEvent( event
);
2027 //-----------------------------------------------------------------------------
2028 // "value_changed" from m_hAdjust
2029 //-----------------------------------------------------------------------------
2031 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2038 wxapp_install_idle_handler();
2040 if (g_blockEventsOnDrag
) return;
2041 if (!win
->m_hasVMT
) return;
2043 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2044 if (fabs(diff
) < 0.2) return;
2046 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
2048 win
->m_oldHorizontalPos
= adjust
->value
;
2050 int value
= (int)(adjust
->value
+0.5);
2052 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2053 event
.SetEventObject( win
);
2054 win
->GetEventHandler()->ProcessEvent( event
);
2057 //-----------------------------------------------------------------------------
2058 // "button_press_event" from scrollbar
2059 //-----------------------------------------------------------------------------
2061 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2062 GdkEventButton
*gdk_event
,
2068 wxapp_install_idle_handler();
2071 g_blockEventsOnScroll
= TRUE
;
2073 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2075 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2081 //-----------------------------------------------------------------------------
2082 // "button_release_event" from scrollbar
2083 //-----------------------------------------------------------------------------
2085 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2086 GdkEventButton
*WXUNUSED(gdk_event
),
2091 // don't test here as we can release the mouse while being over
2092 // a different window than the slider
2094 // if (gdk_event->window != widget->slider) return FALSE;
2096 g_blockEventsOnScroll
= FALSE
;
2098 if (win
->m_isScrolling
)
2100 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2104 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2105 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2107 value
= (int)(win
->m_hAdjust
->value
+0.5);
2110 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2112 value
= (int)(win
->m_vAdjust
->value
+0.5);
2116 wxScrollWinEvent
event( command
, value
, dir
);
2117 event
.SetEventObject( win
);
2118 win
->GetEventHandler()->ProcessEvent( event
);
2121 win
->m_isScrolling
= FALSE
;
2126 // ----------------------------------------------------------------------------
2127 // this wxWindowBase function is implemented here (in platform-specific file)
2128 // because it is static and so couldn't be made virtual
2129 // ----------------------------------------------------------------------------
2131 wxWindow
*wxWindowBase::FindFocus()
2133 // the cast is necessary when we compile in wxUniversal mode
2134 return (wxWindow
*)g_focusWindow
;
2137 //-----------------------------------------------------------------------------
2138 // "realize" from m_widget
2139 //-----------------------------------------------------------------------------
2141 /* We cannot set colours and fonts before the widget has
2142 been realized, so we do this directly after realization. */
2145 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2150 wxapp_install_idle_handler();
2152 if (win
->m_delayedBackgroundColour
)
2153 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2155 if (win
->m_delayedForegroundColour
)
2156 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2158 wxWindowCreateEvent
event( win
);
2159 event
.SetEventObject( win
);
2160 win
->GetEventHandler()->ProcessEvent( event
);
2165 //-----------------------------------------------------------------------------
2167 //-----------------------------------------------------------------------------
2170 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2171 GtkAllocation
*WXUNUSED(alloc
),
2175 wxapp_install_idle_handler();
2177 if (!win
->m_hasScrolling
) return;
2179 int client_width
= 0;
2180 int client_height
= 0;
2181 win
->GetClientSize( &client_width
, &client_height
);
2182 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2185 win
->m_oldClientWidth
= client_width
;
2186 win
->m_oldClientHeight
= client_height
;
2188 if (!win
->m_nativeSizeEvent
)
2190 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2191 event
.SetEventObject( win
);
2192 win
->GetEventHandler()->ProcessEvent( event
);
2198 #define WXUNUSED_UNLESS_XIM(param) param
2200 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2203 /* Resize XIM window */
2206 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2207 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2208 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2211 wxapp_install_idle_handler();
2217 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2221 gdk_window_get_size (widget
->window
, &width
, &height
);
2222 win
->m_icattr
->preedit_area
.width
= width
;
2223 win
->m_icattr
->preedit_area
.height
= height
;
2224 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2229 //-----------------------------------------------------------------------------
2230 // "realize" from m_wxwindow
2231 //-----------------------------------------------------------------------------
2233 /* Initialize XIM support */
2236 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2237 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2240 wxapp_install_idle_handler();
2243 if (win
->m_ic
) return FALSE
;
2244 if (!widget
) return FALSE
;
2245 if (!gdk_im_ready()) return FALSE
;
2247 win
->m_icattr
= gdk_ic_attr_new();
2248 if (!win
->m_icattr
) return FALSE
;
2252 GdkColormap
*colormap
;
2253 GdkICAttr
*attr
= win
->m_icattr
;
2254 unsigned attrmask
= GDK_IC_ALL_REQ
;
2256 GdkIMStyle supported_style
= (GdkIMStyle
)
2257 (GDK_IM_PREEDIT_NONE
|
2258 GDK_IM_PREEDIT_NOTHING
|
2259 GDK_IM_PREEDIT_POSITION
|
2260 GDK_IM_STATUS_NONE
|
2261 GDK_IM_STATUS_NOTHING
);
2263 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2264 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2266 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2267 attr
->client_window
= widget
->window
;
2269 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2270 gtk_widget_get_default_colormap ())
2272 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2273 attr
->preedit_colormap
= colormap
;
2276 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2277 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2278 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2279 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2281 switch (style
& GDK_IM_PREEDIT_MASK
)
2283 case GDK_IM_PREEDIT_POSITION
:
2284 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2286 g_warning ("over-the-spot style requires fontset");
2290 gdk_window_get_size (widget
->window
, &width
, &height
);
2292 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2293 attr
->spot_location
.x
= 0;
2294 attr
->spot_location
.y
= height
;
2295 attr
->preedit_area
.x
= 0;
2296 attr
->preedit_area
.y
= 0;
2297 attr
->preedit_area
.width
= width
;
2298 attr
->preedit_area
.height
= height
;
2299 attr
->preedit_fontset
= widget
->style
->font
;
2304 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2306 if (win
->m_ic
== NULL
)
2307 g_warning ("Can't create input context.");
2310 mask
= gdk_window_get_events (widget
->window
);
2311 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2312 gdk_window_set_events (widget
->window
, mask
);
2314 if (GTK_WIDGET_HAS_FOCUS(widget
))
2315 gdk_im_begin (win
->m_ic
, widget
->window
);
2322 //-----------------------------------------------------------------------------
2323 // InsertChild for wxWindowGTK.
2324 //-----------------------------------------------------------------------------
2326 /* Callback for wxWindowGTK. This very strange beast has to be used because
2327 * C++ has no virtual methods in a constructor. We have to emulate a
2328 * virtual function here as wxNotebook requires a different way to insert
2329 * a child in it. I had opted for creating a wxNotebookPage window class
2330 * which would have made this superfluous (such in the MDI window system),
2331 * but no-one was listening to me... */
2333 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2335 /* the window might have been scrolled already, do we
2336 have to adapt the position */
2337 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2338 child
->m_x
+= pizza
->xoffset
;
2339 child
->m_y
+= pizza
->yoffset
;
2341 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2342 GTK_WIDGET(child
->m_widget
),
2349 //-----------------------------------------------------------------------------
2351 //-----------------------------------------------------------------------------
2353 wxWindow
*wxGetActiveWindow()
2355 // the cast is necessary when we compile in wxUniversal mode
2356 return (wxWindow
*)g_focusWindow
;
2359 //-----------------------------------------------------------------------------
2361 //-----------------------------------------------------------------------------
2363 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2365 #ifdef __WXUNIVERSAL__
2366 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2368 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2369 #endif // __WXUNIVERSAL__/__WXGTK__
2371 void wxWindowGTK::Init()
2377 m_widget
= (GtkWidget
*) NULL
;
2378 m_wxwindow
= (GtkWidget
*) NULL
;
2379 m_focusWidget
= (GtkWidget
*) NULL
;
2389 m_needParent
= TRUE
;
2390 m_isBeingDeleted
= FALSE
;
2393 m_nativeSizeEvent
= FALSE
;
2395 m_hasScrolling
= FALSE
;
2396 m_isScrolling
= FALSE
;
2398 m_hAdjust
= (GtkAdjustment
*) NULL
;
2399 m_vAdjust
= (GtkAdjustment
*) NULL
;
2400 m_oldHorizontalPos
= 0.0;
2401 m_oldVerticalPos
= 0.0;
2404 m_widgetStyle
= (GtkStyle
*) NULL
;
2406 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2408 m_isStaticBox
= FALSE
;
2409 m_isRadioButton
= FALSE
;
2410 m_isListBox
= FALSE
;
2412 m_acceptsFocus
= FALSE
;
2414 m_clipPaintRegion
= FALSE
;
2416 m_cursor
= *wxSTANDARD_CURSOR
;
2418 m_delayedForegroundColour
= FALSE
;
2419 m_delayedBackgroundColour
= FALSE
;
2422 m_ic
= (GdkIC
*) NULL
;
2423 m_icattr
= (GdkICAttr
*) NULL
;
2427 wxWindowGTK::wxWindowGTK()
2432 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2437 const wxString
&name
)
2441 Create( parent
, id
, pos
, size
, style
, name
);
2444 bool wxWindowGTK::Create( wxWindow
*parent
,
2449 const wxString
&name
)
2451 if (!PreCreation( parent
, pos
, size
) ||
2452 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2454 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2458 m_insertCallback
= wxInsertChildInWindow
;
2460 // always needed for background clearing
2461 m_delayedBackgroundColour
= TRUE
;
2463 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2464 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2466 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2468 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2469 scroll_class
->scrollbar_spacing
= 0;
2471 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2473 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2474 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2476 m_wxwindow
= gtk_pizza_new();
2478 #ifndef __WXUNIVERSAL__
2479 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2481 if (HasFlag(wxRAISED_BORDER
))
2483 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2485 else if (HasFlag(wxSUNKEN_BORDER
))
2487 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2489 else if (HasFlag(wxSIMPLE_BORDER
))
2491 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2495 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2497 #endif // __WXUNIVERSAL__
2499 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2501 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2502 m_acceptsFocus
= TRUE
;
2504 // I _really_ don't want scrollbars in the beginning
2505 m_vAdjust
->lower
= 0.0;
2506 m_vAdjust
->upper
= 1.0;
2507 m_vAdjust
->value
= 0.0;
2508 m_vAdjust
->step_increment
= 1.0;
2509 m_vAdjust
->page_increment
= 1.0;
2510 m_vAdjust
->page_size
= 5.0;
2511 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2512 m_hAdjust
->lower
= 0.0;
2513 m_hAdjust
->upper
= 1.0;
2514 m_hAdjust
->value
= 0.0;
2515 m_hAdjust
->step_increment
= 1.0;
2516 m_hAdjust
->page_increment
= 1.0;
2517 m_hAdjust
->page_size
= 5.0;
2518 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2520 // these handlers block mouse events to any window during scrolling such as
2521 // motion events and prevent GTK and wxWindows from fighting over where the
2524 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2525 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2527 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2528 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2530 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2531 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2533 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2534 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2536 // these handlers get notified when screen updates are required either when
2537 // scrolling or when the window size (and therefore scrollbar configuration)
2540 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2541 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2542 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2543 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2545 gtk_widget_show( m_wxwindow
);
2548 m_parent
->DoAddChild( this );
2550 m_focusWidget
= m_wxwindow
;
2559 wxWindowGTK::~wxWindowGTK()
2561 if (g_focusWindow
== this)
2562 g_focusWindow
= NULL
;
2564 if (g_activeFrame
== this)
2565 g_activeFrame
= NULL
;
2567 m_isBeingDeleted
= TRUE
;
2576 m_parent
->RemoveChild( this );
2580 gdk_ic_destroy (m_ic
);
2582 gdk_ic_attr_destroy (m_icattr
);
2587 #if DISABLE_STYLE_IF_BROKEN_THEME
2588 // don't delete if it's a pixmap theme style
2589 if (!m_widgetStyle
->engine_data
)
2590 gtk_style_unref( m_widgetStyle
);
2592 m_widgetStyle
= (GtkStyle
*) NULL
;
2597 gtk_widget_destroy( m_wxwindow
);
2598 m_wxwindow
= (GtkWidget
*) NULL
;
2603 gtk_widget_destroy( m_widget
);
2604 m_widget
= (GtkWidget
*) NULL
;
2608 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2610 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2612 /* this turns -1 into 20 so that a minimal window is
2613 visible even although -1,-1 has been given as the
2614 size of the window. the same trick is used in other
2615 ports and should make debugging easier */
2616 m_width
= WidthDefault(size
.x
);
2617 m_height
= HeightDefault(size
.y
);
2622 /* some reasonable defaults */
2627 m_x
= (gdk_screen_width () - m_width
) / 2;
2628 if (m_x
< 10) m_x
= 10;
2632 m_y
= (gdk_screen_height () - m_height
) / 2;
2633 if (m_y
< 10) m_y
= 10;
2640 void wxWindowGTK::PostCreation()
2642 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2648 // these get reported to wxWindows -> wxPaintEvent
2650 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2652 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2653 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2656 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2657 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2659 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2661 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2662 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2665 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2669 // these are called when the "sunken" or "raised" borders are drawn
2670 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2671 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2674 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2675 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2681 if (m_focusWidget
== NULL
)
2682 m_focusWidget
= m_widget
;
2684 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2685 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2687 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2688 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2690 // connect to the various key and mouse handlers
2692 GtkWidget
*connect_widget
= GetConnectWidget();
2694 ConnectWidget( connect_widget
);
2696 /* We cannot set colours, fonts and cursors before the widget has
2697 been realized, so we do this directly after realization */
2698 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2699 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2703 // Catch native resize events
2704 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2705 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2707 // Initialize XIM support
2708 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2709 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2711 // And resize XIM window
2712 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2713 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2716 if (!GTK_IS_COMBO(m_widget
))
2718 // This is needed if we want to add our windows into native
2719 // GTK control, such as the toolbar. With this callback, the
2720 // toolbar gets to know the correct size (the one set by the
2721 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2722 // when moving to GTK 2.0.
2723 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2724 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2730 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2732 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2733 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2735 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2736 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2738 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2739 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2741 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2742 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2744 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2745 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2747 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2748 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2750 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2751 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2754 bool wxWindowGTK::Destroy()
2756 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2760 return wxWindowBase::Destroy();
2763 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2765 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2768 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2770 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2771 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2774 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2777 if (m_resizing
) return; /* I don't like recursions */
2780 int currentX
, currentY
;
2781 GetPosition(¤tX
, ¤tY
);
2786 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2788 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2790 /* don't set the size for children of wxNotebook, just take the values. */
2798 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2799 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2801 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2802 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2803 if (width
!= -1) m_width
= width
;
2804 if (height
!= -1) m_height
= height
;
2808 m_x
= x
+ pizza
->xoffset
;
2809 m_y
= y
+ pizza
->yoffset
;
2814 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2816 if (width
== -1) m_width
= 80;
2819 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2821 if (height
== -1) m_height
= 26;
2824 int minWidth
= GetMinWidth(),
2825 minHeight
= GetMinHeight(),
2826 maxWidth
= GetMaxWidth(),
2827 maxHeight
= GetMaxHeight();
2829 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2830 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2831 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2832 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2835 int bottom_border
= 0;
2838 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2840 /* the default button has a border around it */
2846 DoMoveWindow( m_x
-border
,
2849 m_height
+border
+bottom_border
);
2854 /* Sometimes the client area changes size without the
2855 whole windows's size changing, but if the whole
2856 windows's size doesn't change, no wxSizeEvent will
2857 normally be sent. Here we add an extra test if
2858 the client test has been changed and this will
2860 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2864 wxPrintf( "OnSize sent from " );
2865 if (GetClassInfo() && GetClassInfo()->GetClassName())
2866 wxPrintf( GetClassInfo()->GetClassName() );
2867 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2870 if (!m_nativeSizeEvent
)
2872 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2873 event
.SetEventObject( this );
2874 GetEventHandler()->ProcessEvent( event
);
2880 void wxWindowGTK::OnInternalIdle()
2882 // Update invalidated regions.
2885 // Synthetize activate events.
2886 if ( g_sendActivateEvent
!= -1 )
2888 bool activate
= g_sendActivateEvent
!= 0;
2891 g_sendActivateEvent
= -1;
2893 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2896 if ( g_activeFrameLostFocus
)
2898 if ( g_activeFrame
)
2900 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2901 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2902 event
.SetEventObject(g_activeFrame
);
2903 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2904 g_activeFrame
= NULL
;
2906 g_activeFrameLostFocus
= FALSE
;
2909 if (g_delayedFocus
== this)
2911 if (GTK_WIDGET_REALIZED(m_widget
))
2913 gtk_widget_grab_focus( m_widget
);
2914 g_delayedFocus
= NULL
;
2918 wxCursor cursor
= m_cursor
;
2919 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2923 /* I now set the cursor anew in every OnInternalIdle call
2924 as setting the cursor in a parent window also effects the
2925 windows above so that checking for the current cursor is
2930 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2932 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2934 if (!g_globalCursor
.Ok())
2935 cursor
= *wxSTANDARD_CURSOR
;
2937 window
= m_widget
->window
;
2938 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2939 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2945 GdkWindow
*window
= m_widget
->window
;
2946 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2947 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2955 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2957 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2959 if (width
) (*width
) = m_width
;
2960 if (height
) (*height
) = m_height
;
2963 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2965 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2969 SetSize( width
, height
);
2976 #ifndef __WXUNIVERSAL__
2977 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2979 /* when using GTK 1.2 we set the shadow border size to 2 */
2983 if (HasFlag(wxSIMPLE_BORDER
))
2985 /* when using GTK 1.2 we set the simple border size to 1 */
2989 #endif // __WXUNIVERSAL__
2993 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2995 GtkRequisition vscroll_req
;
2996 vscroll_req
.width
= 2;
2997 vscroll_req
.height
= 2;
2998 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2999 (scroll_window
->vscrollbar
, &vscroll_req
);
3001 GtkRequisition hscroll_req
;
3002 hscroll_req
.width
= 2;
3003 hscroll_req
.height
= 2;
3004 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3005 (scroll_window
->hscrollbar
, &hscroll_req
);
3007 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3009 if (scroll_window
->vscrollbar_visible
)
3011 dw
+= vscroll_req
.width
;
3012 dw
+= scroll_class
->scrollbar_spacing
;
3015 if (scroll_window
->hscrollbar_visible
)
3017 dh
+= hscroll_req
.height
;
3018 dh
+= scroll_class
->scrollbar_spacing
;
3022 SetSize( width
+dw
, height
+dh
);
3026 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3028 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3032 if (width
) (*width
) = m_width
;
3033 if (height
) (*height
) = m_height
;
3040 #ifndef __WXUNIVERSAL__
3041 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3043 /* when using GTK 1.2 we set the shadow border size to 2 */
3047 if (HasFlag(wxSIMPLE_BORDER
))
3049 /* when using GTK 1.2 we set the simple border size to 1 */
3053 #endif // __WXUNIVERSAL__
3057 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3059 GtkRequisition vscroll_req
;
3060 vscroll_req
.width
= 2;
3061 vscroll_req
.height
= 2;
3062 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3063 (scroll_window
->vscrollbar
, &vscroll_req
);
3065 GtkRequisition hscroll_req
;
3066 hscroll_req
.width
= 2;
3067 hscroll_req
.height
= 2;
3068 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3069 (scroll_window
->hscrollbar
, &hscroll_req
);
3071 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3073 if (scroll_window
->vscrollbar_visible
)
3075 dw
+= vscroll_req
.width
;
3076 dw
+= scroll_class
->scrollbar_spacing
;
3079 if (scroll_window
->hscrollbar_visible
)
3081 dh
+= hscroll_req
.height
;
3082 dh
+= scroll_class
->scrollbar_spacing
;
3086 if (width
) (*width
) = m_width
- dw
;
3087 if (height
) (*height
) = m_height
- dh
;
3091 printf( "GetClientSize, name %s ", GetName().c_str() );
3092 if (width) printf( " width = %d", (*width) );
3093 if (height) printf( " height = %d", (*height) );
3098 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3100 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3104 if (m_parent
&& m_parent
->m_wxwindow
)
3106 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3107 dx
= pizza
->xoffset
;
3108 dy
= pizza
->yoffset
;
3111 if (x
) (*x
) = m_x
- dx
;
3112 if (y
) (*y
) = m_y
- dy
;
3115 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3117 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3119 if (!m_widget
->window
) return;
3121 GdkWindow
*source
= (GdkWindow
*) NULL
;
3123 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3125 source
= m_widget
->window
;
3129 gdk_window_get_origin( source
, &org_x
, &org_y
);
3133 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3135 org_x
+= m_widget
->allocation
.x
;
3136 org_y
+= m_widget
->allocation
.y
;
3144 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3146 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3148 if (!m_widget
->window
) return;
3150 GdkWindow
*source
= (GdkWindow
*) NULL
;
3152 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3154 source
= m_widget
->window
;
3158 gdk_window_get_origin( source
, &org_x
, &org_y
);
3162 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3164 org_x
+= m_widget
->allocation
.x
;
3165 org_y
+= m_widget
->allocation
.y
;
3173 bool wxWindowGTK::Show( bool show
)
3175 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3177 if (!wxWindowBase::Show(show
))
3184 gtk_widget_show( m_widget
);
3186 gtk_widget_hide( m_widget
);
3191 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3193 win
->OnParentEnable(enable
);
3195 // Recurse, so that children have the opportunity to Do The Right Thing
3196 // and reset colours that have been messed up by a parent's (really ancestor's)
3198 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3200 node
= node
->GetNext() )
3202 wxWindow
*child
= node
->GetData();
3203 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3204 wxWindowNotifyEnable(child
, enable
);
3208 bool wxWindowGTK::Enable( bool enable
)
3210 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3212 if (!wxWindowBase::Enable(enable
))
3218 gtk_widget_set_sensitive( m_widget
, enable
);
3220 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3222 wxWindowNotifyEnable(this, enable
);
3227 int wxWindowGTK::GetCharHeight() const
3229 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3231 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3233 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3235 return font
->ascent
+ font
->descent
;
3238 int wxWindowGTK::GetCharWidth() const
3240 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3242 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3244 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3246 return gdk_string_width( font
, "H" );
3249 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3253 int *externalLeading
,
3254 const wxFont
*theFont
) const
3256 wxFont fontToUse
= m_font
;
3257 if (theFont
) fontToUse
= *theFont
;
3259 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3261 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3262 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3263 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3264 if (descent
) (*descent
) = font
->descent
;
3265 if (externalLeading
) (*externalLeading
) = 0; // ??
3268 void wxWindowGTK::SetFocus()
3270 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3274 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3276 gtk_widget_grab_focus (m_wxwindow
);
3281 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3283 if (!GTK_WIDGET_REALIZED(m_widget
))
3284 g_delayedFocus
= this;
3286 gtk_widget_grab_focus (m_widget
);
3288 else if (GTK_IS_CONTAINER(m_widget
))
3290 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3299 bool wxWindowGTK::AcceptsFocus() const
3301 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3304 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3306 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3308 wxWindowGTK
*oldParent
= m_parent
,
3309 *newParent
= (wxWindowGTK
*)newParentBase
;
3311 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3313 if ( !wxWindowBase::Reparent(newParent
) )
3316 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3318 /* prevent GTK from deleting the widget arbitrarily */
3319 gtk_widget_ref( m_widget
);
3323 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3326 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3330 /* insert GTK representation */
3331 (*(newParent
->m_insertCallback
))(newParent
, this);
3334 /* reverse: prevent GTK from deleting the widget arbitrarily */
3335 gtk_widget_unref( m_widget
);
3340 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3342 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3344 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3346 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3351 /* insert GTK representation */
3352 (*m_insertCallback
)(this, child
);
3355 void wxWindowGTK::Raise()
3357 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3359 if (!m_widget
->window
) return;
3361 gdk_window_raise( m_widget
->window
);
3364 void wxWindowGTK::Lower()
3366 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3368 if (!m_widget
->window
) return;
3370 gdk_window_lower( m_widget
->window
);
3373 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3375 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3377 if (cursor
== m_cursor
)
3381 wxapp_install_idle_handler();
3383 if (cursor
== wxNullCursor
)
3384 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3386 return wxWindowBase::SetCursor( cursor
);
3389 void wxWindowGTK::WarpPointer( int x
, int y
)
3391 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3393 // We provide this function ourselves as it is
3394 // missing in GDK (top of this file).
3396 GdkWindow
*window
= (GdkWindow
*) NULL
;
3398 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3400 window
= GetConnectWidget()->window
;
3403 gdk_window_warp_pointer( window
, x
, y
);
3406 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3408 if (!m_widget
) return;
3409 if (!m_widget
->window
) return;
3413 wxapp_install_idle_handler();
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()
3485 void wxWindowGTK::GtkUpdate()
3488 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3489 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3492 if (!m_updateRegion
.IsEmpty())
3493 GtkSendPaintEvents();
3496 void wxWindowGTK::GtkSendPaintEvents()
3500 m_clearRegion
.Clear();
3501 m_updateRegion
.Clear();
3505 m_clipPaintRegion
= TRUE
;
3507 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3509 wxWindowDC
dc( (wxWindow
*)this );
3510 dc
.SetClippingRegion( m_clearRegion
);
3512 wxEraseEvent
erase_event( GetId(), &dc
);
3513 erase_event
.SetEventObject( this );
3515 if (!GetEventHandler()->ProcessEvent(erase_event
))
3519 g_eraseGC
= gdk_gc_new( GTK_PIZZA(m_wxwindow
)->bin_window
);
3520 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3522 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3524 // widget to draw on
3525 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3527 // find ancestor from which to steal background
3528 wxWindow
*parent
= GetParent();
3529 while (parent
&& !parent
->IsTopLevel())
3530 parent
= parent
->GetParent();
3534 wxRegionIterator
upd( m_clearRegion
);
3537 if (GetThemeEnabled())
3540 rect
.x
= upd
.GetX();
3541 rect
.y
= upd
.GetY();
3542 rect
.width
= upd
.GetWidth();
3543 rect
.height
= upd
.GetHeight();
3545 gtk_paint_flat_box( parent
->m_widget
->style
,
3556 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3557 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3562 m_clearRegion
.Clear();
3565 wxNcPaintEvent
nc_paint_event( GetId() );
3566 nc_paint_event
.SetEventObject( this );
3567 GetEventHandler()->ProcessEvent( nc_paint_event
);
3569 wxPaintEvent
paint_event( GetId() );
3570 paint_event
.SetEventObject( this );
3571 GetEventHandler()->ProcessEvent( paint_event
);
3573 m_clipPaintRegion
= FALSE
;
3575 #ifndef __WXUNIVERSAL__
3577 // The following code will result in all window-less widgets
3578 // being redrawn because the wxWindows class is allowed to
3579 // paint over the window-less widgets.
3581 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3583 GList
*children
= pizza
->children
;
3586 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3587 children
= children
->next
;
3589 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3590 GTK_WIDGET_DRAWABLE (child
->widget
))
3592 // Get intersection of widget area and update region
3593 wxRegion
region( m_updateRegion
);
3595 GdkEventExpose gdk_event
;
3596 gdk_event
.type
= GDK_EXPOSE
;
3597 gdk_event
.window
= pizza
->bin_window
;
3598 gdk_event
.count
= 0;
3600 wxRegionIterator
upd( m_updateRegion
);
3604 rect
.x
= upd
.GetX();
3605 rect
.y
= upd
.GetY();
3606 rect
.width
= upd
.GetWidth();
3607 rect
.height
= upd
.GetHeight();
3609 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3611 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3621 m_updateRegion
.Clear();
3624 void wxWindowGTK::Clear()
3626 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3628 if (m_wxwindow
&& m_wxwindow
->window
)
3630 m_clearRegion
.Clear();
3631 wxSize
size( GetClientSize() );
3632 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3634 // Better do this in idle?
3640 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3642 wxWindowBase::DoSetToolTip(tip
);
3645 m_tooltip
->Apply( (wxWindow
*)this );
3648 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3650 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3652 #endif // wxUSE_TOOLTIPS
3654 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3656 GdkWindow
*window
= (GdkWindow
*) NULL
;
3658 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3660 window
= GetConnectWidget()->window
;
3664 // We need the pixel value e.g. for background clearing.
3665 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3668 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3670 /* wxMSW doesn't clear the window here. I don't do that either to
3671 provide compatibility. call Clear() to do the job. */
3673 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3679 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3681 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3683 if (!wxWindowBase::SetBackgroundColour(colour
))
3686 GdkWindow
*window
= (GdkWindow
*) NULL
;
3688 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3690 window
= GetConnectWidget()->window
;
3694 // indicate that a new style has been set
3695 // but it couldn't get applied as the
3696 // widget hasn't been realized yet.
3697 m_delayedBackgroundColour
= TRUE
;
3702 GtkSetBackgroundColour( colour
);
3708 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3710 GdkWindow
*window
= (GdkWindow
*) NULL
;
3712 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3714 window
= GetConnectWidget()->window
;
3721 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3723 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3725 if (!wxWindowBase::SetForegroundColour(colour
))
3727 // don't leave if the GTK widget has just
3729 if (!m_delayedForegroundColour
) return FALSE
;
3732 GdkWindow
*window
= (GdkWindow
*) NULL
;
3734 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3736 window
= GetConnectWidget()->window
;
3740 // indicate that a new style has been set
3741 // but it couldn't get applied as the
3742 // widget hasn't been realized yet.
3743 m_delayedForegroundColour
= TRUE
;
3747 GtkSetForegroundColour( colour
);
3753 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3757 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3759 // FIXME: no more klass in 2.0
3761 remake
->klass
= m_widgetStyle
->klass
;
3764 gtk_style_unref( m_widgetStyle
);
3765 m_widgetStyle
= remake
;
3769 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3772 def
= gtk_widget_get_default_style();
3774 m_widgetStyle
= gtk_style_copy( def
);
3776 // FIXME: no more klass in 2.0
3778 m_widgetStyle
->klass
= def
->klass
;
3782 return m_widgetStyle
;
3785 void wxWindowGTK::SetWidgetStyle()
3787 #if DISABLE_STYLE_IF_BROKEN_THEME
3788 if (m_widget
->style
->engine_data
)
3790 static bool s_warningPrinted
= FALSE
;
3791 if (!s_warningPrinted
)
3793 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3794 s_warningPrinted
= TRUE
;
3796 m_widgetStyle
= m_widget
->style
;
3801 GtkStyle
*style
= GetWidgetStyle();
3803 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3805 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3808 if (m_foregroundColour
.Ok())
3810 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3811 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3813 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3814 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3815 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3819 // Try to restore the gtk default style. This is still a little
3820 // oversimplified for what is probably really needed here for controls
3821 // other than buttons, but is better than not being able to (re)set a
3822 // control's foreground colour to *wxBLACK -- RL
3823 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3826 def
= gtk_widget_get_default_style();
3828 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3829 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3830 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3834 if (m_backgroundColour
.Ok())
3836 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3837 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3839 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3840 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3841 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3842 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3843 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3844 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3845 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3846 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3850 // Try to restore the gtk default style. This is still a little
3851 // oversimplified for what is probably really needed here for controls
3852 // other than buttons, but is better than not being able to (re)set a
3853 // control's background colour to default grey and means resetting a
3854 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3856 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3859 def
= gtk_widget_get_default_style();
3861 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3862 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3863 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3864 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3865 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3866 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3867 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3868 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3873 void wxWindowGTK::ApplyWidgetStyle()
3877 //-----------------------------------------------------------------------------
3878 // Pop-up menu stuff
3879 //-----------------------------------------------------------------------------
3881 #if wxUSE_MENUS_NATIVE
3884 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3886 *is_waiting
= FALSE
;
3889 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3891 menu
->SetInvokingWindow( win
);
3892 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3895 wxMenuItem
*menuitem
= node
->GetData();
3896 if (menuitem
->IsSubMenu())
3898 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3901 node
= node
->GetNext();
3905 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3906 // wxPopupMenuPositionCallback()
3908 // should be safe even in the MT case as the user can hardly popup 2 menus
3909 // simultaneously, can he?
3910 static gint gs_pop_x
= 0;
3911 static gint gs_pop_y
= 0;
3913 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3916 gboolean
* WXUNUSED(whatever
),
3918 gpointer
WXUNUSED(user_data
) )
3920 // ensure that the menu appears entirely on screen
3922 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3924 wxSize sizeScreen
= wxGetDisplaySize();
3926 gint xmax
= sizeScreen
.x
- req
.width
,
3927 ymax
= sizeScreen
.y
- req
.height
;
3929 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3930 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3933 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3935 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3937 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3939 SetInvokingWindow( menu
, this );
3945 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3947 bool is_waiting
= TRUE
;
3949 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3951 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3952 (gpointer
)&is_waiting
);
3955 GTK_MENU(menu
->m_menu
),
3956 (GtkWidget
*) NULL
, // parent menu shell
3957 (GtkWidget
*) NULL
, // parent menu item
3958 wxPopupMenuPositionCallback
, // function to position it
3959 NULL
, // client data
3960 0, // button used to activate it
3961 gs_timeLastClick
// the time of activation
3966 while (gtk_events_pending())
3967 gtk_main_iteration();
3973 #endif // wxUSE_MENUS_NATIVE
3975 #if wxUSE_DRAG_AND_DROP
3977 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3979 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3981 GtkWidget
*dnd_widget
= GetConnectWidget();
3983 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3985 if (m_dropTarget
) delete m_dropTarget
;
3986 m_dropTarget
= dropTarget
;
3988 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3991 #endif // wxUSE_DRAG_AND_DROP
3993 GtkWidget
* wxWindowGTK::GetConnectWidget()
3995 GtkWidget
*connect_widget
= m_widget
;
3996 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3998 return connect_widget
;
4001 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4004 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4006 return (window
== m_widget
->window
);
4009 bool wxWindowGTK::SetFont( const wxFont
&font
)
4011 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4013 if (!wxWindowBase::SetFont(font
))
4018 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4019 if ( sysbg
== m_backgroundColour
)
4021 m_backgroundColour
= wxNullColour
;
4023 m_backgroundColour
= sysbg
;
4033 void wxWindowGTK::DoCaptureMouse()
4035 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4037 GdkWindow
*window
= (GdkWindow
*) NULL
;
4039 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4041 window
= GetConnectWidget()->window
;
4043 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4045 wxCursor
* cursor
= & m_cursor
;
4047 cursor
= wxSTANDARD_CURSOR
;
4049 gdk_pointer_grab( window
, FALSE
,
4051 (GDK_BUTTON_PRESS_MASK
|
4052 GDK_BUTTON_RELEASE_MASK
|
4053 GDK_POINTER_MOTION_HINT_MASK
|
4054 GDK_POINTER_MOTION_MASK
),
4056 cursor
->GetCursor(),
4057 (guint32
)GDK_CURRENT_TIME
);
4058 g_captureWindow
= this;
4059 g_captureWindowHasMouse
= TRUE
;
4062 void wxWindowGTK::DoReleaseMouse()
4064 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4066 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4068 g_captureWindow
= (wxWindowGTK
*) NULL
;
4070 GdkWindow
*window
= (GdkWindow
*) NULL
;
4072 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4074 window
= GetConnectWidget()->window
;
4079 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4083 wxWindow
*wxWindowBase::GetCapture()
4085 return (wxWindow
*)g_captureWindow
;
4088 bool wxWindowGTK::IsRetained() const
4093 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4094 int range
, bool refresh
)
4096 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4098 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4100 m_hasScrolling
= TRUE
;
4102 if (orient
== wxHORIZONTAL
)
4104 float fpos
= (float)pos
;
4105 float frange
= (float)range
;
4106 float fthumb
= (float)thumbVisible
;
4107 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4108 if (fpos
< 0.0) fpos
= 0.0;
4110 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4111 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4113 SetScrollPos( orient
, pos
, refresh
);
4117 m_oldHorizontalPos
= fpos
;
4119 m_hAdjust
->lower
= 0.0;
4120 m_hAdjust
->upper
= frange
;
4121 m_hAdjust
->value
= fpos
;
4122 m_hAdjust
->step_increment
= 1.0;
4123 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4124 m_hAdjust
->page_size
= fthumb
;
4128 float fpos
= (float)pos
;
4129 float frange
= (float)range
;
4130 float fthumb
= (float)thumbVisible
;
4131 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4132 if (fpos
< 0.0) fpos
= 0.0;
4134 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4135 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4137 SetScrollPos( orient
, pos
, refresh
);
4141 m_oldVerticalPos
= fpos
;
4143 m_vAdjust
->lower
= 0.0;
4144 m_vAdjust
->upper
= frange
;
4145 m_vAdjust
->value
= fpos
;
4146 m_vAdjust
->step_increment
= 1.0;
4147 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4148 m_vAdjust
->page_size
= fthumb
;
4151 if (orient
== wxHORIZONTAL
)
4152 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4154 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4157 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4159 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4161 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4163 if (orient
== wxHORIZONTAL
)
4165 float fpos
= (float)pos
;
4166 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4167 if (fpos
< 0.0) fpos
= 0.0;
4168 m_oldHorizontalPos
= fpos
;
4170 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4171 m_hAdjust
->value
= fpos
;
4175 float fpos
= (float)pos
;
4176 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4177 if (fpos
< 0.0) fpos
= 0.0;
4178 m_oldVerticalPos
= fpos
;
4180 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4181 m_vAdjust
->value
= fpos
;
4184 if (m_wxwindow
->window
)
4186 if (orient
== wxHORIZONTAL
)
4188 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4189 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4191 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4193 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4194 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4198 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4199 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4201 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4203 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4204 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4209 int wxWindowGTK::GetScrollThumb( int orient
) const
4211 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4213 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4215 if (orient
== wxHORIZONTAL
)
4216 return (int)(m_hAdjust
->page_size
+0.5);
4218 return (int)(m_vAdjust
->page_size
+0.5);
4221 int wxWindowGTK::GetScrollPos( int orient
) const
4223 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4225 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4227 if (orient
== wxHORIZONTAL
)
4228 return (int)(m_hAdjust
->value
+0.5);
4230 return (int)(m_vAdjust
->value
+0.5);
4233 int wxWindowGTK::GetScrollRange( int orient
) const
4235 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4237 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4239 if (orient
== wxHORIZONTAL
)
4240 return (int)(m_hAdjust
->upper
+0.5);
4242 return (int)(m_vAdjust
->upper
+0.5);
4245 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4247 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4249 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4251 // No scrolling requested.
4252 if ((dx
== 0) && (dy
== 0)) return;
4255 if (!m_updateRegion
.IsEmpty())
4257 m_updateRegion
.Offset( dx
, dy
);
4261 GetClientSize( &cw
, &ch
);
4262 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4265 if (!m_clearRegion
.IsEmpty())
4267 m_clearRegion
.Offset( dx
, dy
);
4271 GetClientSize( &cw
, &ch
);
4272 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4275 m_clipPaintRegion
= TRUE
;
4277 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4279 m_clipPaintRegion
= FALSE
;
4282 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4284 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4285 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4292 // Find the wxWindow at the current mouse position, also returning the mouse
4294 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4296 pt
= wxGetMousePosition();
4297 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4301 // Get the current mouse position.
4302 wxPoint
wxGetMousePosition()
4304 /* This crashes when used within wxHelpContext,
4305 so we have to use the X-specific implementation below.
4307 GdkModifierType *mask;
4308 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4310 return wxPoint(x, y);
4314 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4316 return wxPoint(-999, -999);
4318 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4319 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4320 Window rootReturn
, childReturn
;
4321 int rootX
, rootY
, winX
, winY
;
4322 unsigned int maskReturn
;
4324 XQueryPointer (display
,
4328 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4329 return wxPoint(rootX
, rootY
);
4333 // ----------------------------------------------------------------------------
4335 // ----------------------------------------------------------------------------
4337 class wxWinModule
: public wxModule
4344 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4347 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4349 bool wxWinModule::OnInit()
4351 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4352 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4357 void wxWinModule::OnExit()
4360 gdk_gc_unref( g_eraseGC
);