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"
51 #include "wx/fontutil.h"
54 #include "wx/thread.h"
60 #include "wx/gtk/private.h"
61 #include <gdk/gdkprivate.h>
62 #include <gdk/gdkkeysyms.h>
66 #include <gtk/gtkprivate.h>
68 #include "wx/gtk/win_gtk.h"
71 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
73 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
83 extern GtkContainerClass
*pizza_parent_class
;
86 //-----------------------------------------------------------------------------
87 // documentation on internals
88 //-----------------------------------------------------------------------------
91 I have been asked several times about writing some documentation about
92 the GTK port of wxWindows, especially its internal structures. Obviously,
93 you cannot understand wxGTK without knowing a little about the GTK, but
94 some more information about what the wxWindow, which is the base class
95 for all other window classes, does seems required as well.
99 What does wxWindow do? It contains the common interface for the following
100 jobs of its descendants:
102 1) Define the rudimentary behaviour common to all window classes, such as
103 resizing, intercepting user input (so as to make it possible to use these
104 events for special purposes in a derived class), window names etc.
106 2) Provide the possibility to contain and manage children, if the derived
107 class is allowed to contain children, which holds true for those window
108 classes which do not display a native GTK widget. To name them, these
109 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
110 work classes are a special case and are handled a bit differently from
111 the rest. The same holds true for the wxNotebook class.
113 3) Provide the possibility to draw into a client area of a window. This,
114 too, only holds true for classes that do not display a native GTK widget
117 4) Provide the entire mechanism for scrolling widgets. This actual inter-
118 face for this is usually in wxScrolledWindow, but the GTK implementation
121 5) A multitude of helper or extra methods for special purposes, such as
122 Drag'n'Drop, managing validators etc.
124 6) Display a border (sunken, raised, simple or none).
126 Normally one might expect, that one wxWindows window would always correspond
127 to one GTK widget. Under GTK, there is no such allround widget that has all
128 the functionality. Moreover, the GTK defines a client area as a different
129 widget from the actual widget you are handling. Last but not least some
130 special classes (e.g. wxFrame) handle different categories of widgets and
131 still have the possibility to draw something in the client area.
132 It was therefore required to write a special purpose GTK widget, that would
133 represent a client area in the sense of wxWindows capable to do the jobs
134 2), 3) and 4). I have written this class and it resides in win_gtk.c of
137 All windows must have a widget, with which they interact with other under-
138 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
139 thw wxWindow class has a member variable called m_widget which holds a
140 pointer to this widget. When the window class represents a GTK native widget,
141 this is (in most cases) the only GTK widget the class manages. E.g. the
142 wxStatitText class handles only a GtkLabel widget a pointer to which you
143 can find in m_widget (defined in wxWindow)
145 When the class has a client area for drawing into and for containing children
146 it has to handle the client area widget (of the type GtkPizza, defined in
147 win_gtk.c), but there could be any number of widgets, handled by a class
148 The common rule for all windows is only, that the widget that interacts with
149 the rest of GTK must be referenced in m_widget and all other widgets must be
150 children of this widget on the GTK level. The top-most widget, which also
151 represents the client area, must be in the m_wxwindow field and must be of
154 As I said, the window classes that display a GTK native widget only have
155 one widget, so in the case of e.g. the wxButton class m_widget holds a
156 pointer to a GtkButton widget. But windows with client areas (for drawing
157 and children) have a m_widget field that is a pointer to a GtkScrolled-
158 Window and a m_wxwindow field that is pointer to a GtkPizza and this
159 one is (in the GTK sense) a child of the GtkScrolledWindow.
161 If the m_wxwindow field is set, then all input to this widget is inter-
162 cepted and sent to the wxWindows class. If not, all input to the widget
163 that gets pointed to by m_widget gets intercepted and sent to the class.
167 The design of scrolling in wxWindows is markedly different from that offered
168 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
169 clicking on a scrollbar belonging to scrolled window will inevitably move
170 the window. In wxWindows, the scrollbar will only emit an event, send this
171 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
172 which actually moves the window and its subchildren. Note that GtkPizza
173 memorizes how much it has been scrolled but that wxWindows forgets this
174 so that the two coordinates systems have to be kept in synch. This is done
175 in various places using the pizza->xoffset and pizza->yoffset values.
179 Singularily the most broken code in GTK is the code that is supposes to
180 inform subwindows (child windows) about new positions. Very often, duplicate
181 events are sent without changes in size or position, equally often no
182 events are sent at all (All this is due to a bug in the GtkContainer code
183 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
184 GTK's own system and it simply waits for size events for toplevel windows
185 and then iterates down the respective size events to all window. This has
186 the disadvantage, that windows might get size events before the GTK widget
187 actually has the reported size. This doesn't normally pose any problem, but
188 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
189 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
190 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
191 window that is used for OpenGl output really has that size (as reported by
196 If someone at some point of time feels the immense desire to have a look at,
197 change or attempt to optimse the Refresh() logic, this person will need an
198 intimate understanding of what a "draw" and what an "expose" events are and
199 what there are used for, in particular when used in connection with GTK's
200 own windowless widgets. Beware.
204 Cursors, too, have been a constant source of pleasure. The main difficulty
205 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
206 for the parent. To prevent this from doing too much harm, I use idle time
207 to set the cursor over and over again, starting from the toplevel windows
208 and ending with the youngest generation (speaking of parent and child windows).
209 Also don't forget that cursors (like much else) are connected to GdkWindows,
210 not GtkWidgets and that the "window" field of a GtkWidget might very well
211 point to the GdkWindow of the parent widget (-> "window less widget") and
212 that the two obviously have very different meanings.
216 //-----------------------------------------------------------------------------
218 //-----------------------------------------------------------------------------
220 extern wxList wxPendingDelete
;
221 extern bool g_blockEventsOnDrag
;
222 extern bool g_blockEventsOnScroll
;
223 extern wxCursor g_globalCursor
;
225 static GdkGC
*g_eraseGC
= NULL
;
227 // mouse capture state: the window which has it and if the mouse is currently
229 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
230 static bool g_captureWindowHasMouse
= FALSE
;
232 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
234 // the last window which had the focus - this is normally never NULL (except
235 // if we never had focus at all) as even when g_focusWindow is NULL it still
236 // keeps its previous value
237 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
239 // the frame that is currently active (i.e. its child has focus). It is
240 // used to generate wxActivateEvents
241 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
242 static bool g_activeFrameLostFocus
= FALSE
;
244 // If a window get the focus set but has not been realized
245 // yet, defer setting the focus to idle time.
246 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
248 // if we detect that the app has got/lost the focus, we set this variable to
249 // either TRUE or FALSE and an activate event will be sent during the next
250 // OnIdle() call and it is reset to -1: this value means that we shouldn't
251 // send any activate events at all
252 static int g_sendActivateEvent
= -1;
254 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
255 the last click here */
256 static guint32 gs_timeLastClick
= 0;
258 extern bool g_mainThreadLocked
;
260 //-----------------------------------------------------------------------------
262 //-----------------------------------------------------------------------------
265 #define DISABLE_STYLE_IF_BROKEN_THEME 1
271 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
273 # define DEBUG_MAIN_THREAD
276 #define DEBUG_MAIN_THREAD
279 // the trace mask used for the focus debugging messages
280 #define TRACE_FOCUS _T("focus")
282 //-----------------------------------------------------------------------------
283 // missing gdk functions
284 //-----------------------------------------------------------------------------
287 gdk_window_warp_pointer (GdkWindow
*window
,
292 GdkWindowPrivate
*priv
;
296 window
= GDK_ROOT_PARENT();
299 if (!GDK_WINDOW_DESTROYED(window
))
301 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
302 None
, /* not source window -> move from anywhere */
303 GDK_WINDOW_XID(window
), /* dest window */
304 0, 0, 0, 0, /* not source window -> move from anywhere */
308 priv
= (GdkWindowPrivate
*) window
;
310 if (!priv
->destroyed
)
312 XWarpPointer (priv
->xdisplay
,
313 None
, /* not source window -> move from anywhere */
314 priv
->xwindow
, /* dest window */
315 0, 0, 0, 0, /* not source window -> move from anywhere */
321 //-----------------------------------------------------------------------------
323 //-----------------------------------------------------------------------------
325 extern void wxapp_install_idle_handler();
326 extern bool g_isIdle
;
328 //-----------------------------------------------------------------------------
329 // local code (see below)
330 //-----------------------------------------------------------------------------
332 // returns the child of win which currently has focus or NULL if not found
334 // Note: can't be static, needed by textctrl.cpp.
335 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
337 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
339 return (wxWindow
*)NULL
;
341 if ( winFocus
== win
)
342 return (wxWindow
*)win
;
344 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
346 node
= node
->GetNext() )
348 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
353 return (wxWindow
*)NULL
;
356 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
358 // wxUniversal widgets draw the borders and scrollbars themselves
359 #ifndef __WXUNIVERSAL__
366 if (win
->m_hasScrolling
)
368 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
370 GtkRequisition vscroll_req
;
371 vscroll_req
.width
= 2;
372 vscroll_req
.height
= 2;
373 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
374 (scroll_window
->vscrollbar
, &vscroll_req
);
376 GtkRequisition hscroll_req
;
377 hscroll_req
.width
= 2;
378 hscroll_req
.height
= 2;
379 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
380 (scroll_window
->hscrollbar
, &hscroll_req
);
382 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
384 if (scroll_window
->vscrollbar_visible
)
386 dw
+= vscroll_req
.width
;
387 dw
+= scroll_class
->scrollbar_spacing
;
390 if (scroll_window
->hscrollbar_visible
)
392 dh
+= hscroll_req
.height
;
393 dh
+= scroll_class
->scrollbar_spacing
;
399 if (GTK_WIDGET_NO_WINDOW (widget
))
401 dx
+= widget
->allocation
.x
;
402 dy
+= widget
->allocation
.y
;
405 if (win
->HasFlag(wxRAISED_BORDER
))
407 gtk_draw_shadow( widget
->style
,
412 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
416 if (win
->HasFlag(wxSUNKEN_BORDER
))
418 gtk_draw_shadow( widget
->style
,
423 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
427 if (win
->HasFlag(wxSIMPLE_BORDER
))
430 gc
= gdk_gc_new( widget
->window
);
431 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
432 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
434 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
438 #endif // __WXUNIVERSAL__
441 //-----------------------------------------------------------------------------
442 // "expose_event" of m_widget
443 //-----------------------------------------------------------------------------
445 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
447 if (gdk_event
->count
> 0) return FALSE
;
449 draw_frame( widget
, win
);
453 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
459 //-----------------------------------------------------------------------------
460 // "draw" of m_widget
461 //-----------------------------------------------------------------------------
465 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
467 draw_frame( widget
, win
);
472 //-----------------------------------------------------------------------------
473 // "size_request" of m_widget
474 //-----------------------------------------------------------------------------
476 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
479 win
->GetSize( &w
, &h
);
483 requisition
->height
= h
;
484 requisition
->width
= w
;
487 //-----------------------------------------------------------------------------
488 // "expose_event" of m_wxwindow
489 //-----------------------------------------------------------------------------
491 static int gtk_window_expose_callback( GtkWidget
*widget
,
492 GdkEventExpose
*gdk_event
,
498 wxapp_install_idle_handler();
501 // This callback gets called in drawing-idle time under
502 // GTK 2.0, so we don't need to defer anything to idle
505 GtkPizza
*pizza
= GTK_PIZZA( widget
);
506 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
511 wxPrintf( wxT("OnExpose from ") );
512 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
513 wxPrintf( win
->GetClassInfo()->GetClassName() );
514 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
515 (int)gdk_event
->area
.y
,
516 (int)gdk_event
->area
.width
,
517 (int)gdk_event
->area
.height
);
521 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
523 win
->GtkSendPaintEvents();
525 // Let parent window draw window less widgets
526 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
528 // This gets called immediately after an expose event
529 // under GTK 1.2 so we collect the calls and wait for
530 // the idle handler to pick things up.
532 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
534 gdk_event
->area
.width
,
535 gdk_event
->area
.height
);
536 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
538 gdk_event
->area
.width
,
539 gdk_event
->area
.height
);
541 // Actual redrawing takes place in idle time.
548 //-----------------------------------------------------------------------------
549 // "event" of m_wxwindow
550 //-----------------------------------------------------------------------------
552 // GTK thinks it is clever and filters out a certain amount of "unneeded"
553 // expose events. We need them, of course, so we override the main event
554 // procedure in GtkWidget by giving our own handler for all system events.
555 // There, we look for expose events ourselves whereas all other events are
558 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
559 GdkEventExpose
*event
,
562 if (event
->type
== GDK_EXPOSE
)
564 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
571 //-----------------------------------------------------------------------------
572 // "draw" of m_wxwindow
573 //-----------------------------------------------------------------------------
577 // This callback is a complete replacement of the gtk_pizza_draw() function,
578 // which is disabled.
580 static void gtk_window_draw_callback( GtkWidget
*widget
,
587 wxapp_install_idle_handler();
589 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
590 // there are no child windows.
591 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
592 (win
->GetChildren().GetCount() == 0))
600 wxPrintf( wxT("OnDraw from ") );
601 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
602 wxPrintf( win
->GetClassInfo()->GetClassName() );
603 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
610 #ifndef __WXUNIVERSAL__
611 GtkPizza
*pizza
= GTK_PIZZA (widget
);
613 if (win
->GetThemeEnabled())
615 wxWindow
*parent
= win
->GetParent();
616 while (parent
&& !parent
->IsTopLevel())
617 parent
= parent
->GetParent();
621 gtk_paint_flat_box (parent
->m_widget
->style
,
632 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
633 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
635 // Update immediately, not in idle time.
638 #ifndef __WXUNIVERSAL__
639 // Redraw child widgets
640 GList
*children
= pizza
->children
;
643 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
644 children
= children
->next
;
646 GdkRectangle child_area
;
647 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
649 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
657 //-----------------------------------------------------------------------------
658 // "key_press_event" from any window
659 //-----------------------------------------------------------------------------
661 // set WXTRACE to this to see the key event codes on the console
662 #define TRACE_KEYS _T("keyevent")
664 // translates an X key symbol to WXK_XXX value
666 // if isChar is true it means that the value returned will be used for EVT_CHAR
667 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
668 // for example, while if it is false it means that the value is going to be
669 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
671 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
677 // Shift, Control and Alt don't generate the CHAR events at all
680 key_code
= isChar
? 0 : WXK_SHIFT
;
684 key_code
= isChar
? 0 : WXK_CONTROL
;
692 key_code
= isChar
? 0 : WXK_ALT
;
695 // neither do the toggle modifies
696 case GDK_Scroll_Lock
:
697 key_code
= isChar
? 0 : WXK_SCROLL
;
701 key_code
= isChar
? 0 : WXK_CAPITAL
;
705 key_code
= isChar
? 0 : WXK_NUMLOCK
;
709 // various other special keys
722 case GDK_ISO_Left_Tab
:
729 key_code
= WXK_RETURN
;
733 key_code
= WXK_CLEAR
;
737 key_code
= WXK_PAUSE
;
741 key_code
= WXK_SELECT
;
745 key_code
= WXK_PRINT
;
749 key_code
= WXK_EXECUTE
;
753 key_code
= WXK_ESCAPE
;
756 // cursor and other extended keyboard keys
758 key_code
= WXK_DELETE
;
774 key_code
= WXK_RIGHT
;
781 case GDK_Prior
: // == GDK_Page_Up
782 key_code
= WXK_PRIOR
;
785 case GDK_Next
: // == GDK_Page_Down
798 key_code
= WXK_INSERT
;
813 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
817 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
821 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
825 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
829 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
833 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
837 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
841 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
845 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
849 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
853 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
857 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
861 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
864 case GDK_KP_Prior
: // == GDK_KP_Page_Up
865 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
868 case GDK_KP_Next
: // == GDK_KP_Page_Down
869 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
873 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
877 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
881 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
885 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
889 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
892 case GDK_KP_Multiply
:
893 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
897 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
900 case GDK_KP_Separator
:
901 // FIXME: what is this?
902 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
905 case GDK_KP_Subtract
:
906 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
910 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
914 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
931 key_code
= WXK_F1
+ keysym
- GDK_F1
;
941 static inline bool wxIsAsciiKeysym(KeySym ks
)
947 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
949 GdkEventKey
*gdk_event
)
951 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
952 // but only event->keyval which is quite useless to us, so remember
953 // the last character from GDK_KEY_PRESS and reuse it as last resort
955 // NB: should be MT-safe as we're always called from the main thread only
960 } s_lastKeyPress
= { 0, 0 };
962 KeySym keysym
= gdk_event
->keyval
;
964 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
965 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
969 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
973 // do we have the translation or is it a plain ASCII character?
974 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
976 // we should use keysym if it is ASCII as X does some translations
977 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
978 // which we don't want here (but which we do use for OnChar())
979 if ( !wxIsAsciiKeysym(keysym
) )
981 keysym
= (KeySym
)gdk_event
->string
[0];
984 // we want to always get the same key code when the same key is
985 // pressed regardless of the state of the modifies, i.e. on a
986 // standard US keyboard pressing '5' or '%' ('5' key with
987 // Shift) should result in the same key code in OnKeyDown():
988 // '5' (although OnChar() will get either '5' or '%').
990 // to do it we first translate keysym to keycode (== scan code)
991 // and then back but always using the lower register
992 Display
*dpy
= (Display
*)wxGetDisplay();
993 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
995 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
997 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
999 // use the normalized, i.e. lower register, keysym if we've
1001 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1003 // as explained above, we want to have lower register key codes
1004 // normally but for the letter keys we want to have the upper ones
1006 // NB: don't use XConvertCase() here, we want to do it for letters
1008 key_code
= toupper(key_code
);
1010 else // non ASCII key, what to do?
1012 // by default, ignore it
1015 // but if we have cached information from the last KEY_PRESS
1016 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1019 if ( keysym
== s_lastKeyPress
.keysym
)
1021 key_code
= s_lastKeyPress
.keycode
;
1026 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1028 // remember it to be reused for KEY_UP event later
1029 s_lastKeyPress
.keysym
= keysym
;
1030 s_lastKeyPress
.keycode
= key_code
;
1034 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1036 // sending unknown key events doesn't really make sense
1040 // now fill all the other fields
1043 GdkModifierType state
;
1044 if (gdk_event
->window
)
1045 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1047 event
.SetTimestamp( gdk_event
->time
);
1048 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1049 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1050 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1051 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1052 event
.m_keyCode
= key_code
;
1053 event
.m_scanCode
= gdk_event
->keyval
;
1054 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1055 event
.m_rawFlags
= 0;
1058 event
.SetEventObject( win
);
1063 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1064 GdkEventKey
*gdk_event
,
1070 wxapp_install_idle_handler();
1074 if (g_blockEventsOnDrag
)
1078 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1079 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1081 // unknown key pressed, ignore (the event would be useless anyhow)
1085 // Emit KEY_DOWN event
1086 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1091 wxWindowGTK
*ancestor
= win
;
1094 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1097 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1098 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1101 if (ancestor
->IsTopLevel())
1103 ancestor
= ancestor
->GetParent();
1106 #endif // wxUSE_ACCEL
1108 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1109 // will only be sent if it is not in an accelerator table.
1112 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1113 KeySym keysym
= gdk_event
->keyval
;
1114 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1117 if ( gdk_event
->length
== 1 )
1119 key_code
= (unsigned char)gdk_event
->string
[0];
1121 else if ( wxIsAsciiKeysym(keysym
) )
1124 key_code
= (unsigned char)keysym
;
1130 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1132 event
.m_keyCode
= key_code
;
1134 // Implement OnCharHook by checking ancesteror top level windows
1135 wxWindow
*parent
= win
;
1136 while (parent
&& !parent
->IsTopLevel())
1137 parent
= parent
->GetParent();
1140 event
.SetEventType( wxEVT_CHAR_HOOK
);
1141 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1146 event
.SetEventType(wxEVT_CHAR
);
1147 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1152 // win is a control: tab can be propagated up
1154 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1155 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1156 // have this style, yet choose not to process this particular TAB in which
1157 // case TAB must still work as a navigational character
1159 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1161 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1163 wxNavigationKeyEvent new_event
;
1164 new_event
.SetEventObject( win
->GetParent() );
1165 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1166 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1167 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1168 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1169 new_event
.SetCurrentFocus( win
);
1170 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1173 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1175 (gdk_event
->keyval
== GDK_Escape
) )
1177 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1178 new_event
.SetEventObject( win
);
1179 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1184 // Pressing F10 will activate the menu bar of the top frame
1186 (gdk_event
->keyval
== GDK_F10
) )
1188 wxWindowGTK
*ancestor
= win
;
1191 if (wxIsKindOf(ancestor
,wxFrame
))
1193 wxFrame
*frame
= (wxFrame
*) ancestor
;
1194 wxMenuBar
*menubar
= frame
->GetMenuBar();
1197 wxNode
*node
= menubar
->GetMenus().First();
1200 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1201 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1207 ancestor
= ancestor
->GetParent();
1214 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1221 //-----------------------------------------------------------------------------
1222 // "key_release_event" from any window
1223 //-----------------------------------------------------------------------------
1225 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1226 GdkEventKey
*gdk_event
,
1232 wxapp_install_idle_handler();
1237 if (g_blockEventsOnDrag
)
1240 wxKeyEvent
event( wxEVT_KEY_UP
);
1241 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1243 // unknown key pressed, ignore (the event would be useless anyhow
1247 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1250 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1254 // ============================================================================
1256 // ============================================================================
1258 // ----------------------------------------------------------------------------
1259 // mouse event processing helpers
1260 // ----------------------------------------------------------------------------
1262 // init wxMouseEvent with the info from gdk_event
1264 // NB: this has to be a macro as gdk_event type is different for different
1265 // events we're used with
1266 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1267 /* wxMouseEvent& */ event, \
1268 /* GdkEventXXX * */ gdk_event) \
1270 event.SetTimestamp( gdk_event->time ); \
1271 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1272 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1273 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1274 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1275 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1276 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1277 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1279 wxPoint pt = win->GetClientAreaOrigin(); \
1280 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1281 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1283 event.SetEventObject( win ); \
1284 event.SetId( win->GetId() ); \
1285 event.SetTimestamp( gdk_event->time ); \
1288 static void AdjustEventButtonState(wxMouseEvent& event)
1290 // GDK reports the old state of the button for a button press event, but
1291 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1292 // for a LEFT_DOWN event, not FALSE, so we will invert
1293 // left/right/middleDown for the corresponding click events
1295 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1296 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1297 (event
.GetEventType() == wxEVT_LEFT_UP
))
1299 event
.m_leftDown
= !event
.m_leftDown
;
1303 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1304 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1305 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1307 event
.m_middleDown
= !event
.m_middleDown
;
1311 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1312 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1313 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1315 event
.m_rightDown
= !event
.m_rightDown
;
1320 // find the window to send the mouse event too
1322 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1327 if (win
->m_wxwindow
)
1329 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1330 xx
+= pizza
->xoffset
;
1331 yy
+= pizza
->yoffset
;
1334 wxNode
*node
= win
->GetChildren().First();
1337 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1339 node
= node
->Next();
1340 if (!child
->IsShown())
1343 if (child
->IsTransparentForMouse())
1345 // wxStaticBox is transparent in the box itself
1346 int xx1
= child
->m_x
;
1347 int yy1
= child
->m_y
;
1348 int xx2
= child
->m_x
+ child
->m_width
;
1349 int yy2
= child
->m_x
+ child
->m_height
;
1352 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1354 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1356 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1358 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1369 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1370 (child
->m_x
<= xx
) &&
1371 (child
->m_y
<= yy
) &&
1372 (child
->m_x
+child
->m_width
>= xx
) &&
1373 (child
->m_y
+child
->m_height
>= yy
))
1386 //-----------------------------------------------------------------------------
1387 // "button_press_event"
1388 //-----------------------------------------------------------------------------
1390 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1391 GdkEventButton
*gdk_event
,
1397 wxapp_install_idle_handler();
1400 wxPrintf( wxT("1) OnButtonPress from ") );
1401 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1402 wxPrintf( win->GetClassInfo()->GetClassName() );
1403 wxPrintf( wxT(".\n") );
1405 if (!win
->m_hasVMT
) return FALSE
;
1406 if (g_blockEventsOnDrag
) return TRUE
;
1407 if (g_blockEventsOnScroll
) return TRUE
;
1409 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1411 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1413 gtk_widget_grab_focus( win
->m_wxwindow
);
1415 wxPrintf( wxT("GrabFocus from ") );
1416 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1417 wxPrintf( win->GetClassInfo()->GetClassName() );
1418 wxPrintf( wxT(".\n") );
1422 wxEventType event_type
= wxEVT_NULL
;
1424 if (gdk_event
->button
== 1)
1426 switch (gdk_event
->type
)
1428 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1429 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1433 else if (gdk_event
->button
== 2)
1435 switch (gdk_event
->type
)
1437 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1438 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1442 else if (gdk_event
->button
== 3)
1444 switch (gdk_event
->type
)
1446 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1447 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1452 if ( event_type
== wxEVT_NULL
)
1454 // unknown mouse button or click type
1458 wxMouseEvent
event( event_type
);
1459 InitMouseEvent( win
, event
, gdk_event
);
1461 AdjustEventButtonState(event
);
1463 // wxListBox actually get mouse events from the item, so we need to give it
1464 // a chance to correct this
1465 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1467 // find the correct window to send the event too: it may be a different one
1468 // from the one which got it at GTK+ level because some control don't have
1469 // their own X window and thus cannot get any events.
1470 if ( !g_captureWindow
)
1471 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1473 gs_timeLastClick
= gdk_event
->time
;
1476 wxPrintf( wxT("2) OnButtonPress from ") );
1477 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1478 wxPrintf( win->GetClassInfo()->GetClassName() );
1479 wxPrintf( wxT(".\n") );
1482 if (win
->GetEventHandler()->ProcessEvent( event
))
1484 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1491 //-----------------------------------------------------------------------------
1492 // "button_release_event"
1493 //-----------------------------------------------------------------------------
1495 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1500 wxapp_install_idle_handler();
1502 if (!win
->m_hasVMT
) return FALSE
;
1503 if (g_blockEventsOnDrag
) return FALSE
;
1504 if (g_blockEventsOnScroll
) return FALSE
;
1506 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1509 printf( "OnButtonRelease from " );
1510 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1511 printf( win->GetClassInfo()->GetClassName() );
1515 wxEventType event_type
= wxEVT_NULL
;
1517 switch (gdk_event
->button
)
1519 case 1: event_type
= wxEVT_LEFT_UP
; break;
1520 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1521 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1522 default: return FALSE
;
1525 wxMouseEvent
event( event_type
);
1526 InitMouseEvent( win
, event
, gdk_event
);
1528 AdjustEventButtonState(event
);
1530 // same wxListBox hack as above
1531 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1533 if ( !g_captureWindow
)
1534 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1536 if (win
->GetEventHandler()->ProcessEvent( event
))
1538 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1545 //-----------------------------------------------------------------------------
1546 // "motion_notify_event"
1547 //-----------------------------------------------------------------------------
1549 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1550 GdkEventMotion
*gdk_event
,
1556 wxapp_install_idle_handler();
1558 if (!win
->m_hasVMT
) return FALSE
;
1559 if (g_blockEventsOnDrag
) return FALSE
;
1560 if (g_blockEventsOnScroll
) return FALSE
;
1562 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1564 if (gdk_event
->is_hint
)
1568 GdkModifierType state
;
1569 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1575 printf( "OnMotion from " );
1576 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1577 printf( win->GetClassInfo()->GetClassName() );
1581 wxMouseEvent
event( wxEVT_MOTION
);
1582 InitMouseEvent(win
, event
, gdk_event
);
1584 if ( g_captureWindow
)
1586 // synthetize a mouse enter or leave event if needed
1587 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1588 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1589 if ( hasMouse
!= g_captureWindowHasMouse
)
1591 // the mouse changed window
1592 g_captureWindowHasMouse
= hasMouse
;
1594 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1595 : wxEVT_LEAVE_WINDOW
);
1596 InitMouseEvent(win
, event
, gdk_event
);
1597 event
.SetEventObject(win
);
1598 win
->GetEventHandler()->ProcessEvent(event
);
1603 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1606 if (win
->GetEventHandler()->ProcessEvent( event
))
1608 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1615 //-----------------------------------------------------------------------------
1617 //-----------------------------------------------------------------------------
1619 // send the wxChildFocusEvent and wxFocusEvent, common code of
1620 // gtk_window_focus_in_callback() and SetFocus()
1621 static bool DoSendFocusEvents(wxWindow
*win
)
1623 // Notify the parent keeping track of focus for the kbd navigation
1624 // purposes that we got it.
1625 wxChildFocusEvent
eventChildFocus(win
);
1626 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1628 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1629 eventFocus
.SetEventObject(win
);
1631 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1634 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1635 GdkEvent
*WXUNUSED(event
),
1641 wxapp_install_idle_handler();
1643 if (!win
->m_hasVMT
) return FALSE
;
1644 if (g_blockEventsOnDrag
) return FALSE
;
1646 switch ( g_sendActivateEvent
)
1649 // we've got focus from outside, synthetize wxActivateEvent
1650 g_sendActivateEvent
= 1;
1654 // another our window just lost focus, it was already ours before
1655 // - don't send any wxActivateEvent
1656 g_sendActivateEvent
= -1;
1661 g_focusWindow
= win
;
1663 wxLogTrace(TRACE_FOCUS
,
1664 _T("%s: focus in"), win
->GetName().c_str());
1668 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1672 // caret needs to be informed about focus change
1673 wxCaret
*caret
= win
->GetCaret();
1676 caret
->OnSetFocus();
1678 #endif // wxUSE_CARET
1680 g_activeFrameLostFocus
= FALSE
;
1682 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1683 if ( active
!= g_activeFrame
)
1685 if ( g_activeFrame
)
1687 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1688 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1689 event
.SetEventObject(g_activeFrame
);
1690 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1693 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1694 g_activeFrame
= active
;
1695 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1696 event
.SetEventObject(g_activeFrame
);
1697 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1699 // Don't send focus events in addition to activate
1700 // if (win == g_activeFrame)
1704 // does the window itself think that it has the focus?
1705 if ( !win
->m_hasFocus
)
1707 // not yet, notify it
1708 win
->m_hasFocus
= TRUE
;
1710 if ( DoSendFocusEvents(win
) )
1712 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1720 //-----------------------------------------------------------------------------
1721 // "focus_out_event"
1722 //-----------------------------------------------------------------------------
1724 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1729 wxapp_install_idle_handler();
1731 if (!win
->m_hasVMT
) return FALSE
;
1732 if (g_blockEventsOnDrag
) return FALSE
;
1734 wxLogTrace( TRACE_FOCUS
,
1735 _T("%s: focus out"), win
->GetName().c_str() );
1737 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1739 // VZ: commenting this out because it does happen (although not easy
1740 // to reproduce, I only see it when using wxMiniFrame and not
1741 // always) and makes using Mahogany quite annoying
1743 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1744 wxT("unfocusing window that hasn't gained focus properly") );
1747 g_activeFrameLostFocus
= TRUE
;
1750 // if the focus goes out of our app alltogether, OnIdle() will send
1751 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1752 // g_sendActivateEvent to -1
1753 g_sendActivateEvent
= 0;
1755 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1759 g_focusWindow
= (wxWindowGTK
*)NULL
;
1767 // caret needs to be informed about focus change
1768 wxCaret
*caret
= win
->GetCaret();
1771 caret
->OnKillFocus();
1773 #endif // wxUSE_CARET
1775 // don't send the window a kill focus event if it thinks that it doesn't
1776 // have focus already
1777 if ( win
->m_hasFocus
)
1779 win
->m_hasFocus
= FALSE
;
1781 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1782 event
.SetEventObject( win
);
1784 if (win
->GetEventHandler()->ProcessEvent( event
))
1786 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1794 //-----------------------------------------------------------------------------
1795 // "enter_notify_event"
1796 //-----------------------------------------------------------------------------
1799 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1800 GdkEventCrossing
*gdk_event
,
1806 wxapp_install_idle_handler();
1808 if (!win
->m_hasVMT
) return FALSE
;
1809 if (g_blockEventsOnDrag
) return FALSE
;
1811 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1815 GdkModifierType state
= (GdkModifierType
)0;
1817 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1819 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1820 InitMouseEvent(win
, event
, gdk_event
);
1821 wxPoint pt
= win
->GetClientAreaOrigin();
1822 event
.m_x
= x
+ pt
.x
;
1823 event
.m_y
= y
+ pt
.y
;
1825 if (win
->GetEventHandler()->ProcessEvent( event
))
1827 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1834 //-----------------------------------------------------------------------------
1835 // "leave_notify_event"
1836 //-----------------------------------------------------------------------------
1838 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1843 wxapp_install_idle_handler();
1845 if (!win
->m_hasVMT
) return FALSE
;
1846 if (g_blockEventsOnDrag
) return FALSE
;
1848 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1850 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1851 event
.SetTimestamp( gdk_event
->time
);
1852 event
.SetEventObject( win
);
1856 GdkModifierType state
= (GdkModifierType
)0;
1858 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1860 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1861 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1862 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1863 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1864 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1865 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1866 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1868 wxPoint pt
= win
->GetClientAreaOrigin();
1869 event
.m_x
= x
+ pt
.x
;
1870 event
.m_y
= y
+ pt
.y
;
1872 if (win
->GetEventHandler()->ProcessEvent( event
))
1874 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1881 //-----------------------------------------------------------------------------
1882 // "value_changed" from m_vAdjust
1883 //-----------------------------------------------------------------------------
1885 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1892 wxapp_install_idle_handler();
1894 if (g_blockEventsOnDrag
) return;
1896 if (!win
->m_hasVMT
) return;
1898 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1899 if (fabs(diff
) < 0.2) return;
1901 win
->m_oldVerticalPos
= adjust
->value
;
1904 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1906 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
1908 int value
= (int)(adjust
->value
+0.5);
1910 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1911 event
.SetEventObject( win
);
1912 win
->GetEventHandler()->ProcessEvent( event
);
1915 //-----------------------------------------------------------------------------
1916 // "value_changed" from m_hAdjust
1917 //-----------------------------------------------------------------------------
1919 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1926 wxapp_install_idle_handler();
1928 if (g_blockEventsOnDrag
) return;
1929 if (!win
->m_hasVMT
) return;
1931 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1932 if (fabs(diff
) < 0.2) return;
1935 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1937 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
1939 win
->m_oldHorizontalPos
= adjust
->value
;
1941 int value
= (int)(adjust
->value
+0.5);
1943 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1944 event
.SetEventObject( win
);
1945 win
->GetEventHandler()->ProcessEvent( event
);
1948 //-----------------------------------------------------------------------------
1949 // "button_press_event" from scrollbar
1950 //-----------------------------------------------------------------------------
1952 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1953 GdkEventButton
*gdk_event
,
1959 wxapp_install_idle_handler();
1962 g_blockEventsOnScroll
= TRUE
;
1964 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1966 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1972 //-----------------------------------------------------------------------------
1973 // "button_release_event" from scrollbar
1974 //-----------------------------------------------------------------------------
1976 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1977 GdkEventButton
*WXUNUSED(gdk_event
),
1982 // don't test here as we can release the mouse while being over
1983 // a different window than the slider
1985 // if (gdk_event->window != widget->slider) return FALSE;
1987 g_blockEventsOnScroll
= FALSE
;
1989 if (win
->m_isScrolling
)
1991 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1995 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1996 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1998 value
= (int)(win
->m_hAdjust
->value
+0.5);
2001 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2003 value
= (int)(win
->m_vAdjust
->value
+0.5);
2007 wxScrollWinEvent
event( command
, value
, dir
);
2008 event
.SetEventObject( win
);
2009 win
->GetEventHandler()->ProcessEvent( event
);
2012 win
->m_isScrolling
= FALSE
;
2017 // ----------------------------------------------------------------------------
2018 // this wxWindowBase function is implemented here (in platform-specific file)
2019 // because it is static and so couldn't be made virtual
2020 // ----------------------------------------------------------------------------
2022 wxWindow
*wxWindowBase::FindFocus()
2024 // the cast is necessary when we compile in wxUniversal mode
2025 return (wxWindow
*)g_focusWindow
;
2028 //-----------------------------------------------------------------------------
2030 //-----------------------------------------------------------------------------
2032 // VZ: Robert commented the code using out so it generates warnings: should
2033 // be either fixed or removed completely
2036 static void gtk_window_destroy_callback( GtkWidget
* widget
, wxWindow
*win
)
2038 wxWindowDestroyEvent
event(win
);
2039 win
->GetEventHandler()->ProcessEvent(event
);
2044 //-----------------------------------------------------------------------------
2045 // "realize" from m_widget
2046 //-----------------------------------------------------------------------------
2048 /* We cannot set colours and fonts before the widget has
2049 been realized, so we do this directly after realization. */
2052 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2057 wxapp_install_idle_handler();
2059 if (win
->m_delayedBackgroundColour
)
2060 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2062 if (win
->m_delayedForegroundColour
)
2063 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2065 wxWindowCreateEvent
event( win
);
2066 event
.SetEventObject( win
);
2067 win
->GetEventHandler()->ProcessEvent( event
);
2072 //-----------------------------------------------------------------------------
2074 //-----------------------------------------------------------------------------
2077 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2078 GtkAllocation
*WXUNUSED(alloc
),
2082 wxapp_install_idle_handler();
2084 if (!win
->m_hasScrolling
) return;
2086 int client_width
= 0;
2087 int client_height
= 0;
2088 win
->GetClientSize( &client_width
, &client_height
);
2089 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2092 win
->m_oldClientWidth
= client_width
;
2093 win
->m_oldClientHeight
= client_height
;
2095 if (!win
->m_nativeSizeEvent
)
2097 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2098 event
.SetEventObject( win
);
2099 win
->GetEventHandler()->ProcessEvent( event
);
2105 #define WXUNUSED_UNLESS_XIM(param) param
2107 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2110 /* Resize XIM window */
2113 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2114 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2115 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2118 wxapp_install_idle_handler();
2124 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2128 gdk_window_get_size (widget
->window
, &width
, &height
);
2129 win
->m_icattr
->preedit_area
.width
= width
;
2130 win
->m_icattr
->preedit_area
.height
= height
;
2131 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2136 //-----------------------------------------------------------------------------
2137 // "realize" from m_wxwindow
2138 //-----------------------------------------------------------------------------
2140 /* Initialize XIM support */
2143 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2144 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2147 wxapp_install_idle_handler();
2150 if (win
->m_ic
) return FALSE
;
2151 if (!widget
) return FALSE
;
2152 if (!gdk_im_ready()) return FALSE
;
2154 win
->m_icattr
= gdk_ic_attr_new();
2155 if (!win
->m_icattr
) return FALSE
;
2159 GdkColormap
*colormap
;
2160 GdkICAttr
*attr
= win
->m_icattr
;
2161 unsigned attrmask
= GDK_IC_ALL_REQ
;
2163 GdkIMStyle supported_style
= (GdkIMStyle
)
2164 (GDK_IM_PREEDIT_NONE
|
2165 GDK_IM_PREEDIT_NOTHING
|
2166 GDK_IM_PREEDIT_POSITION
|
2167 GDK_IM_STATUS_NONE
|
2168 GDK_IM_STATUS_NOTHING
);
2170 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2171 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2173 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2174 attr
->client_window
= widget
->window
;
2176 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2177 gtk_widget_get_default_colormap ())
2179 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2180 attr
->preedit_colormap
= colormap
;
2183 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2184 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2185 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2186 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2188 switch (style
& GDK_IM_PREEDIT_MASK
)
2190 case GDK_IM_PREEDIT_POSITION
:
2191 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2193 g_warning ("over-the-spot style requires fontset");
2197 gdk_window_get_size (widget
->window
, &width
, &height
);
2199 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2200 attr
->spot_location
.x
= 0;
2201 attr
->spot_location
.y
= height
;
2202 attr
->preedit_area
.x
= 0;
2203 attr
->preedit_area
.y
= 0;
2204 attr
->preedit_area
.width
= width
;
2205 attr
->preedit_area
.height
= height
;
2206 attr
->preedit_fontset
= widget
->style
->font
;
2211 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2213 if (win
->m_ic
== NULL
)
2214 g_warning ("Can't create input context.");
2217 mask
= gdk_window_get_events (widget
->window
);
2218 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2219 gdk_window_set_events (widget
->window
, mask
);
2221 if (GTK_WIDGET_HAS_FOCUS(widget
))
2222 gdk_im_begin (win
->m_ic
, widget
->window
);
2229 //-----------------------------------------------------------------------------
2230 // InsertChild for wxWindowGTK.
2231 //-----------------------------------------------------------------------------
2233 /* Callback for wxWindowGTK. This very strange beast has to be used because
2234 * C++ has no virtual methods in a constructor. We have to emulate a
2235 * virtual function here as wxNotebook requires a different way to insert
2236 * a child in it. I had opted for creating a wxNotebookPage window class
2237 * which would have made this superfluous (such in the MDI window system),
2238 * but no-one was listening to me... */
2240 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2242 /* the window might have been scrolled already, do we
2243 have to adapt the position */
2244 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2245 child
->m_x
+= pizza
->xoffset
;
2246 child
->m_y
+= pizza
->yoffset
;
2248 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2249 GTK_WIDGET(child
->m_widget
),
2256 //-----------------------------------------------------------------------------
2258 //-----------------------------------------------------------------------------
2260 wxWindow
*wxGetActiveWindow()
2262 return wxWindow::FindFocus();
2265 //-----------------------------------------------------------------------------
2267 //-----------------------------------------------------------------------------
2269 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2271 #ifdef __WXUNIVERSAL__
2272 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2274 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2275 #endif // __WXUNIVERSAL__/__WXGTK__
2277 void wxWindowGTK::Init()
2283 m_widget
= (GtkWidget
*) NULL
;
2284 m_wxwindow
= (GtkWidget
*) NULL
;
2285 m_focusWidget
= (GtkWidget
*) NULL
;
2295 m_needParent
= TRUE
;
2296 m_isBeingDeleted
= FALSE
;
2299 m_nativeSizeEvent
= FALSE
;
2301 m_hasScrolling
= FALSE
;
2302 m_isScrolling
= FALSE
;
2304 m_hAdjust
= (GtkAdjustment
*) NULL
;
2305 m_vAdjust
= (GtkAdjustment
*) NULL
;
2306 m_oldHorizontalPos
= 0.0;
2307 m_oldVerticalPos
= 0.0;
2310 m_widgetStyle
= (GtkStyle
*) NULL
;
2312 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2314 m_acceptsFocus
= FALSE
;
2317 m_clipPaintRegion
= FALSE
;
2319 m_cursor
= *wxSTANDARD_CURSOR
;
2321 m_delayedForegroundColour
= FALSE
;
2322 m_delayedBackgroundColour
= FALSE
;
2325 m_ic
= (GdkIC
*) NULL
;
2326 m_icattr
= (GdkICAttr
*) NULL
;
2330 wxWindowGTK::wxWindowGTK()
2335 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2340 const wxString
&name
)
2344 Create( parent
, id
, pos
, size
, style
, name
);
2347 bool wxWindowGTK::Create( wxWindow
*parent
,
2352 const wxString
&name
)
2354 if (!PreCreation( parent
, pos
, size
) ||
2355 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2357 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2361 m_insertCallback
= wxInsertChildInWindow
;
2363 // always needed for background clearing
2364 m_delayedBackgroundColour
= TRUE
;
2366 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2367 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2369 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2371 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2372 scroll_class
->scrollbar_spacing
= 0;
2374 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2376 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2377 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2379 m_wxwindow
= gtk_pizza_new();
2381 #ifndef __WXUNIVERSAL__
2382 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2384 if (HasFlag(wxRAISED_BORDER
))
2386 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2388 else if (HasFlag(wxSUNKEN_BORDER
))
2390 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2392 else if (HasFlag(wxSIMPLE_BORDER
))
2394 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2398 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2400 #endif // __WXUNIVERSAL__
2402 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2404 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2405 m_acceptsFocus
= TRUE
;
2407 // I _really_ don't want scrollbars in the beginning
2408 m_vAdjust
->lower
= 0.0;
2409 m_vAdjust
->upper
= 1.0;
2410 m_vAdjust
->value
= 0.0;
2411 m_vAdjust
->step_increment
= 1.0;
2412 m_vAdjust
->page_increment
= 1.0;
2413 m_vAdjust
->page_size
= 5.0;
2414 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2415 m_hAdjust
->lower
= 0.0;
2416 m_hAdjust
->upper
= 1.0;
2417 m_hAdjust
->value
= 0.0;
2418 m_hAdjust
->step_increment
= 1.0;
2419 m_hAdjust
->page_increment
= 1.0;
2420 m_hAdjust
->page_size
= 5.0;
2421 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2423 // these handlers block mouse events to any window during scrolling such as
2424 // motion events and prevent GTK and wxWindows from fighting over where the
2427 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2428 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2430 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2431 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2433 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2434 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2436 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2437 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2439 // these handlers get notified when screen updates are required either when
2440 // scrolling or when the window size (and therefore scrollbar configuration)
2443 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2444 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2445 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2446 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2448 gtk_widget_show( m_wxwindow
);
2451 m_parent
->DoAddChild( this );
2453 m_focusWidget
= m_wxwindow
;
2462 wxWindowGTK::~wxWindowGTK()
2464 if (g_focusWindow
== this)
2465 g_focusWindow
= NULL
;
2467 if (g_activeFrame
== this)
2468 g_activeFrame
= NULL
;
2470 if ( g_delayedFocus
== this )
2471 g_delayedFocus
= NULL
;
2473 m_isBeingDeleted
= TRUE
;
2482 m_parent
->RemoveChild( this );
2486 gdk_ic_destroy (m_ic
);
2488 gdk_ic_attr_destroy (m_icattr
);
2493 #if DISABLE_STYLE_IF_BROKEN_THEME
2494 // don't delete if it's a pixmap theme style
2495 if (!m_widgetStyle
->engine_data
)
2496 gtk_style_unref( m_widgetStyle
);
2498 m_widgetStyle
= (GtkStyle
*) NULL
;
2503 gtk_widget_destroy( m_wxwindow
);
2504 m_wxwindow
= (GtkWidget
*) NULL
;
2509 gtk_widget_destroy( m_widget
);
2510 m_widget
= (GtkWidget
*) NULL
;
2514 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2516 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2518 // This turns -1 into 30 so that a minimal window is
2519 // visible even although -1,-1 has been given as the
2520 // size of the window. the same trick is used in other
2521 // ports and should make debugging easier.
2522 m_width
= WidthDefault(size
.x
) ;
2523 m_height
= HeightDefault(size
.y
);
2528 // some reasonable defaults
2533 m_x
= (gdk_screen_width () - m_width
) / 2;
2534 if (m_x
< 10) m_x
= 10;
2538 m_y
= (gdk_screen_height () - m_height
) / 2;
2539 if (m_y
< 10) m_y
= 10;
2546 void wxWindowGTK::PostCreation()
2548 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2554 // these get reported to wxWindows -> wxPaintEvent
2556 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2558 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2559 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2562 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2563 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2565 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2567 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2568 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2571 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2575 // these are called when the "sunken" or "raised" borders are drawn
2576 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2577 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2580 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2581 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2587 if (m_focusWidget
== NULL
)
2588 m_focusWidget
= m_widget
;
2590 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2591 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2593 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2594 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2596 // connect to the various key and mouse handlers
2598 GtkWidget
*connect_widget
= GetConnectWidget();
2600 ConnectWidget( connect_widget
);
2602 /* We cannot set colours, fonts and cursors before the widget has
2603 been realized, so we do this directly after realization */
2604 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2605 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2609 // Catch native resize events
2610 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2611 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2613 // Initialize XIM support
2614 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2615 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2617 // And resize XIM window
2618 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2619 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2622 if (!GTK_IS_COMBO(m_widget
))
2624 // This is needed if we want to add our windows into native
2625 // GTK control, such as the toolbar. With this callback, the
2626 // toolbar gets to know the correct size (the one set by the
2627 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2628 // when moving to GTK 2.0.
2629 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2630 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2636 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2638 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2639 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2641 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2642 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2644 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2645 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2647 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2648 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2650 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2651 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2653 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2654 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2656 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2657 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2659 // This keeps crashing on me. RR.
2661 // gtk_signal_connect( GTK_OBJECT(widget), "destroy",
2662 // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this );
2665 bool wxWindowGTK::Destroy()
2667 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2671 return wxWindowBase::Destroy();
2674 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2676 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2679 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2681 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2682 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2685 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2688 if (m_resizing
) return; /* I don't like recursions */
2691 int currentX
, currentY
;
2692 GetPosition(¤tX
, ¤tY
);
2697 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2699 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2701 /* don't set the size for children of wxNotebook, just take the values. */
2709 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2710 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2712 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2713 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2717 m_x
= x
+ pizza
->xoffset
;
2718 m_y
= y
+ pizza
->yoffset
;
2720 if (width
!= -1) m_width
= width
;
2721 if (height
!= -1) m_height
= height
;
2723 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2725 if (width
== -1) m_width
= 80;
2728 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2730 if (height
== -1) m_height
= 26;
2733 int minWidth
= GetMinWidth(),
2734 minHeight
= GetMinHeight(),
2735 maxWidth
= GetMaxWidth(),
2736 maxHeight
= GetMaxHeight();
2738 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2739 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2740 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2741 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2744 int bottom_border
= 0;
2747 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2749 /* the default button has a border around it */
2755 DoMoveWindow( m_x
-border
,
2758 m_height
+border
+bottom_border
);
2763 /* Sometimes the client area changes size without the
2764 whole windows's size changing, but if the whole
2765 windows's size doesn't change, no wxSizeEvent will
2766 normally be sent. Here we add an extra test if
2767 the client test has been changed and this will
2769 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2773 wxPrintf( "OnSize sent from " );
2774 if (GetClassInfo() && GetClassInfo()->GetClassName())
2775 wxPrintf( GetClassInfo()->GetClassName() );
2776 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2779 if (!m_nativeSizeEvent
)
2781 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2782 event
.SetEventObject( this );
2783 GetEventHandler()->ProcessEvent( event
);
2789 void wxWindowGTK::OnInternalIdle()
2791 // Update invalidated regions.
2794 // Synthetize activate events.
2795 if ( g_sendActivateEvent
!= -1 )
2797 bool activate
= g_sendActivateEvent
!= 0;
2800 g_sendActivateEvent
= -1;
2802 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2805 if ( g_activeFrameLostFocus
)
2807 if ( g_activeFrame
)
2809 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2810 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2811 event
.SetEventObject(g_activeFrame
);
2812 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2813 g_activeFrame
= NULL
;
2815 g_activeFrameLostFocus
= FALSE
;
2818 wxCursor cursor
= m_cursor
;
2819 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2823 /* I now set the cursor anew in every OnInternalIdle call
2824 as setting the cursor in a parent window also effects the
2825 windows above so that checking for the current cursor is
2830 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2832 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2834 if (!g_globalCursor
.Ok())
2835 cursor
= *wxSTANDARD_CURSOR
;
2837 window
= m_widget
->window
;
2838 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2839 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2845 GdkWindow
*window
= m_widget
->window
;
2846 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2847 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2855 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2857 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2859 if (width
) (*width
) = m_width
;
2860 if (height
) (*height
) = m_height
;
2863 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2865 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2869 SetSize( width
, height
);
2876 #ifndef __WXUNIVERSAL__
2877 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2879 /* when using GTK 1.2 we set the shadow border size to 2 */
2883 if (HasFlag(wxSIMPLE_BORDER
))
2885 /* when using GTK 1.2 we set the simple border size to 1 */
2889 #endif // __WXUNIVERSAL__
2893 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2895 GtkRequisition vscroll_req
;
2896 vscroll_req
.width
= 2;
2897 vscroll_req
.height
= 2;
2898 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2899 (scroll_window
->vscrollbar
, &vscroll_req
);
2901 GtkRequisition hscroll_req
;
2902 hscroll_req
.width
= 2;
2903 hscroll_req
.height
= 2;
2904 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2905 (scroll_window
->hscrollbar
, &hscroll_req
);
2907 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2909 if (scroll_window
->vscrollbar_visible
)
2911 dw
+= vscroll_req
.width
;
2912 dw
+= scroll_class
->scrollbar_spacing
;
2915 if (scroll_window
->hscrollbar_visible
)
2917 dh
+= hscroll_req
.height
;
2918 dh
+= scroll_class
->scrollbar_spacing
;
2922 SetSize( width
+dw
, height
+dh
);
2926 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2928 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2932 if (width
) (*width
) = m_width
;
2933 if (height
) (*height
) = m_height
;
2940 #ifndef __WXUNIVERSAL__
2941 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2943 /* when using GTK 1.2 we set the shadow border size to 2 */
2947 if (HasFlag(wxSIMPLE_BORDER
))
2949 /* when using GTK 1.2 we set the simple border size to 1 */
2953 #endif // __WXUNIVERSAL__
2957 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2959 GtkRequisition vscroll_req
;
2960 vscroll_req
.width
= 2;
2961 vscroll_req
.height
= 2;
2962 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2963 (scroll_window
->vscrollbar
, &vscroll_req
);
2965 GtkRequisition hscroll_req
;
2966 hscroll_req
.width
= 2;
2967 hscroll_req
.height
= 2;
2968 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2969 (scroll_window
->hscrollbar
, &hscroll_req
);
2971 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2973 if (scroll_window
->vscrollbar_visible
)
2975 dw
+= vscroll_req
.width
;
2976 dw
+= scroll_class
->scrollbar_spacing
;
2979 if (scroll_window
->hscrollbar_visible
)
2981 dh
+= hscroll_req
.height
;
2982 dh
+= scroll_class
->scrollbar_spacing
;
2986 if (width
) (*width
) = m_width
- dw
;
2987 if (height
) (*height
) = m_height
- dh
;
2991 printf( "GetClientSize, name %s ", GetName().c_str() );
2992 if (width) printf( " width = %d", (*width) );
2993 if (height) printf( " height = %d", (*height) );
2998 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3000 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3004 if (m_parent
&& m_parent
->m_wxwindow
)
3006 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3007 dx
= pizza
->xoffset
;
3008 dy
= pizza
->yoffset
;
3011 if (x
) (*x
) = m_x
- dx
;
3012 if (y
) (*y
) = m_y
- dy
;
3015 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3017 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3019 if (!m_widget
->window
) return;
3021 GdkWindow
*source
= (GdkWindow
*) NULL
;
3023 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3025 source
= m_widget
->window
;
3029 gdk_window_get_origin( source
, &org_x
, &org_y
);
3033 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3035 org_x
+= m_widget
->allocation
.x
;
3036 org_y
+= m_widget
->allocation
.y
;
3044 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3046 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3048 if (!m_widget
->window
) return;
3050 GdkWindow
*source
= (GdkWindow
*) NULL
;
3052 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3054 source
= m_widget
->window
;
3058 gdk_window_get_origin( source
, &org_x
, &org_y
);
3062 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3064 org_x
+= m_widget
->allocation
.x
;
3065 org_y
+= m_widget
->allocation
.y
;
3073 bool wxWindowGTK::Show( bool show
)
3075 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3077 if (!wxWindowBase::Show(show
))
3084 gtk_widget_show( m_widget
);
3086 gtk_widget_hide( m_widget
);
3091 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3093 win
->OnParentEnable(enable
);
3095 // Recurse, so that children have the opportunity to Do The Right Thing
3096 // and reset colours that have been messed up by a parent's (really ancestor's)
3098 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3100 node
= node
->GetNext() )
3102 wxWindow
*child
= node
->GetData();
3103 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3104 wxWindowNotifyEnable(child
, enable
);
3108 bool wxWindowGTK::Enable( bool enable
)
3110 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3112 if (!wxWindowBase::Enable(enable
))
3118 gtk_widget_set_sensitive( m_widget
, enable
);
3120 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3122 wxWindowNotifyEnable(this, enable
);
3127 int wxWindowGTK::GetCharHeight() const
3129 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3131 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3133 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3135 return font
->ascent
+ font
->descent
;
3138 int wxWindowGTK::GetCharWidth() const
3140 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3142 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3144 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3146 return gdk_string_width( font
, "H" );
3149 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3153 int *externalLeading
,
3154 const wxFont
*theFont
) const
3156 wxFont fontToUse
= m_font
;
3157 if (theFont
) fontToUse
= *theFont
;
3159 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3161 if (string
.IsEmpty())
3169 PangoContext
*context
= NULL
;
3171 gtk_widget_get_pango_context( m_widget
);
3180 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3181 PangoLayout
*layout
= pango_layout_new(context
);
3182 pango_layout_set_font_description(layout
, desc
);
3185 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3186 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3188 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3189 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3190 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3193 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3195 PangoRectangle rect
;
3196 pango_layout_line_get_extents(line
, NULL
, &rect
);
3198 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3199 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3202 // Do something about metrics here
3205 if (externalLeading
) (*externalLeading
) = 0; // ??
3207 g_object_unref( G_OBJECT( layout
) );
3209 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3210 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3211 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3212 if (descent
) (*descent
) = font
->descent
;
3213 if (externalLeading
) (*externalLeading
) = 0; // ??
3217 void wxWindowGTK::SetFocus()
3219 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3223 // don't do anything if we already have focus
3229 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3231 gtk_widget_grab_focus (m_wxwindow
);
3236 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3238 if (!GTK_WIDGET_REALIZED(m_widget
))
3240 // we can't set the focus to the widget now so we remember that
3241 // it should be focused and will do it later, during the idle
3242 // time, as soon as we can
3243 wxLogTrace(TRACE_FOCUS
,
3244 _T("Delaying setting focus to %s(%s)"),
3245 GetClassInfo()->GetClassName(), GetLabel().c_str());
3247 g_delayedFocus
= this;
3251 wxLogTrace(TRACE_FOCUS
,
3252 _T("Setting focus to %s(%s)"),
3253 GetClassInfo()->GetClassName(), GetLabel().c_str());
3255 gtk_widget_grab_focus (m_widget
);
3258 else if (GTK_IS_CONTAINER(m_widget
))
3260 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3264 wxLogTrace(TRACE_FOCUS
,
3265 _T("Can't set focus to %s(%s)"),
3266 GetClassInfo()->GetClassName(), GetLabel().c_str());
3271 bool wxWindowGTK::AcceptsFocus() const
3273 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3276 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3278 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3280 wxWindowGTK
*oldParent
= m_parent
,
3281 *newParent
= (wxWindowGTK
*)newParentBase
;
3283 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3285 if ( !wxWindowBase::Reparent(newParent
) )
3288 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3290 /* prevent GTK from deleting the widget arbitrarily */
3291 gtk_widget_ref( m_widget
);
3295 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3298 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3302 /* insert GTK representation */
3303 (*(newParent
->m_insertCallback
))(newParent
, this);
3306 /* reverse: prevent GTK from deleting the widget arbitrarily */
3307 gtk_widget_unref( m_widget
);
3312 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3314 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3316 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3318 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3323 /* insert GTK representation */
3324 (*m_insertCallback
)(this, child
);
3327 void wxWindowGTK::Raise()
3329 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3331 if (!m_widget
->window
) return;
3333 gdk_window_raise( m_widget
->window
);
3336 void wxWindowGTK::Lower()
3338 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3340 if (!m_widget
->window
) return;
3342 gdk_window_lower( m_widget
->window
);
3345 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3347 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3349 if (cursor
== m_cursor
)
3353 wxapp_install_idle_handler();
3355 if (cursor
== wxNullCursor
)
3356 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3358 return wxWindowBase::SetCursor( cursor
);
3361 void wxWindowGTK::WarpPointer( int x
, int y
)
3363 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3365 // We provide this function ourselves as it is
3366 // missing in GDK (top of this file).
3368 GdkWindow
*window
= (GdkWindow
*) NULL
;
3370 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3372 window
= GetConnectWidget()->window
;
3375 gdk_window_warp_pointer( window
, x
, y
);
3379 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3381 if (!m_widget
) return;
3382 if (!m_widget
->window
) return;
3386 wxapp_install_idle_handler();
3388 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3392 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3393 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3397 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3398 m_clearRegion
.Clear();
3399 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3407 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3408 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3412 GdkRectangle gdk_rect
;
3413 gdk_rect
.x
= rect
->x
;
3414 gdk_rect
.y
= rect
->y
;
3415 gdk_rect
.width
= rect
->width
;
3416 gdk_rect
.height
= rect
->height
;
3417 gtk_widget_draw( m_widget
, &gdk_rect
);
3424 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3425 m_updateRegion
.Clear();
3426 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3430 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3438 GdkRectangle gdk_rect
;
3439 gdk_rect
.x
= rect
->x
;
3440 gdk_rect
.y
= rect
->y
;
3441 gdk_rect
.width
= rect
->width
;
3442 gdk_rect
.height
= rect
->height
;
3443 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3447 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3453 void wxWindowGTK::Update()
3458 void wxWindowGTK::GtkUpdate()
3461 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3462 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3464 if (!m_updateRegion
.IsEmpty())
3465 GtkSendPaintEvents();
3469 void wxWindowGTK::GtkSendPaintEvents()
3474 m_clearRegion
.Clear();
3476 m_updateRegion
.Clear();
3480 // Clip to paint region in wxClientDC
3481 m_clipPaintRegion
= TRUE
;
3484 // widget to draw on
3485 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3487 // later for GTK 2.0, too.
3488 if (GetThemeEnabled())
3490 // find ancestor from which to steal background
3491 wxWindow
*parent
= GetParent();
3492 while (parent
&& !parent
->IsTopLevel())
3493 parent
= parent
->GetParent();
3495 parent
= (wxWindow
*)this;
3497 wxRegionIterator
upd( m_updateRegion
);
3501 rect
.x
= upd
.GetX();
3502 rect
.y
= upd
.GetY();
3503 rect
.width
= upd
.GetWidth();
3504 rect
.height
= upd
.GetHeight();
3506 gtk_paint_flat_box( parent
->m_widget
->style
,
3523 wxWindowDC
dc( (wxWindow
*)this );
3524 dc
.SetClippingRegion( m_updateRegion
);
3526 wxEraseEvent
erase_event( GetId(), &dc
);
3527 erase_event
.SetEventObject( this );
3529 GetEventHandler()->ProcessEvent(erase_event
);
3532 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3534 wxWindowDC
dc( (wxWindow
*)this );
3535 if (m_clearRegion
.IsEmpty())
3536 dc
.SetClippingRegion( m_updateRegion
);
3538 dc
.SetClippingRegion( m_clearRegion
);
3540 wxEraseEvent
erase_event( GetId(), &dc
);
3541 erase_event
.SetEventObject( this );
3543 if (!GetEventHandler()->ProcessEvent(erase_event
))
3547 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3548 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3550 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3552 wxRegionIterator
upd( m_clearRegion
);
3555 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3556 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3560 m_clearRegion
.Clear();
3564 wxNcPaintEvent
nc_paint_event( GetId() );
3565 nc_paint_event
.SetEventObject( this );
3566 GetEventHandler()->ProcessEvent( nc_paint_event
);
3568 wxPaintEvent
paint_event( GetId() );
3569 paint_event
.SetEventObject( this );
3570 GetEventHandler()->ProcessEvent( paint_event
);
3572 m_clipPaintRegion
= FALSE
;
3574 #ifndef __WXUNIVERSAL__
3576 // The following code will result in all window-less widgets
3577 // being redrawn because the wxWindows class is allowed to
3578 // paint over the window-less widgets.
3580 GList
*children
= pizza
->children
;
3583 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3584 children
= children
->next
;
3586 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3587 GTK_WIDGET_DRAWABLE (child
->widget
))
3589 // Get intersection of widget area and update region
3590 wxRegion
region( m_updateRegion
);
3592 GdkEventExpose gdk_event
;
3593 gdk_event
.type
= GDK_EXPOSE
;
3594 gdk_event
.window
= pizza
->bin_window
;
3595 gdk_event
.count
= 0;
3597 wxRegionIterator
upd( m_updateRegion
);
3601 rect
.x
= upd
.GetX();
3602 rect
.y
= upd
.GetY();
3603 rect
.width
= upd
.GetWidth();
3604 rect
.height
= upd
.GetHeight();
3606 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3608 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3618 m_updateRegion
.Clear();
3621 void wxWindowGTK::Clear()
3623 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3626 if (m_wxwindow
&& m_wxwindow
->window
)
3628 m_clearRegion
.Clear();
3629 wxSize
size( GetClientSize() );
3630 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3632 // Better do this in idle?
3639 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3641 wxWindowBase::DoSetToolTip(tip
);
3644 m_tooltip
->Apply( (wxWindow
*)this );
3647 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3649 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3651 #endif // wxUSE_TOOLTIPS
3653 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3655 GdkWindow
*window
= (GdkWindow
*) NULL
;
3657 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3659 window
= GetConnectWidget()->window
;
3663 // We need the pixel value e.g. for background clearing.
3664 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3668 // wxMSW doesn't clear the window here, either.
3669 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3675 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3677 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3679 if (!wxWindowBase::SetBackgroundColour(colour
))
3682 GdkWindow
*window
= (GdkWindow
*) NULL
;
3684 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3686 window
= GetConnectWidget()->window
;
3690 // indicate that a new style has been set
3691 // but it couldn't get applied as the
3692 // widget hasn't been realized yet.
3693 m_delayedBackgroundColour
= TRUE
;
3698 GtkSetBackgroundColour( colour
);
3704 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3706 GdkWindow
*window
= (GdkWindow
*) NULL
;
3708 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3710 window
= GetConnectWidget()->window
;
3717 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3719 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3721 if (!wxWindowBase::SetForegroundColour(colour
))
3723 // don't leave if the GTK widget has just
3725 if (!m_delayedForegroundColour
) return FALSE
;
3728 GdkWindow
*window
= (GdkWindow
*) NULL
;
3730 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3732 window
= GetConnectWidget()->window
;
3736 // indicate that a new style has been set
3737 // but it couldn't get applied as the
3738 // widget hasn't been realized yet.
3739 m_delayedForegroundColour
= TRUE
;
3743 GtkSetForegroundColour( colour
);
3749 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3753 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3755 // FIXME: no more klass in 2.0
3757 remake
->klass
= m_widgetStyle
->klass
;
3760 gtk_style_unref( m_widgetStyle
);
3761 m_widgetStyle
= remake
;
3765 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3768 def
= gtk_widget_get_default_style();
3770 m_widgetStyle
= gtk_style_copy( def
);
3772 // FIXME: no more klass in 2.0
3774 m_widgetStyle
->klass
= def
->klass
;
3778 return m_widgetStyle
;
3781 void wxWindowGTK::SetWidgetStyle()
3783 #if DISABLE_STYLE_IF_BROKEN_THEME
3784 if (m_widget
->style
->engine_data
)
3786 static bool s_warningPrinted
= FALSE
;
3787 if (!s_warningPrinted
)
3789 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3790 s_warningPrinted
= TRUE
;
3792 m_widgetStyle
= m_widget
->style
;
3797 GtkStyle
*style
= GetWidgetStyle();
3799 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3801 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3804 if (m_foregroundColour
.Ok())
3806 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3807 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3809 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3810 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3811 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3815 // Try to restore the gtk default style. This is still a little
3816 // oversimplified for what is probably really needed here for controls
3817 // other than buttons, but is better than not being able to (re)set a
3818 // control's foreground colour to *wxBLACK -- RL
3819 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3822 def
= gtk_widget_get_default_style();
3824 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3825 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3826 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3830 if (m_backgroundColour
.Ok())
3832 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3833 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3835 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3836 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3837 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3838 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3839 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3840 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3841 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3842 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3846 // Try to restore the gtk default style. This is still a little
3847 // oversimplified for what is probably really needed here for controls
3848 // other than buttons, but is better than not being able to (re)set a
3849 // control's background colour to default grey and means resetting a
3850 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3852 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3855 def
= gtk_widget_get_default_style();
3857 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3858 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3859 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3860 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3861 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3862 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3863 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3864 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3869 void wxWindowGTK::ApplyWidgetStyle()
3873 //-----------------------------------------------------------------------------
3874 // Pop-up menu stuff
3875 //-----------------------------------------------------------------------------
3877 #if wxUSE_MENUS_NATIVE
3880 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3882 *is_waiting
= FALSE
;
3885 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3887 menu
->SetInvokingWindow( win
);
3888 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3891 wxMenuItem
*menuitem
= node
->GetData();
3892 if (menuitem
->IsSubMenu())
3894 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3897 node
= node
->GetNext();
3901 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3902 // wxPopupMenuPositionCallback()
3904 // should be safe even in the MT case as the user can hardly popup 2 menus
3905 // simultaneously, can he?
3906 static gint gs_pop_x
= 0;
3907 static gint gs_pop_y
= 0;
3909 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3912 gboolean
* WXUNUSED(whatever
),
3914 gpointer
WXUNUSED(user_data
) )
3916 // ensure that the menu appears entirely on screen
3918 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3920 wxSize sizeScreen
= wxGetDisplaySize();
3922 gint xmax
= sizeScreen
.x
- req
.width
,
3923 ymax
= sizeScreen
.y
- req
.height
;
3925 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3926 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3929 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3931 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3933 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3935 SetInvokingWindow( menu
, this );
3941 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3943 bool is_waiting
= TRUE
;
3945 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3947 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3948 (gpointer
)&is_waiting
);
3951 GTK_MENU(menu
->m_menu
),
3952 (GtkWidget
*) NULL
, // parent menu shell
3953 (GtkWidget
*) NULL
, // parent menu item
3954 wxPopupMenuPositionCallback
, // function to position it
3955 NULL
, // client data
3956 0, // button used to activate it
3957 gs_timeLastClick
// the time of activation
3962 while (gtk_events_pending())
3963 gtk_main_iteration();
3969 #endif // wxUSE_MENUS_NATIVE
3971 #if wxUSE_DRAG_AND_DROP
3973 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3975 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3977 GtkWidget
*dnd_widget
= GetConnectWidget();
3979 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3981 if (m_dropTarget
) delete m_dropTarget
;
3982 m_dropTarget
= dropTarget
;
3984 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3987 #endif // wxUSE_DRAG_AND_DROP
3989 GtkWidget
* wxWindowGTK::GetConnectWidget()
3991 GtkWidget
*connect_widget
= m_widget
;
3992 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3994 return connect_widget
;
3997 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4000 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4002 return (window
== m_widget
->window
);
4005 bool wxWindowGTK::SetFont( const wxFont
&font
)
4007 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4009 if (!wxWindowBase::SetFont(font
))
4014 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4015 if ( sysbg
== m_backgroundColour
)
4017 m_backgroundColour
= wxNullColour
;
4019 m_backgroundColour
= sysbg
;
4029 void wxWindowGTK::DoCaptureMouse()
4031 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4033 GdkWindow
*window
= (GdkWindow
*) NULL
;
4035 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4037 window
= GetConnectWidget()->window
;
4039 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4041 wxCursor
* cursor
= & m_cursor
;
4043 cursor
= wxSTANDARD_CURSOR
;
4045 gdk_pointer_grab( window
, FALSE
,
4047 (GDK_BUTTON_PRESS_MASK
|
4048 GDK_BUTTON_RELEASE_MASK
|
4049 GDK_POINTER_MOTION_HINT_MASK
|
4050 GDK_POINTER_MOTION_MASK
),
4052 cursor
->GetCursor(),
4053 (guint32
)GDK_CURRENT_TIME
);
4054 g_captureWindow
= this;
4055 g_captureWindowHasMouse
= TRUE
;
4058 void wxWindowGTK::DoReleaseMouse()
4060 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4062 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4064 g_captureWindow
= (wxWindowGTK
*) NULL
;
4066 GdkWindow
*window
= (GdkWindow
*) NULL
;
4068 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4070 window
= GetConnectWidget()->window
;
4075 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4079 wxWindow
*wxWindowBase::GetCapture()
4081 return (wxWindow
*)g_captureWindow
;
4084 bool wxWindowGTK::IsRetained() const
4089 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4090 int range
, bool refresh
)
4092 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4094 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4096 m_hasScrolling
= TRUE
;
4098 if (orient
== wxHORIZONTAL
)
4100 float fpos
= (float)pos
;
4101 float frange
= (float)range
;
4102 float fthumb
= (float)thumbVisible
;
4103 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4104 if (fpos
< 0.0) fpos
= 0.0;
4106 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4107 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4109 SetScrollPos( orient
, pos
, refresh
);
4113 m_oldHorizontalPos
= fpos
;
4115 m_hAdjust
->lower
= 0.0;
4116 m_hAdjust
->upper
= frange
;
4117 m_hAdjust
->value
= fpos
;
4118 m_hAdjust
->step_increment
= 1.0;
4119 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4120 m_hAdjust
->page_size
= fthumb
;
4124 float fpos
= (float)pos
;
4125 float frange
= (float)range
;
4126 float fthumb
= (float)thumbVisible
;
4127 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4128 if (fpos
< 0.0) fpos
= 0.0;
4130 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4131 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4133 SetScrollPos( orient
, pos
, refresh
);
4137 m_oldVerticalPos
= fpos
;
4139 m_vAdjust
->lower
= 0.0;
4140 m_vAdjust
->upper
= frange
;
4141 m_vAdjust
->value
= fpos
;
4142 m_vAdjust
->step_increment
= 1.0;
4143 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4144 m_vAdjust
->page_size
= fthumb
;
4147 if (orient
== wxHORIZONTAL
)
4148 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4150 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4153 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4155 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4157 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4159 if (orient
== wxHORIZONTAL
)
4161 float fpos
= (float)pos
;
4162 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4163 if (fpos
< 0.0) fpos
= 0.0;
4164 m_oldHorizontalPos
= fpos
;
4166 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4167 m_hAdjust
->value
= fpos
;
4171 float fpos
= (float)pos
;
4172 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4173 if (fpos
< 0.0) fpos
= 0.0;
4174 m_oldVerticalPos
= fpos
;
4176 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4177 m_vAdjust
->value
= fpos
;
4180 if (m_wxwindow
->window
)
4182 if (orient
== wxHORIZONTAL
)
4184 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4185 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4187 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4189 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4190 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4194 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4195 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4197 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4199 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4200 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4205 int wxWindowGTK::GetScrollThumb( int orient
) const
4207 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4209 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4211 if (orient
== wxHORIZONTAL
)
4212 return (int)(m_hAdjust
->page_size
+0.5);
4214 return (int)(m_vAdjust
->page_size
+0.5);
4217 int wxWindowGTK::GetScrollPos( int orient
) const
4219 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4221 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4223 if (orient
== wxHORIZONTAL
)
4224 return (int)(m_hAdjust
->value
+0.5);
4226 return (int)(m_vAdjust
->value
+0.5);
4229 int wxWindowGTK::GetScrollRange( int orient
) const
4231 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4233 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4235 if (orient
== wxHORIZONTAL
)
4236 return (int)(m_hAdjust
->upper
+0.5);
4238 return (int)(m_vAdjust
->upper
+0.5);
4241 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4243 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4245 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4247 // No scrolling requested.
4248 if ((dx
== 0) && (dy
== 0)) return;
4251 if (!m_updateRegion
.IsEmpty())
4253 m_updateRegion
.Offset( dx
, dy
);
4257 GetClientSize( &cw
, &ch
);
4258 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4261 if (!m_clearRegion
.IsEmpty())
4263 m_clearRegion
.Offset( dx
, dy
);
4267 GetClientSize( &cw
, &ch
);
4268 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4272 m_clipPaintRegion
= TRUE
;
4274 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4276 m_clipPaintRegion
= FALSE
;
4280 // Find the wxWindow at the current mouse position, also returning the mouse
4282 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4284 pt
= wxGetMousePosition();
4285 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4289 // Get the current mouse position.
4290 wxPoint
wxGetMousePosition()
4292 /* This crashes when used within wxHelpContext,
4293 so we have to use the X-specific implementation below.
4295 GdkModifierType *mask;
4296 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4298 return wxPoint(x, y);
4302 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4304 return wxPoint(-999, -999);
4306 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4307 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4308 Window rootReturn
, childReturn
;
4309 int rootX
, rootY
, winX
, winY
;
4310 unsigned int maskReturn
;
4312 XQueryPointer (display
,
4316 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4317 return wxPoint(rootX
, rootY
);
4321 // ----------------------------------------------------------------------------
4323 // ----------------------------------------------------------------------------
4325 class wxWinModule
: public wxModule
4332 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4335 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4337 bool wxWinModule::OnInit()
4339 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4340 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4345 void wxWinModule::OnExit()
4348 gdk_gc_unref( g_eraseGC
);