1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "window.h"
16 #define XWarpPointer XWARPPOINTER
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
24 #include "wx/layout.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28 #include "wx/module.h"
30 #if wxUSE_DRAG_AND_DROP
35 #include "wx/tooltip.h"
43 #include "wx/textctrl.h"
47 #include "wx/statusbr.h"
49 #include "wx/settings.h"
53 #include "wx/thread.h"
58 #include "wx/gtk/private.h"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
69 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
71 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
81 extern GtkContainerClass
*pizza_parent_class
;
84 //-----------------------------------------------------------------------------
85 // documentation on internals
86 //-----------------------------------------------------------------------------
89 I have been asked several times about writing some documentation about
90 the GTK port of wxWindows, especially its internal structures. Obviously,
91 you cannot understand wxGTK without knowing a little about the GTK, but
92 some more information about what the wxWindow, which is the base class
93 for all other window classes, does seems required as well.
97 What does wxWindow do? It contains the common interface for the following
98 jobs of its descendants:
100 1) Define the rudimentary behaviour common to all window classes, such as
101 resizing, intercepting user input (so as to make it possible to use these
102 events for special purposes in a derived class), window names etc.
104 2) Provide the possibility to contain and manage children, if the derived
105 class is allowed to contain children, which holds true for those window
106 classes which do not display a native GTK widget. To name them, these
107 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
108 work classes are a special case and are handled a bit differently from
109 the rest. The same holds true for the wxNotebook class.
111 3) Provide the possibility to draw into a client area of a window. This,
112 too, only holds true for classes that do not display a native GTK widget
115 4) Provide the entire mechanism for scrolling widgets. This actual inter-
116 face for this is usually in wxScrolledWindow, but the GTK implementation
119 5) A multitude of helper or extra methods for special purposes, such as
120 Drag'n'Drop, managing validators etc.
122 6) Display a border (sunken, raised, simple or none).
124 Normally one might expect, that one wxWindows window would always correspond
125 to one GTK widget. Under GTK, there is no such allround widget that has all
126 the functionality. Moreover, the GTK defines a client area as a different
127 widget from the actual widget you are handling. Last but not least some
128 special classes (e.g. wxFrame) handle different categories of widgets and
129 still have the possibility to draw something in the client area.
130 It was therefore required to write a special purpose GTK widget, that would
131 represent a client area in the sense of wxWindows capable to do the jobs
132 2), 3) and 4). I have written this class and it resides in win_gtk.c of
135 All windows must have a widget, with which they interact with other under-
136 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
137 thw wxWindow class has a member variable called m_widget which holds a
138 pointer to this widget. When the window class represents a GTK native widget,
139 this is (in most cases) the only GTK widget the class manages. E.g. the
140 wxStatitText class handles only a GtkLabel widget a pointer to which you
141 can find in m_widget (defined in wxWindow)
143 When the class has a client area for drawing into and for containing children
144 it has to handle the client area widget (of the type GtkPizza, defined in
145 win_gtk.c), but there could be any number of widgets, handled by a class
146 The common rule for all windows is only, that the widget that interacts with
147 the rest of GTK must be referenced in m_widget and all other widgets must be
148 children of this widget on the GTK level. The top-most widget, which also
149 represents the client area, must be in the m_wxwindow field and must be of
152 As I said, the window classes that display a GTK native widget only have
153 one widget, so in the case of e.g. the wxButton class m_widget holds a
154 pointer to a GtkButton widget. But windows with client areas (for drawing
155 and children) have a m_widget field that is a pointer to a GtkScrolled-
156 Window and a m_wxwindow field that is pointer to a GtkPizza and this
157 one is (in the GTK sense) a child of the GtkScrolledWindow.
159 If the m_wxwindow field is set, then all input to this widget is inter-
160 cepted and sent to the wxWindows class. If not, all input to the widget
161 that gets pointed to by m_widget gets intercepted and sent to the class.
165 The design of scrolling in wxWindows is markedly different from that offered
166 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
167 clicking on a scrollbar belonging to scrolled window will inevitably move
168 the window. In wxWindows, the scrollbar will only emit an event, send this
169 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
170 which actually moves the window and its subchildren. Note that GtkPizza
171 memorizes how much it has been scrolled but that wxWindows forgets this
172 so that the two coordinates systems have to be kept in synch. This is done
173 in various places using the pizza->xoffset and pizza->yoffset values.
177 Singularily the most broken code in GTK is the code that is supposes to
178 inform subwindows (child windows) about new positions. Very often, duplicate
179 events are sent without changes in size or position, equally often no
180 events are sent at all (All this is due to a bug in the GtkContainer code
181 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
182 GTK's own system and it simply waits for size events for toplevel windows
183 and then iterates down the respective size events to all window. This has
184 the disadvantage, that windows might get size events before the GTK widget
185 actually has the reported size. This doesn't normally pose any problem, but
186 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
187 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
188 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
189 window that is used for OpenGl output really has that size (as reported by
194 If someone at some point of time feels the immense desire to have a look at,
195 change or attempt to optimse the Refresh() logic, this person will need an
196 intimate understanding of what a "draw" and what an "expose" events are and
197 what there are used for, in particular when used in connection with GTK's
198 own windowless widgets. Beware.
202 Cursors, too, have been a constant source of pleasure. The main difficulty
203 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
204 for the parent. To prevent this from doing too much harm, I use idle time
205 to set the cursor over and over again, starting from the toplevel windows
206 and ending with the youngest generation (speaking of parent and child windows).
207 Also don't forget that cursors (like much else) are connected to GdkWindows,
208 not GtkWidgets and that the "window" field of a GtkWidget might very well
209 point to the GdkWindow of the parent widget (-> "window less widget") and
210 that the two obviously have very different meanings.
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 extern wxList wxPendingDelete
;
219 extern bool g_blockEventsOnDrag
;
220 extern bool g_blockEventsOnScroll
;
221 extern wxCursor g_globalCursor
;
223 static GdkGC
*g_eraseGC
= NULL
;
225 // mouse capture state: the window which has it and if the mouse is currently
227 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
228 static bool g_captureWindowHasMouse
= FALSE
;
230 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
232 // the last window which had the focus - this is normally never NULL (except
233 // if we never had focus at all) as even when g_focusWindow is NULL it still
234 // keeps its previous value
235 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
237 // the frame that is currently active (i.e. its child has focus). It is
238 // used to generate wxActivateEvents
239 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
240 static bool g_activeFrameLostFocus
= FALSE
;
242 // If a window get the focus set but has not been realized
243 // yet, defer setting the focus to idle time.
244 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
246 // if we detect that the app has got/lost the focus, we set this variable to
247 // either TRUE or FALSE and an activate event will be sent during the next
248 // OnIdle() call and it is reset to -1: this value means that we shouldn't
249 // send any activate events at all
250 static int g_sendActivateEvent
= -1;
252 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
253 the last click here */
254 static guint32 gs_timeLastClick
= 0;
256 extern bool g_mainThreadLocked
;
258 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
263 #define DISABLE_STYLE_IF_BROKEN_THEME 1
269 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
271 # define DEBUG_MAIN_THREAD
274 #define DEBUG_MAIN_THREAD
277 //-----------------------------------------------------------------------------
278 // missing gdk functions
279 //-----------------------------------------------------------------------------
282 gdk_window_warp_pointer (GdkWindow
*window
,
287 GdkWindowPrivate
*priv
;
291 window
= GDK_ROOT_PARENT();
294 if (!GDK_WINDOW_DESTROYED(window
))
296 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
297 None
, /* not source window -> move from anywhere */
298 GDK_WINDOW_XID(window
), /* dest window */
299 0, 0, 0, 0, /* not source window -> move from anywhere */
303 priv
= (GdkWindowPrivate
*) window
;
305 if (!priv
->destroyed
)
307 XWarpPointer (priv
->xdisplay
,
308 None
, /* not source window -> move from anywhere */
309 priv
->xwindow
, /* dest window */
310 0, 0, 0, 0, /* not source window -> move from anywhere */
316 //-----------------------------------------------------------------------------
318 //-----------------------------------------------------------------------------
320 extern void wxapp_install_idle_handler();
321 extern bool g_isIdle
;
323 //-----------------------------------------------------------------------------
324 // local code (see below)
325 //-----------------------------------------------------------------------------
327 // returns the child of win which currently has focus or NULL if not found
329 // Note: can't be static, needed by textctrl.cpp.
330 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
332 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
334 return (wxWindow
*)NULL
;
336 if ( winFocus
== win
)
337 return (wxWindow
*)win
;
339 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
341 node
= node
->GetNext() )
343 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
348 return (wxWindow
*)NULL
;
351 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
353 // wxUniversal widgets draw the borders and scrollbars themselves
354 #ifndef __WXUNIVERSAL__
361 if (win
->m_hasScrolling
)
363 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
365 GtkRequisition vscroll_req
;
366 vscroll_req
.width
= 2;
367 vscroll_req
.height
= 2;
368 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
369 (scroll_window
->vscrollbar
, &vscroll_req
);
371 GtkRequisition hscroll_req
;
372 hscroll_req
.width
= 2;
373 hscroll_req
.height
= 2;
374 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
375 (scroll_window
->hscrollbar
, &hscroll_req
);
377 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
379 if (scroll_window
->vscrollbar_visible
)
381 dw
+= vscroll_req
.width
;
382 dw
+= scroll_class
->scrollbar_spacing
;
385 if (scroll_window
->hscrollbar_visible
)
387 dh
+= hscroll_req
.height
;
388 dh
+= scroll_class
->scrollbar_spacing
;
394 if (GTK_WIDGET_NO_WINDOW (widget
))
396 dx
+= widget
->allocation
.x
;
397 dy
+= widget
->allocation
.y
;
400 if (win
->HasFlag(wxRAISED_BORDER
))
402 gtk_draw_shadow( widget
->style
,
407 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
411 if (win
->HasFlag(wxSUNKEN_BORDER
))
413 gtk_draw_shadow( widget
->style
,
418 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
422 if (win
->HasFlag(wxSIMPLE_BORDER
))
425 gc
= gdk_gc_new( widget
->window
);
426 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
427 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
429 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
433 #endif // __WXUNIVERSAL__
436 //-----------------------------------------------------------------------------
437 // "expose_event" of m_widget
438 //-----------------------------------------------------------------------------
440 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
442 if (gdk_event
->count
> 0) return FALSE
;
444 draw_frame( widget
, win
);
448 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
454 //-----------------------------------------------------------------------------
455 // "draw" of m_widget
456 //-----------------------------------------------------------------------------
460 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
462 draw_frame( widget
, win
);
467 //-----------------------------------------------------------------------------
468 // "size_request" of m_widget
469 //-----------------------------------------------------------------------------
471 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
474 win
->GetSize( &w
, &h
);
478 requisition
->height
= h
;
479 requisition
->width
= w
;
482 //-----------------------------------------------------------------------------
483 // "expose_event" of m_wxwindow
484 //-----------------------------------------------------------------------------
486 static int gtk_window_expose_callback( GtkWidget
*widget
,
487 GdkEventExpose
*gdk_event
,
493 wxapp_install_idle_handler();
498 wxPrintf( wxT("OnExpose from ") );
499 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
500 wxPrintf( win
->GetClassInfo()->GetClassName() );
501 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
502 (int)gdk_event
->area
.y
,
503 (int)gdk_event
->area
.width
,
504 (int)gdk_event
->area
.height
);
508 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
510 gdk_event
->area
.width
,
511 gdk_event
->area
.height
);
513 // Actual redrawing takes place in idle time.
518 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
525 //-----------------------------------------------------------------------------
526 // "event" of m_wxwindow
527 //-----------------------------------------------------------------------------
529 // GTK thinks it is clever and filters out a certain amount of "unneeded"
530 // expose events. We need them, of course, so we override the main event
531 // procedure in GtkWidget by giving our own handler for all system events.
532 // There, we look for expose events ourselves whereas all other events are
535 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
536 GdkEventExpose
*event
,
539 if (event
->type
== GDK_EXPOSE
)
541 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
548 //-----------------------------------------------------------------------------
549 // "draw" of m_wxwindow
550 //-----------------------------------------------------------------------------
554 // This callback is a complete replacement of the gtk_pizza_draw() function,
555 // which is disabled.
557 static void gtk_window_draw_callback( GtkWidget
*widget
,
564 wxapp_install_idle_handler();
566 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
567 // there are no child windows.
568 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
569 (win
->GetChildren().GetCount() == 0))
577 wxPrintf( wxT("OnDraw from ") );
578 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
579 wxPrintf( win
->GetClassInfo()->GetClassName() );
580 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
587 #ifndef __WXUNIVERSAL__
588 GtkPizza
*pizza
= GTK_PIZZA (widget
);
590 if (win
->GetThemeEnabled())
592 wxWindow
*parent
= win
->GetParent();
593 while (parent
&& !parent
->IsTopLevel())
594 parent
= parent
->GetParent();
598 gtk_paint_flat_box (parent
->m_widget
->style
,
609 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
610 (pizza
->clear_on_draw
))
612 gdk_window_clear_area( pizza
->bin_window
,
613 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
617 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
619 // Actual redrawing takes place in idle time.
623 #ifndef __WXUNIVERSAL__
624 // Redraw child widgets
625 GList
*children
= pizza
->children
;
628 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
629 children
= children
->next
;
631 GdkRectangle child_area
;
632 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
634 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
642 //-----------------------------------------------------------------------------
643 // "key_press_event" from any window
644 //-----------------------------------------------------------------------------
646 // set WXTRACE to this to see the key event codes on the console
647 #define TRACE_KEYS _T("keyevent")
649 // translates an X key symbol to WXK_XXX value
651 // if isChar is true it means that the value returned will be used for EVT_CHAR
652 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
653 // for example, while if it is false it means that the value is going to be
654 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
656 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
662 // Shift, Control and Alt don't generate the CHAR events at all
665 key_code
= isChar
? 0 : WXK_SHIFT
;
669 key_code
= isChar
? 0 : WXK_CONTROL
;
677 key_code
= isChar
? 0 : WXK_ALT
;
680 // neither do the toggle modifies
681 case GDK_Scroll_Lock
:
682 key_code
= isChar
? 0 : WXK_SCROLL
;
686 key_code
= isChar
? 0 : WXK_CAPITAL
;
690 key_code
= isChar
? 0 : WXK_NUMLOCK
;
694 // various other special keys
707 case GDK_ISO_Left_Tab
:
714 key_code
= WXK_RETURN
;
718 key_code
= WXK_CLEAR
;
722 key_code
= WXK_PAUSE
;
726 key_code
= WXK_SELECT
;
730 key_code
= WXK_PRINT
;
734 key_code
= WXK_EXECUTE
;
738 key_code
= WXK_ESCAPE
;
741 // cursor and other extended keyboard keys
743 key_code
= WXK_DELETE
;
759 key_code
= WXK_RIGHT
;
766 case GDK_Prior
: // == GDK_Page_Up
767 key_code
= WXK_PRIOR
;
770 case GDK_Next
: // == GDK_Page_Down
783 key_code
= WXK_INSERT
;
798 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
802 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
806 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
810 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
814 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
818 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
822 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
826 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
830 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
834 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
838 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
842 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
846 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
849 case GDK_KP_Prior
: // == GDK_KP_Page_Up
850 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
853 case GDK_KP_Next
: // == GDK_KP_Page_Down
854 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
858 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
862 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
866 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
870 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
874 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
877 case GDK_KP_Multiply
:
878 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
882 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
885 case GDK_KP_Separator
:
886 // FIXME: what is this?
887 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
890 case GDK_KP_Subtract
:
891 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
895 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
899 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
916 key_code
= WXK_F1
+ keysym
- GDK_F1
;
926 static inline bool wxIsAsciiKeysym(KeySym ks
)
932 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
934 GdkEventKey
*gdk_event
)
936 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
937 // but only event->keyval which is quite useless to us, so remember
938 // the last character from GDK_KEY_PRESS and reuse it as last resort
940 // NB: should be MT-safe as we're always called from the main thread only
945 } s_lastKeyPress
= { 0, 0 };
947 KeySym keysym
= gdk_event
->keyval
;
949 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %d"),
950 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
954 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
958 // do we have the translation or is it a plain ASCII character?
959 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
961 // we should use keysym if it is ASCII as X does some translations
962 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
963 // which we don't want here (but which we do use for OnChar())
964 if ( !wxIsAsciiKeysym(keysym
) )
966 keysym
= (KeySym
)gdk_event
->string
[0];
969 // we want to always get the same key code when the same key is
970 // pressed regardless of the state of the modifies, i.e. on a
971 // standard US keyboard pressing '5' or '%' ('5' key with
972 // Shift) should result in the same key code in OnKeyDown():
973 // '5' (although OnChar() will get either '5' or '%').
975 // to do it we first translate keysym to keycode (== scan code)
976 // and then back but always using the lower register
977 Display
*dpy
= (Display
*)wxGetDisplay();
978 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
980 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
982 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
984 // use the normalized, i.e. lower register, keysym if we've
986 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
988 // as explained above, we want to have lower register key codes
989 // normally but for the letter keys we want to have the upper ones
991 // NB: don't use XConvertCase() here, we want to do it for letters
993 key_code
= toupper(key_code
);
995 else // non ASCII key, what to do?
997 // by default, ignore it
1000 // but if we have cached information from the last KEY_PRESS
1001 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1004 if ( keysym
== s_lastKeyPress
.keysym
)
1006 key_code
= s_lastKeyPress
.keycode
;
1011 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1013 // remember it to be reused for KEY_UP event later
1014 s_lastKeyPress
.keysym
= keysym
;
1015 s_lastKeyPress
.keycode
= key_code
;
1019 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %d"), key_code
);
1021 // sending unknown key events doesn't really make sense
1025 // now fill all the other fields
1028 GdkModifierType state
;
1029 if (gdk_event
->window
)
1030 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1032 event
.SetTimestamp( gdk_event
->time
);
1033 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1034 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1035 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1036 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1037 event
.m_keyCode
= key_code
;
1038 event
.m_scanCode
= gdk_event
->keyval
;
1039 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1040 event
.m_rawFlags
= 0;
1043 event
.SetEventObject( win
);
1048 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1049 GdkEventKey
*gdk_event
,
1055 wxapp_install_idle_handler();
1059 if (g_blockEventsOnDrag
)
1062 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1063 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1065 // unknown key pressed, ignore (the event would be useless anyhow)
1069 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1074 wxWindowGTK
*ancestor
= win
;
1077 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1080 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1081 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1084 if (ancestor
->IsTopLevel())
1086 ancestor
= ancestor
->GetParent();
1089 #endif // wxUSE_ACCEL
1091 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1092 will only be sent if it is not in an accelerator table. */
1095 KeySym keysym
= gdk_event
->keyval
;
1096 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1099 if ( gdk_event
->length
== 1 )
1101 key_code
= (unsigned char)gdk_event
->string
[0];
1103 else if ( wxIsAsciiKeysym(keysym
) )
1106 key_code
= (unsigned char)keysym
;
1112 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1114 // reuse the same event object, just change its type and use the
1115 // translated keycode instead of the raw one
1116 event
.SetEventType(wxEVT_CHAR
);
1117 event
.m_keyCode
= key_code
;
1119 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1123 /* win is a control: tab can be propagated up */
1125 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1126 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1127 // have this style, yet choose not to process this particular TAB in which
1128 // case TAB must still work as a navigational character
1130 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1132 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1134 wxNavigationKeyEvent new_event
;
1135 new_event
.SetEventObject( win
->GetParent() );
1136 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1137 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1138 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1139 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1140 new_event
.SetCurrentFocus( win
);
1141 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1144 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1146 (gdk_event
->keyval
== GDK_Escape
) )
1148 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1149 new_event
.SetEventObject( win
);
1150 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1154 #if 0 // (GTK_MINOR_VERSION > 0)
1155 /* Pressing F10 will activate the menu bar of the top frame. */
1157 (gdk_event
->keyval
== GDK_F10
) )
1159 wxWindowGTK
*ancestor
= win
;
1162 if (wxIsKindOf(ancestor
,wxFrame
))
1164 wxFrame
*frame
= (wxFrame
*) ancestor
;
1165 wxMenuBar
*menubar
= frame
->GetMenuBar();
1168 wxNode
*node
= menubar
->GetMenus().First();
1171 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1172 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1178 ancestor
= ancestor
->GetParent();
1185 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1192 //-----------------------------------------------------------------------------
1193 // "key_release_event" from any window
1194 //-----------------------------------------------------------------------------
1196 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1197 GdkEventKey
*gdk_event
,
1203 wxapp_install_idle_handler();
1208 if (g_blockEventsOnDrag
)
1211 wxKeyEvent
event( wxEVT_KEY_UP
);
1212 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1214 // unknown key pressed, ignore (the event would be useless anyhow
1218 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1221 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1225 // ============================================================================
1227 // ============================================================================
1229 // init wxMouseEvent with the info from gdk_event
1230 #define InitMouseEvent(win, event, gdk_event) \
1232 event.SetTimestamp( gdk_event->time ); \
1233 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1234 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1235 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1236 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1237 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1238 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1239 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1241 wxPoint pt = win->GetClientAreaOrigin(); \
1242 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1243 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1246 // ----------------------------------------------------------------------------
1247 // mouse event processing helper
1248 // ----------------------------------------------------------------------------
1250 static void AdjustEventButtonState(wxMouseEvent
& event
)
1252 // GDK reports the old state of the button for a button press event, but
1253 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1254 // for a LEFT_DOWN event, not FALSE, so we will invert
1255 // left/right/middleDown for the corresponding click events
1257 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1258 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1259 (event
.GetEventType() == wxEVT_LEFT_UP
))
1261 event
.m_leftDown
= !event
.m_leftDown
;
1265 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1266 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1267 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1269 event
.m_middleDown
= !event
.m_middleDown
;
1273 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1274 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1275 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1277 event
.m_rightDown
= !event
.m_rightDown
;
1282 //-----------------------------------------------------------------------------
1283 // "button_press_event"
1284 //-----------------------------------------------------------------------------
1286 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1291 wxapp_install_idle_handler();
1294 wxPrintf( wxT("1) OnButtonPress from ") );
1295 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1296 wxPrintf( win->GetClassInfo()->GetClassName() );
1297 wxPrintf( wxT(".\n") );
1299 if (!win
->m_hasVMT
) return FALSE
;
1300 if (g_blockEventsOnDrag
) return TRUE
;
1301 if (g_blockEventsOnScroll
) return TRUE
;
1303 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1305 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1307 gtk_widget_grab_focus( win
->m_wxwindow
);
1309 wxPrintf( wxT("GrabFocus from ") );
1310 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1311 wxPrintf( win->GetClassInfo()->GetClassName() );
1312 wxPrintf( wxT(".\n") );
1316 wxEventType event_type
= wxEVT_NULL
;
1318 if (gdk_event
->button
== 1)
1320 switch (gdk_event
->type
)
1322 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1323 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1327 else if (gdk_event
->button
== 2)
1329 switch (gdk_event
->type
)
1331 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1332 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1336 else if (gdk_event
->button
== 3)
1338 switch (gdk_event
->type
)
1340 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1341 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1346 if ( event_type
== wxEVT_NULL
)
1348 // unknown mouse button or click type
1352 wxMouseEvent
event( event_type
);
1353 InitMouseEvent( win
, event
, gdk_event
);
1355 AdjustEventButtonState(event
);
1357 // wxListBox actually get mouse events from the item
1359 if (win
->m_isListBox
)
1361 event
.m_x
+= widget
->allocation
.x
;
1362 event
.m_y
+= widget
->allocation
.y
;
1365 // Some control don't have their own X window and thus cannot get
1368 if (!g_captureWindow
)
1370 wxCoord x
= event
.m_x
;
1371 wxCoord y
= event
.m_y
;
1372 if (win
->m_wxwindow
)
1374 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1375 x
+= pizza
->xoffset
;
1376 y
+= pizza
->yoffset
;
1379 wxNode
*node
= win
->GetChildren().First();
1382 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1384 node
= node
->Next();
1385 if (!child
->IsShown())
1388 if (child
->m_isStaticBox
)
1390 // wxStaticBox is transparent in the box itself
1391 int xx1
= child
->m_x
;
1392 int yy1
= child
->m_y
;
1393 int xx2
= child
->m_x
+ child
->m_width
;
1394 int yy2
= child
->m_x
+ child
->m_height
;
1397 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1399 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1401 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1403 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1406 event
.m_x
-= child
->m_x
;
1407 event
.m_y
-= child
->m_y
;
1414 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1415 (child
->m_x
<= x
) &&
1416 (child
->m_y
<= y
) &&
1417 (child
->m_x
+child
->m_width
>= x
) &&
1418 (child
->m_y
+child
->m_height
>= y
))
1421 event
.m_x
-= child
->m_x
;
1422 event
.m_y
-= child
->m_y
;
1429 event
.SetEventObject( win
);
1431 gs_timeLastClick
= gdk_event
->time
;
1434 wxPrintf( wxT("2) OnButtonPress from ") );
1435 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1436 wxPrintf( win->GetClassInfo()->GetClassName() );
1437 wxPrintf( wxT(".\n") );
1440 if (win
->GetEventHandler()->ProcessEvent( event
))
1442 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1449 //-----------------------------------------------------------------------------
1450 // "button_release_event"
1451 //-----------------------------------------------------------------------------
1453 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1458 wxapp_install_idle_handler();
1460 if (!win
->m_hasVMT
) return FALSE
;
1461 if (g_blockEventsOnDrag
) return FALSE
;
1462 if (g_blockEventsOnScroll
) return FALSE
;
1464 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1467 printf( "OnButtonRelease from " );
1468 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1469 printf( win->GetClassInfo()->GetClassName() );
1473 wxEventType event_type
= wxEVT_NULL
;
1475 switch (gdk_event
->button
)
1477 case 1: event_type
= wxEVT_LEFT_UP
; break;
1478 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1479 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1480 default: return FALSE
;
1483 wxMouseEvent
event( event_type
);
1484 InitMouseEvent( win
, event
, gdk_event
);
1486 AdjustEventButtonState(event
);
1488 // wxListBox actually get mouse events from the item
1490 if (win
->m_isListBox
)
1492 event
.m_x
+= widget
->allocation
.x
;
1493 event
.m_y
+= widget
->allocation
.y
;
1496 // Some control don't have their own X window and thus cannot get
1499 if (!g_captureWindow
)
1501 wxCoord x
= event
.m_x
;
1502 wxCoord y
= event
.m_y
;
1503 if (win
->m_wxwindow
)
1505 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1506 x
+= pizza
->xoffset
;
1507 y
+= pizza
->yoffset
;
1510 wxNode
*node
= win
->GetChildren().First();
1513 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1515 node
= node
->Next();
1516 if (!child
->IsShown())
1519 if (child
->m_isStaticBox
)
1521 // wxStaticBox is transparent in the box itself
1522 int xx1
= child
->m_x
;
1523 int yy1
= child
->m_y
;
1524 int xx2
= child
->m_x
+ child
->m_width
;
1525 int yy2
= child
->m_x
+ child
->m_height
;
1528 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1530 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1532 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1534 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1537 event
.m_x
-= child
->m_x
;
1538 event
.m_y
-= child
->m_y
;
1545 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1546 (child
->m_x
<= x
) &&
1547 (child
->m_y
<= y
) &&
1548 (child
->m_x
+child
->m_width
>= x
) &&
1549 (child
->m_y
+child
->m_height
>= y
))
1552 event
.m_x
-= child
->m_x
;
1553 event
.m_y
-= child
->m_y
;
1560 event
.SetEventObject( win
);
1562 if (win
->GetEventHandler()->ProcessEvent( event
))
1564 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1571 //-----------------------------------------------------------------------------
1572 // "motion_notify_event"
1573 //-----------------------------------------------------------------------------
1575 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1576 GdkEventMotion
*gdk_event
,
1582 wxapp_install_idle_handler();
1584 if (!win
->m_hasVMT
) return FALSE
;
1585 if (g_blockEventsOnDrag
) return FALSE
;
1586 if (g_blockEventsOnScroll
) return FALSE
;
1588 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1590 if (gdk_event
->is_hint
)
1594 GdkModifierType state
;
1595 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1601 printf( "OnMotion from " );
1602 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1603 printf( win->GetClassInfo()->GetClassName() );
1607 wxMouseEvent
event( wxEVT_MOTION
);
1608 InitMouseEvent(win
, event
, gdk_event
);
1610 if ( g_captureWindow
)
1612 // synthetize a mouse enter or leave event if needed
1613 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1614 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1615 if ( hasMouse
!= g_captureWindowHasMouse
)
1617 // the mouse changed window
1618 g_captureWindowHasMouse
= hasMouse
;
1620 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1621 : wxEVT_LEAVE_WINDOW
);
1622 InitMouseEvent(win
, event
, gdk_event
);
1623 event
.SetEventObject(win
);
1624 win
->GetEventHandler()->ProcessEvent(event
);
1629 // Some control don't have their own X window and thus cannot get
1632 wxCoord x
= event
.m_x
;
1633 wxCoord y
= event
.m_y
;
1634 if (win
->m_wxwindow
)
1636 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1637 x
+= pizza
->xoffset
;
1638 y
+= pizza
->yoffset
;
1641 wxNode
*node
= win
->GetChildren().First();
1644 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1646 node
= node
->Next();
1647 if (!child
->IsShown())
1650 if (child
->m_isStaticBox
)
1652 // wxStaticBox is transparent in the box itself
1653 int xx1
= child
->m_x
;
1654 int yy1
= child
->m_y
;
1655 int xx2
= child
->m_x
+ child
->m_width
;
1656 int yy2
= child
->m_x
+ child
->m_height
;
1659 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1661 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1663 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1665 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1668 event
.m_x
-= child
->m_x
;
1669 event
.m_y
-= child
->m_y
;
1676 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1677 (child
->m_x
<= x
) &&
1678 (child
->m_y
<= y
) &&
1679 (child
->m_x
+child
->m_width
>= x
) &&
1680 (child
->m_y
+child
->m_height
>= y
))
1683 event
.m_x
-= child
->m_x
;
1684 event
.m_y
-= child
->m_y
;
1691 event
.SetEventObject( win
);
1693 if (win
->GetEventHandler()->ProcessEvent( event
))
1695 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1702 //-----------------------------------------------------------------------------
1704 //-----------------------------------------------------------------------------
1706 // send the wxChildFocusEvent and wxFocusEvent, common code of
1707 // gtk_window_focus_in_callback() and SetFocus()
1708 static bool DoSendFocusEvents(wxWindow
*win
)
1710 // Notify the parent keeping track of focus for the kbd navigation
1711 // purposes that we got it.
1712 wxChildFocusEvent
eventChildFocus(win
);
1713 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1715 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1716 eventFocus
.SetEventObject(win
);
1718 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1721 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1722 GdkEvent
*WXUNUSED(event
),
1728 wxapp_install_idle_handler();
1730 if (!win
->m_hasVMT
) return FALSE
;
1731 if (g_blockEventsOnDrag
) return FALSE
;
1733 switch ( g_sendActivateEvent
)
1736 // we've got focus from outside, synthetize wxActivateEvent
1737 g_sendActivateEvent
= 1;
1741 // another our window just lost focus, it was already ours before
1742 // - don't send any wxActivateEvent
1743 g_sendActivateEvent
= -1;
1748 g_focusWindow
= win
;
1751 printf( "OnSetFocus 2 from %s\n", win
->GetName().c_str() );
1756 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1760 // caret needs to be informed about focus change
1761 wxCaret
*caret
= win
->GetCaret();
1764 caret
->OnSetFocus();
1766 #endif // wxUSE_CARET
1768 g_activeFrameLostFocus
= FALSE
;
1770 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1771 if ( active
!= g_activeFrame
)
1773 if ( g_activeFrame
)
1775 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1776 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1777 event
.SetEventObject(g_activeFrame
);
1778 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1781 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1782 g_activeFrame
= active
;
1783 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1784 event
.SetEventObject(g_activeFrame
);
1785 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1787 // Don't send focus events in addition to activate
1788 // if (win == g_activeFrame)
1792 if ( DoSendFocusEvents(win
) )
1794 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1801 //-----------------------------------------------------------------------------
1802 // "focus_out_event"
1803 //-----------------------------------------------------------------------------
1805 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1810 wxapp_install_idle_handler();
1812 if (!win
->m_hasVMT
) return FALSE
;
1813 if (g_blockEventsOnDrag
) return FALSE
;
1816 wxLogDebug( wxT("OnKillFocus from %s"), win
->GetName().c_str() );
1819 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1821 // VZ: commenting this out because it does happen (although not easy
1822 // to reproduce, I only see it when using wxMiniFrame and not
1823 // always) and makes using Mahogany quite annoying
1825 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1826 wxT("unfocusing window that hasn't gained focus properly") )
1829 g_activeFrameLostFocus
= TRUE
;
1832 // if the focus goes out of our app alltogether, OnIdle() will send
1833 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1834 // g_sendActivateEvent to -1
1835 g_sendActivateEvent
= 0;
1837 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1841 g_focusWindow
= (wxWindowGTK
*)NULL
;
1849 // caret needs to be informed about focus change
1850 wxCaret
*caret
= win
->GetCaret();
1853 caret
->OnKillFocus();
1855 #endif // wxUSE_CARET
1857 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1858 event
.SetEventObject( win
);
1860 if (win
->GetEventHandler()->ProcessEvent( event
))
1862 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1869 //-----------------------------------------------------------------------------
1870 // "enter_notify_event"
1871 //-----------------------------------------------------------------------------
1873 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1878 wxapp_install_idle_handler();
1880 if (!win
->m_hasVMT
) return FALSE
;
1881 if (g_blockEventsOnDrag
) return FALSE
;
1883 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1885 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1886 event
.SetTimestamp( gdk_event
->time
);
1887 event
.SetEventObject( win
);
1891 GdkModifierType state
= (GdkModifierType
)0;
1893 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1895 InitMouseEvent(win
, event
, gdk_event
);
1896 wxPoint pt
= win
->GetClientAreaOrigin();
1897 event
.m_x
= x
+ pt
.x
;
1898 event
.m_y
= y
+ pt
.y
;
1900 if (win
->GetEventHandler()->ProcessEvent( event
))
1902 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1909 //-----------------------------------------------------------------------------
1910 // "leave_notify_event"
1911 //-----------------------------------------------------------------------------
1913 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1918 wxapp_install_idle_handler();
1920 if (!win
->m_hasVMT
) return FALSE
;
1921 if (g_blockEventsOnDrag
) return FALSE
;
1923 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1925 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1926 event
.SetTimestamp( gdk_event
->time
);
1927 event
.SetEventObject( win
);
1931 GdkModifierType state
= (GdkModifierType
)0;
1933 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1935 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1936 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1937 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1938 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1939 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1940 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1941 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1943 wxPoint pt
= win
->GetClientAreaOrigin();
1944 event
.m_x
= x
+ pt
.x
;
1945 event
.m_y
= y
+ pt
.y
;
1947 if (win
->GetEventHandler()->ProcessEvent( event
))
1949 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1956 //-----------------------------------------------------------------------------
1957 // "value_changed" from m_vAdjust
1958 //-----------------------------------------------------------------------------
1960 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1967 wxapp_install_idle_handler();
1969 if (g_blockEventsOnDrag
) return;
1971 if (!win
->m_hasVMT
) return;
1973 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1974 if (fabs(diff
) < 0.2) return;
1976 win
->m_oldVerticalPos
= adjust
->value
;
1978 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1980 int value
= (int)(adjust
->value
+0.5);
1982 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1983 event
.SetEventObject( win
);
1984 win
->GetEventHandler()->ProcessEvent( event
);
1987 //-----------------------------------------------------------------------------
1988 // "value_changed" from m_hAdjust
1989 //-----------------------------------------------------------------------------
1991 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1998 wxapp_install_idle_handler();
2000 if (g_blockEventsOnDrag
) return;
2001 if (!win
->m_hasVMT
) return;
2003 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2004 if (fabs(diff
) < 0.2) return;
2006 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
2008 win
->m_oldHorizontalPos
= adjust
->value
;
2010 int value
= (int)(adjust
->value
+0.5);
2012 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2013 event
.SetEventObject( win
);
2014 win
->GetEventHandler()->ProcessEvent( event
);
2017 //-----------------------------------------------------------------------------
2018 // "button_press_event" from scrollbar
2019 //-----------------------------------------------------------------------------
2021 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2022 GdkEventButton
*gdk_event
,
2028 wxapp_install_idle_handler();
2031 g_blockEventsOnScroll
= TRUE
;
2033 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2035 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2041 //-----------------------------------------------------------------------------
2042 // "button_release_event" from scrollbar
2043 //-----------------------------------------------------------------------------
2045 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2046 GdkEventButton
*WXUNUSED(gdk_event
),
2051 // don't test here as we can release the mouse while being over
2052 // a different window than the slider
2054 // if (gdk_event->window != widget->slider) return FALSE;
2056 g_blockEventsOnScroll
= FALSE
;
2058 if (win
->m_isScrolling
)
2060 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2064 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2065 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2067 value
= (int)(win
->m_hAdjust
->value
+0.5);
2070 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2072 value
= (int)(win
->m_vAdjust
->value
+0.5);
2076 wxScrollWinEvent
event( command
, value
, dir
);
2077 event
.SetEventObject( win
);
2078 win
->GetEventHandler()->ProcessEvent( event
);
2081 win
->m_isScrolling
= FALSE
;
2086 // ----------------------------------------------------------------------------
2087 // this wxWindowBase function is implemented here (in platform-specific file)
2088 // because it is static and so couldn't be made virtual
2089 // ----------------------------------------------------------------------------
2091 wxWindow
*wxWindowBase::FindFocus()
2093 // the cast is necessary when we compile in wxUniversal mode
2094 return (wxWindow
*)g_focusWindow
;
2097 //-----------------------------------------------------------------------------
2098 // "realize" from m_widget
2099 //-----------------------------------------------------------------------------
2101 /* We cannot set colours and fonts before the widget has
2102 been realized, so we do this directly after realization. */
2105 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2110 wxapp_install_idle_handler();
2112 if (win
->m_delayedBackgroundColour
)
2113 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2115 if (win
->m_delayedForegroundColour
)
2116 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2118 wxWindowCreateEvent
event( win
);
2119 event
.SetEventObject( win
);
2120 win
->GetEventHandler()->ProcessEvent( event
);
2125 //-----------------------------------------------------------------------------
2127 //-----------------------------------------------------------------------------
2130 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2131 GtkAllocation
*WXUNUSED(alloc
),
2135 wxapp_install_idle_handler();
2137 if (!win
->m_hasScrolling
) return;
2139 int client_width
= 0;
2140 int client_height
= 0;
2141 win
->GetClientSize( &client_width
, &client_height
);
2142 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2145 win
->m_oldClientWidth
= client_width
;
2146 win
->m_oldClientHeight
= client_height
;
2148 if (!win
->m_nativeSizeEvent
)
2150 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2151 event
.SetEventObject( win
);
2152 win
->GetEventHandler()->ProcessEvent( event
);
2158 #define WXUNUSED_UNLESS_XIM(param) param
2160 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2163 /* Resize XIM window */
2166 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2167 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2168 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2171 wxapp_install_idle_handler();
2177 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2181 gdk_window_get_size (widget
->window
, &width
, &height
);
2182 win
->m_icattr
->preedit_area
.width
= width
;
2183 win
->m_icattr
->preedit_area
.height
= height
;
2184 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2189 //-----------------------------------------------------------------------------
2190 // "realize" from m_wxwindow
2191 //-----------------------------------------------------------------------------
2193 /* Initialize XIM support */
2196 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2197 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2200 wxapp_install_idle_handler();
2203 if (win
->m_ic
) return FALSE
;
2204 if (!widget
) return FALSE
;
2205 if (!gdk_im_ready()) return FALSE
;
2207 win
->m_icattr
= gdk_ic_attr_new();
2208 if (!win
->m_icattr
) return FALSE
;
2212 GdkColormap
*colormap
;
2213 GdkICAttr
*attr
= win
->m_icattr
;
2214 unsigned attrmask
= GDK_IC_ALL_REQ
;
2216 GdkIMStyle supported_style
= (GdkIMStyle
)
2217 (GDK_IM_PREEDIT_NONE
|
2218 GDK_IM_PREEDIT_NOTHING
|
2219 GDK_IM_PREEDIT_POSITION
|
2220 GDK_IM_STATUS_NONE
|
2221 GDK_IM_STATUS_NOTHING
);
2223 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2224 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2226 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2227 attr
->client_window
= widget
->window
;
2229 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2230 gtk_widget_get_default_colormap ())
2232 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2233 attr
->preedit_colormap
= colormap
;
2236 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2237 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2238 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2239 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2241 switch (style
& GDK_IM_PREEDIT_MASK
)
2243 case GDK_IM_PREEDIT_POSITION
:
2244 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2246 g_warning ("over-the-spot style requires fontset");
2250 gdk_window_get_size (widget
->window
, &width
, &height
);
2252 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2253 attr
->spot_location
.x
= 0;
2254 attr
->spot_location
.y
= height
;
2255 attr
->preedit_area
.x
= 0;
2256 attr
->preedit_area
.y
= 0;
2257 attr
->preedit_area
.width
= width
;
2258 attr
->preedit_area
.height
= height
;
2259 attr
->preedit_fontset
= widget
->style
->font
;
2264 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2266 if (win
->m_ic
== NULL
)
2267 g_warning ("Can't create input context.");
2270 mask
= gdk_window_get_events (widget
->window
);
2271 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2272 gdk_window_set_events (widget
->window
, mask
);
2274 if (GTK_WIDGET_HAS_FOCUS(widget
))
2275 gdk_im_begin (win
->m_ic
, widget
->window
);
2282 //-----------------------------------------------------------------------------
2283 // InsertChild for wxWindowGTK.
2284 //-----------------------------------------------------------------------------
2286 /* Callback for wxWindowGTK. This very strange beast has to be used because
2287 * C++ has no virtual methods in a constructor. We have to emulate a
2288 * virtual function here as wxNotebook requires a different way to insert
2289 * a child in it. I had opted for creating a wxNotebookPage window class
2290 * which would have made this superfluous (such in the MDI window system),
2291 * but no-one was listening to me... */
2293 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2295 /* the window might have been scrolled already, do we
2296 have to adapt the position */
2297 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2298 child
->m_x
+= pizza
->xoffset
;
2299 child
->m_y
+= pizza
->yoffset
;
2301 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2302 GTK_WIDGET(child
->m_widget
),
2309 //-----------------------------------------------------------------------------
2311 //-----------------------------------------------------------------------------
2313 wxWindow
*wxGetActiveWindow()
2315 // the cast is necessary when we compile in wxUniversal mode
2316 return (wxWindow
*)g_focusWindow
;
2319 //-----------------------------------------------------------------------------
2321 //-----------------------------------------------------------------------------
2323 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2325 #ifdef __WXUNIVERSAL__
2326 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2328 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2329 #endif // __WXUNIVERSAL__/__WXGTK__
2331 void wxWindowGTK::Init()
2337 m_widget
= (GtkWidget
*) NULL
;
2338 m_wxwindow
= (GtkWidget
*) NULL
;
2339 m_focusWidget
= (GtkWidget
*) NULL
;
2349 m_needParent
= TRUE
;
2350 m_isBeingDeleted
= FALSE
;
2353 m_nativeSizeEvent
= FALSE
;
2355 m_hasScrolling
= FALSE
;
2356 m_isScrolling
= FALSE
;
2358 m_hAdjust
= (GtkAdjustment
*) NULL
;
2359 m_vAdjust
= (GtkAdjustment
*) NULL
;
2360 m_oldHorizontalPos
= 0.0;
2361 m_oldVerticalPos
= 0.0;
2364 m_widgetStyle
= (GtkStyle
*) NULL
;
2366 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2368 m_isStaticBox
= FALSE
;
2369 m_isRadioButton
= FALSE
;
2370 m_isListBox
= FALSE
;
2372 m_acceptsFocus
= FALSE
;
2374 m_clipPaintRegion
= FALSE
;
2376 m_cursor
= *wxSTANDARD_CURSOR
;
2378 m_delayedForegroundColour
= FALSE
;
2379 m_delayedBackgroundColour
= FALSE
;
2382 m_ic
= (GdkIC
*) NULL
;
2383 m_icattr
= (GdkICAttr
*) NULL
;
2387 wxWindowGTK::wxWindowGTK()
2392 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2397 const wxString
&name
)
2401 Create( parent
, id
, pos
, size
, style
, name
);
2404 bool wxWindowGTK::Create( wxWindow
*parent
,
2409 const wxString
&name
)
2411 if (!PreCreation( parent
, pos
, size
) ||
2412 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2414 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2418 m_insertCallback
= wxInsertChildInWindow
;
2420 // always needed for background clearing
2421 m_delayedBackgroundColour
= TRUE
;
2423 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2424 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2426 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2428 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2429 scroll_class
->scrollbar_spacing
= 0;
2431 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2433 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2434 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2436 m_wxwindow
= gtk_pizza_new();
2438 #ifndef __WXUNIVERSAL__
2439 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2441 if (HasFlag(wxRAISED_BORDER
))
2443 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2445 else if (HasFlag(wxSUNKEN_BORDER
))
2447 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2449 else if (HasFlag(wxSIMPLE_BORDER
))
2451 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2455 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2457 #endif // __WXUNIVERSAL__
2459 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2461 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2462 m_acceptsFocus
= TRUE
;
2464 // I _really_ don't want scrollbars in the beginning
2465 m_vAdjust
->lower
= 0.0;
2466 m_vAdjust
->upper
= 1.0;
2467 m_vAdjust
->value
= 0.0;
2468 m_vAdjust
->step_increment
= 1.0;
2469 m_vAdjust
->page_increment
= 1.0;
2470 m_vAdjust
->page_size
= 5.0;
2471 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2472 m_hAdjust
->lower
= 0.0;
2473 m_hAdjust
->upper
= 1.0;
2474 m_hAdjust
->value
= 0.0;
2475 m_hAdjust
->step_increment
= 1.0;
2476 m_hAdjust
->page_increment
= 1.0;
2477 m_hAdjust
->page_size
= 5.0;
2478 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2480 // these handlers block mouse events to any window during scrolling such as
2481 // motion events and prevent GTK and wxWindows from fighting over where the
2484 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2485 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2487 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2488 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2490 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2491 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2493 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2494 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2496 // these handlers get notified when screen updates are required either when
2497 // scrolling or when the window size (and therefore scrollbar configuration)
2500 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2501 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2502 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2503 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2505 gtk_widget_show( m_wxwindow
);
2508 m_parent
->DoAddChild( this );
2510 m_focusWidget
= m_wxwindow
;
2519 wxWindowGTK::~wxWindowGTK()
2521 if (g_focusWindow
== this)
2522 g_focusWindow
= NULL
;
2524 if (g_activeFrame
== this)
2525 g_activeFrame
= NULL
;
2527 m_isBeingDeleted
= TRUE
;
2536 m_parent
->RemoveChild( this );
2540 gdk_ic_destroy (m_ic
);
2542 gdk_ic_attr_destroy (m_icattr
);
2547 #if DISABLE_STYLE_IF_BROKEN_THEME
2548 // don't delete if it's a pixmap theme style
2549 if (!m_widgetStyle
->engine_data
)
2550 gtk_style_unref( m_widgetStyle
);
2552 m_widgetStyle
= (GtkStyle
*) NULL
;
2557 gtk_widget_destroy( m_wxwindow
);
2558 m_wxwindow
= (GtkWidget
*) NULL
;
2563 gtk_widget_destroy( m_widget
);
2564 m_widget
= (GtkWidget
*) NULL
;
2568 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2570 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2572 /* this turns -1 into 20 so that a minimal window is
2573 visible even although -1,-1 has been given as the
2574 size of the window. the same trick is used in other
2575 ports and should make debugging easier */
2576 m_width
= WidthDefault(size
.x
);
2577 m_height
= HeightDefault(size
.y
);
2582 /* some reasonable defaults */
2587 m_x
= (gdk_screen_width () - m_width
) / 2;
2588 if (m_x
< 10) m_x
= 10;
2592 m_y
= (gdk_screen_height () - m_height
) / 2;
2593 if (m_y
< 10) m_y
= 10;
2600 void wxWindowGTK::PostCreation()
2602 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2608 // these get reported to wxWindows -> wxPaintEvent
2610 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2612 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2613 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2616 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2617 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2619 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2621 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2622 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2625 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2629 // these are called when the "sunken" or "raised" borders are drawn
2630 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2631 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2634 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2635 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2641 if (m_focusWidget
== NULL
)
2642 m_focusWidget
= m_widget
;
2644 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2645 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2647 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2648 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2650 // connect to the various key and mouse handlers
2652 GtkWidget
*connect_widget
= GetConnectWidget();
2654 ConnectWidget( connect_widget
);
2656 /* We cannot set colours, fonts and cursors before the widget has
2657 been realized, so we do this directly after realization */
2658 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2659 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2663 // Catch native resize events
2664 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2665 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2667 // Initialize XIM support
2668 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2669 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2671 // And resize XIM window
2672 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2673 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2676 if (!GTK_IS_COMBO(m_widget
))
2678 // This is needed if we want to add our windows into native
2679 // GTK control, such as the toolbar. With this callback, the
2680 // toolbar gets to know the correct size (the one set by the
2681 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2682 // when moving to GTK 2.0.
2683 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2684 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2690 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2692 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2693 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2695 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2696 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2698 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2699 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2701 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2702 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2704 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2705 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2707 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2708 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2710 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2711 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2714 bool wxWindowGTK::Destroy()
2716 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2720 return wxWindowBase::Destroy();
2723 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2725 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2728 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2730 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2731 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2734 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2737 if (m_resizing
) return; /* I don't like recursions */
2740 int currentX
, currentY
;
2741 GetPosition(¤tX
, ¤tY
);
2746 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2748 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2750 /* don't set the size for children of wxNotebook, just take the values. */
2758 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2759 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2761 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2762 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2763 if (width
!= -1) m_width
= width
;
2764 if (height
!= -1) m_height
= height
;
2768 m_x
= x
+ pizza
->xoffset
;
2769 m_y
= y
+ pizza
->yoffset
;
2774 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2776 if (width
== -1) m_width
= 80;
2779 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2781 if (height
== -1) m_height
= 26;
2784 int minWidth
= GetMinWidth(),
2785 minHeight
= GetMinHeight(),
2786 maxWidth
= GetMaxWidth(),
2787 maxHeight
= GetMaxHeight();
2789 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2790 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2791 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2792 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2795 int bottom_border
= 0;
2798 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2800 /* the default button has a border around it */
2806 DoMoveWindow( m_x
-border
,
2809 m_height
+border
+bottom_border
);
2814 /* Sometimes the client area changes size without the
2815 whole windows's size changing, but if the whole
2816 windows's size doesn't change, no wxSizeEvent will
2817 normally be sent. Here we add an extra test if
2818 the client test has been changed and this will
2820 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2824 wxPrintf( "OnSize sent from " );
2825 if (GetClassInfo() && GetClassInfo()->GetClassName())
2826 wxPrintf( GetClassInfo()->GetClassName() );
2827 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2830 if (!m_nativeSizeEvent
)
2832 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2833 event
.SetEventObject( this );
2834 GetEventHandler()->ProcessEvent( event
);
2840 void wxWindowGTK::OnInternalIdle()
2842 // Update invalidated regions.
2845 // Synthetize activate events.
2846 if ( g_sendActivateEvent
!= -1 )
2848 bool activate
= g_sendActivateEvent
!= 0;
2851 g_sendActivateEvent
= -1;
2853 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2856 if ( g_activeFrameLostFocus
)
2858 if ( g_activeFrame
)
2860 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2861 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2862 event
.SetEventObject(g_activeFrame
);
2863 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2864 g_activeFrame
= NULL
;
2866 g_activeFrameLostFocus
= FALSE
;
2869 wxCursor cursor
= m_cursor
;
2870 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2874 /* I now set the cursor anew in every OnInternalIdle call
2875 as setting the cursor in a parent window also effects the
2876 windows above so that checking for the current cursor is
2881 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2883 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2885 if (!g_globalCursor
.Ok())
2886 cursor
= *wxSTANDARD_CURSOR
;
2888 window
= m_widget
->window
;
2889 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2890 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2896 GdkWindow
*window
= m_widget
->window
;
2897 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2898 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2906 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2908 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2910 if (width
) (*width
) = m_width
;
2911 if (height
) (*height
) = m_height
;
2914 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2916 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2920 SetSize( width
, height
);
2927 #ifndef __WXUNIVERSAL__
2928 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2930 /* when using GTK 1.2 we set the shadow border size to 2 */
2934 if (HasFlag(wxSIMPLE_BORDER
))
2936 /* when using GTK 1.2 we set the simple border size to 1 */
2940 #endif // __WXUNIVERSAL__
2944 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2946 GtkRequisition vscroll_req
;
2947 vscroll_req
.width
= 2;
2948 vscroll_req
.height
= 2;
2949 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2950 (scroll_window
->vscrollbar
, &vscroll_req
);
2952 GtkRequisition hscroll_req
;
2953 hscroll_req
.width
= 2;
2954 hscroll_req
.height
= 2;
2955 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2956 (scroll_window
->hscrollbar
, &hscroll_req
);
2958 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2960 if (scroll_window
->vscrollbar_visible
)
2962 dw
+= vscroll_req
.width
;
2963 dw
+= scroll_class
->scrollbar_spacing
;
2966 if (scroll_window
->hscrollbar_visible
)
2968 dh
+= hscroll_req
.height
;
2969 dh
+= scroll_class
->scrollbar_spacing
;
2973 SetSize( width
+dw
, height
+dh
);
2977 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2979 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2983 if (width
) (*width
) = m_width
;
2984 if (height
) (*height
) = m_height
;
2991 #ifndef __WXUNIVERSAL__
2992 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2994 /* when using GTK 1.2 we set the shadow border size to 2 */
2998 if (HasFlag(wxSIMPLE_BORDER
))
3000 /* when using GTK 1.2 we set the simple border size to 1 */
3004 #endif // __WXUNIVERSAL__
3008 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3010 GtkRequisition vscroll_req
;
3011 vscroll_req
.width
= 2;
3012 vscroll_req
.height
= 2;
3013 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3014 (scroll_window
->vscrollbar
, &vscroll_req
);
3016 GtkRequisition hscroll_req
;
3017 hscroll_req
.width
= 2;
3018 hscroll_req
.height
= 2;
3019 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3020 (scroll_window
->hscrollbar
, &hscroll_req
);
3022 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3024 if (scroll_window
->vscrollbar_visible
)
3026 dw
+= vscroll_req
.width
;
3027 dw
+= scroll_class
->scrollbar_spacing
;
3030 if (scroll_window
->hscrollbar_visible
)
3032 dh
+= hscroll_req
.height
;
3033 dh
+= scroll_class
->scrollbar_spacing
;
3037 if (width
) (*width
) = m_width
- dw
;
3038 if (height
) (*height
) = m_height
- dh
;
3042 printf( "GetClientSize, name %s ", GetName().c_str() );
3043 if (width) printf( " width = %d", (*width) );
3044 if (height) printf( " height = %d", (*height) );
3049 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3051 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3055 if (m_parent
&& m_parent
->m_wxwindow
)
3057 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3058 dx
= pizza
->xoffset
;
3059 dy
= pizza
->yoffset
;
3062 if (x
) (*x
) = m_x
- dx
;
3063 if (y
) (*y
) = m_y
- dy
;
3066 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3068 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3070 if (!m_widget
->window
) return;
3072 GdkWindow
*source
= (GdkWindow
*) NULL
;
3074 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3076 source
= m_widget
->window
;
3080 gdk_window_get_origin( source
, &org_x
, &org_y
);
3084 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3086 org_x
+= m_widget
->allocation
.x
;
3087 org_y
+= m_widget
->allocation
.y
;
3095 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3097 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3099 if (!m_widget
->window
) return;
3101 GdkWindow
*source
= (GdkWindow
*) NULL
;
3103 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3105 source
= m_widget
->window
;
3109 gdk_window_get_origin( source
, &org_x
, &org_y
);
3113 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3115 org_x
+= m_widget
->allocation
.x
;
3116 org_y
+= m_widget
->allocation
.y
;
3124 bool wxWindowGTK::Show( bool show
)
3126 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3128 if (!wxWindowBase::Show(show
))
3135 gtk_widget_show( m_widget
);
3137 gtk_widget_hide( m_widget
);
3142 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3144 win
->OnParentEnable(enable
);
3146 // Recurse, so that children have the opportunity to Do The Right Thing
3147 // and reset colours that have been messed up by a parent's (really ancestor's)
3149 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3151 node
= node
->GetNext() )
3153 wxWindow
*child
= node
->GetData();
3154 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3155 wxWindowNotifyEnable(child
, enable
);
3159 bool wxWindowGTK::Enable( bool enable
)
3161 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3163 if (!wxWindowBase::Enable(enable
))
3169 gtk_widget_set_sensitive( m_widget
, enable
);
3171 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3173 wxWindowNotifyEnable(this, enable
);
3178 int wxWindowGTK::GetCharHeight() const
3180 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3182 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3184 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3186 return font
->ascent
+ font
->descent
;
3189 int wxWindowGTK::GetCharWidth() const
3191 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3193 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3195 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3197 return gdk_string_width( font
, "H" );
3200 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3204 int *externalLeading
,
3205 const wxFont
*theFont
) const
3207 wxFont fontToUse
= m_font
;
3208 if (theFont
) fontToUse
= *theFont
;
3210 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3212 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3213 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3214 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3215 if (descent
) (*descent
) = font
->descent
;
3216 if (externalLeading
) (*externalLeading
) = 0; // ??
3219 void wxWindowGTK::SetFocus()
3221 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3225 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3227 gtk_widget_grab_focus (m_wxwindow
);
3232 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3234 if (!GTK_WIDGET_REALIZED(m_widget
))
3236 wxLogTrace(_T("focus"),
3237 _T("Delaying setting focus to %s(%s)\n"),
3238 GetClassInfo()->GetClassName(), GetLabel().c_str());
3240 g_delayedFocus
= this;
3244 wxLogTrace(_T("focus"),
3245 _T("Setting focus to %s(%s)\n"),
3246 GetClassInfo()->GetClassName(), GetLabel().c_str());
3248 gtk_widget_grab_focus (m_widget
);
3251 else if (GTK_IS_CONTAINER(m_widget
))
3253 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3261 (void)DoSendFocusEvents(this);
3264 bool wxWindowGTK::AcceptsFocus() const
3266 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3269 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3271 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3273 wxWindowGTK
*oldParent
= m_parent
,
3274 *newParent
= (wxWindowGTK
*)newParentBase
;
3276 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3278 if ( !wxWindowBase::Reparent(newParent
) )
3281 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3283 /* prevent GTK from deleting the widget arbitrarily */
3284 gtk_widget_ref( m_widget
);
3288 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3291 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3295 /* insert GTK representation */
3296 (*(newParent
->m_insertCallback
))(newParent
, this);
3299 /* reverse: prevent GTK from deleting the widget arbitrarily */
3300 gtk_widget_unref( m_widget
);
3305 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3307 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3309 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3311 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3316 /* insert GTK representation */
3317 (*m_insertCallback
)(this, child
);
3320 void wxWindowGTK::Raise()
3322 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3324 if (!m_widget
->window
) return;
3326 gdk_window_raise( m_widget
->window
);
3329 void wxWindowGTK::Lower()
3331 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3333 if (!m_widget
->window
) return;
3335 gdk_window_lower( m_widget
->window
);
3338 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3340 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3342 if (cursor
== m_cursor
)
3346 wxapp_install_idle_handler();
3348 if (cursor
== wxNullCursor
)
3349 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3351 return wxWindowBase::SetCursor( cursor
);
3354 void wxWindowGTK::WarpPointer( int x
, int y
)
3356 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3358 // We provide this function ourselves as it is
3359 // missing in GDK (top of this file).
3361 GdkWindow
*window
= (GdkWindow
*) NULL
;
3363 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3365 window
= GetConnectWidget()->window
;
3368 gdk_window_warp_pointer( window
, x
, y
);
3371 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3373 if (!m_widget
) return;
3374 if (!m_widget
->window
) return;
3378 wxapp_install_idle_handler();
3380 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3384 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3385 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3389 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3390 m_clearRegion
.Clear();
3391 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3399 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3400 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3404 GdkRectangle gdk_rect
;
3405 gdk_rect
.x
= rect
->x
;
3406 gdk_rect
.y
= rect
->y
;
3407 gdk_rect
.width
= rect
->width
;
3408 gdk_rect
.height
= rect
->height
;
3409 gtk_widget_draw( m_widget
, &gdk_rect
);
3416 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3417 m_updateRegion
.Clear();
3418 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3422 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3430 GdkRectangle gdk_rect
;
3431 gdk_rect
.x
= rect
->x
;
3432 gdk_rect
.y
= rect
->y
;
3433 gdk_rect
.width
= rect
->width
;
3434 gdk_rect
.height
= rect
->height
;
3435 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3439 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3445 void wxWindowGTK::Update()
3450 void wxWindowGTK::GtkUpdate()
3453 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3454 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3457 if (!m_updateRegion
.IsEmpty())
3458 GtkSendPaintEvents();
3461 void wxWindowGTK::GtkSendPaintEvents()
3465 m_clearRegion
.Clear();
3466 m_updateRegion
.Clear();
3470 m_clipPaintRegion
= TRUE
;
3472 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3474 wxWindowDC
dc( (wxWindow
*)this );
3475 dc
.SetClippingRegion( m_clearRegion
);
3477 wxEraseEvent
erase_event( GetId(), &dc
);
3478 erase_event
.SetEventObject( this );
3480 if (!GetEventHandler()->ProcessEvent(erase_event
))
3484 g_eraseGC
= gdk_gc_new( GTK_PIZZA(m_wxwindow
)->bin_window
);
3485 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3487 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3489 // widget to draw on
3490 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3492 // find ancestor from which to steal background
3493 wxWindow
*parent
= GetParent();
3494 while (parent
&& !parent
->IsTopLevel())
3495 parent
= parent
->GetParent();
3499 wxRegionIterator
upd( m_clearRegion
);
3502 if (GetThemeEnabled())
3505 rect
.x
= upd
.GetX();
3506 rect
.y
= upd
.GetY();
3507 rect
.width
= upd
.GetWidth();
3508 rect
.height
= upd
.GetHeight();
3510 gtk_paint_flat_box( parent
->m_widget
->style
,
3521 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3522 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3527 m_clearRegion
.Clear();
3530 wxNcPaintEvent
nc_paint_event( GetId() );
3531 nc_paint_event
.SetEventObject( this );
3532 GetEventHandler()->ProcessEvent( nc_paint_event
);
3534 wxPaintEvent
paint_event( GetId() );
3535 paint_event
.SetEventObject( this );
3536 GetEventHandler()->ProcessEvent( paint_event
);
3538 m_clipPaintRegion
= FALSE
;
3540 #ifndef __WXUNIVERSAL__
3542 // The following code will result in all window-less widgets
3543 // being redrawn because the wxWindows class is allowed to
3544 // paint over the window-less widgets.
3546 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3548 GList
*children
= pizza
->children
;
3551 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3552 children
= children
->next
;
3554 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3555 GTK_WIDGET_DRAWABLE (child
->widget
))
3557 // Get intersection of widget area and update region
3558 wxRegion
region( m_updateRegion
);
3560 GdkEventExpose gdk_event
;
3561 gdk_event
.type
= GDK_EXPOSE
;
3562 gdk_event
.window
= pizza
->bin_window
;
3563 gdk_event
.count
= 0;
3565 wxRegionIterator
upd( m_updateRegion
);
3569 rect
.x
= upd
.GetX();
3570 rect
.y
= upd
.GetY();
3571 rect
.width
= upd
.GetWidth();
3572 rect
.height
= upd
.GetHeight();
3574 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3576 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3586 m_updateRegion
.Clear();
3589 void wxWindowGTK::Clear()
3591 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3593 if (m_wxwindow
&& m_wxwindow
->window
)
3595 m_clearRegion
.Clear();
3596 wxSize
size( GetClientSize() );
3597 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3599 // Better do this in idle?
3605 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3607 wxWindowBase::DoSetToolTip(tip
);
3610 m_tooltip
->Apply( (wxWindow
*)this );
3613 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3615 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3617 #endif // wxUSE_TOOLTIPS
3619 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3621 GdkWindow
*window
= (GdkWindow
*) NULL
;
3623 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3625 window
= GetConnectWidget()->window
;
3629 // We need the pixel value e.g. for background clearing.
3630 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3633 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3635 /* wxMSW doesn't clear the window here. I don't do that either to
3636 provide compatibility. call Clear() to do the job. */
3638 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3644 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3646 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3648 if (!wxWindowBase::SetBackgroundColour(colour
))
3651 GdkWindow
*window
= (GdkWindow
*) NULL
;
3653 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3655 window
= GetConnectWidget()->window
;
3659 // indicate that a new style has been set
3660 // but it couldn't get applied as the
3661 // widget hasn't been realized yet.
3662 m_delayedBackgroundColour
= TRUE
;
3667 GtkSetBackgroundColour( colour
);
3673 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3675 GdkWindow
*window
= (GdkWindow
*) NULL
;
3677 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3679 window
= GetConnectWidget()->window
;
3686 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3688 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3690 if (!wxWindowBase::SetForegroundColour(colour
))
3692 // don't leave if the GTK widget has just
3694 if (!m_delayedForegroundColour
) return FALSE
;
3697 GdkWindow
*window
= (GdkWindow
*) NULL
;
3699 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3701 window
= GetConnectWidget()->window
;
3705 // indicate that a new style has been set
3706 // but it couldn't get applied as the
3707 // widget hasn't been realized yet.
3708 m_delayedForegroundColour
= TRUE
;
3712 GtkSetForegroundColour( colour
);
3718 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3722 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3724 // FIXME: no more klass in 2.0
3726 remake
->klass
= m_widgetStyle
->klass
;
3729 gtk_style_unref( m_widgetStyle
);
3730 m_widgetStyle
= remake
;
3734 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3737 def
= gtk_widget_get_default_style();
3739 m_widgetStyle
= gtk_style_copy( def
);
3741 // FIXME: no more klass in 2.0
3743 m_widgetStyle
->klass
= def
->klass
;
3747 return m_widgetStyle
;
3750 void wxWindowGTK::SetWidgetStyle()
3752 #if DISABLE_STYLE_IF_BROKEN_THEME
3753 if (m_widget
->style
->engine_data
)
3755 static bool s_warningPrinted
= FALSE
;
3756 if (!s_warningPrinted
)
3758 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3759 s_warningPrinted
= TRUE
;
3761 m_widgetStyle
= m_widget
->style
;
3766 GtkStyle
*style
= GetWidgetStyle();
3768 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3770 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3773 if (m_foregroundColour
.Ok())
3775 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3776 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3778 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3779 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3780 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3784 // Try to restore the gtk default style. This is still a little
3785 // oversimplified for what is probably really needed here for controls
3786 // other than buttons, but is better than not being able to (re)set a
3787 // control's foreground colour to *wxBLACK -- RL
3788 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3791 def
= gtk_widget_get_default_style();
3793 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3794 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3795 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3799 if (m_backgroundColour
.Ok())
3801 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3802 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3804 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3805 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3806 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3807 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3808 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3809 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3810 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3811 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.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 background colour to default grey and means resetting a
3819 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3821 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3824 def
= gtk_widget_get_default_style();
3826 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3827 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3828 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3829 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3830 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3831 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3832 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3833 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3838 void wxWindowGTK::ApplyWidgetStyle()
3842 //-----------------------------------------------------------------------------
3843 // Pop-up menu stuff
3844 //-----------------------------------------------------------------------------
3846 #if wxUSE_MENUS_NATIVE
3849 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3851 *is_waiting
= FALSE
;
3854 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3856 menu
->SetInvokingWindow( win
);
3857 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3860 wxMenuItem
*menuitem
= node
->GetData();
3861 if (menuitem
->IsSubMenu())
3863 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3866 node
= node
->GetNext();
3870 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3871 // wxPopupMenuPositionCallback()
3873 // should be safe even in the MT case as the user can hardly popup 2 menus
3874 // simultaneously, can he?
3875 static gint gs_pop_x
= 0;
3876 static gint gs_pop_y
= 0;
3878 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3881 gboolean
* WXUNUSED(whatever
),
3883 gpointer
WXUNUSED(user_data
) )
3885 // ensure that the menu appears entirely on screen
3887 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3889 wxSize sizeScreen
= wxGetDisplaySize();
3891 gint xmax
= sizeScreen
.x
- req
.width
,
3892 ymax
= sizeScreen
.y
- req
.height
;
3894 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3895 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3898 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3900 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3902 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3904 SetInvokingWindow( menu
, this );
3910 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3912 bool is_waiting
= TRUE
;
3914 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3916 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3917 (gpointer
)&is_waiting
);
3920 GTK_MENU(menu
->m_menu
),
3921 (GtkWidget
*) NULL
, // parent menu shell
3922 (GtkWidget
*) NULL
, // parent menu item
3923 wxPopupMenuPositionCallback
, // function to position it
3924 NULL
, // client data
3925 0, // button used to activate it
3926 gs_timeLastClick
// the time of activation
3931 while (gtk_events_pending())
3932 gtk_main_iteration();
3938 #endif // wxUSE_MENUS_NATIVE
3940 #if wxUSE_DRAG_AND_DROP
3942 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3944 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3946 GtkWidget
*dnd_widget
= GetConnectWidget();
3948 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3950 if (m_dropTarget
) delete m_dropTarget
;
3951 m_dropTarget
= dropTarget
;
3953 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3956 #endif // wxUSE_DRAG_AND_DROP
3958 GtkWidget
* wxWindowGTK::GetConnectWidget()
3960 GtkWidget
*connect_widget
= m_widget
;
3961 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3963 return connect_widget
;
3966 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3969 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3971 return (window
== m_widget
->window
);
3974 bool wxWindowGTK::SetFont( const wxFont
&font
)
3976 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3978 if (!wxWindowBase::SetFont(font
))
3983 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3984 if ( sysbg
== m_backgroundColour
)
3986 m_backgroundColour
= wxNullColour
;
3988 m_backgroundColour
= sysbg
;
3998 void wxWindowGTK::DoCaptureMouse()
4000 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4002 GdkWindow
*window
= (GdkWindow
*) NULL
;
4004 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4006 window
= GetConnectWidget()->window
;
4008 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4010 wxCursor
* cursor
= & m_cursor
;
4012 cursor
= wxSTANDARD_CURSOR
;
4014 gdk_pointer_grab( window
, FALSE
,
4016 (GDK_BUTTON_PRESS_MASK
|
4017 GDK_BUTTON_RELEASE_MASK
|
4018 GDK_POINTER_MOTION_HINT_MASK
|
4019 GDK_POINTER_MOTION_MASK
),
4021 cursor
->GetCursor(),
4022 (guint32
)GDK_CURRENT_TIME
);
4023 g_captureWindow
= this;
4024 g_captureWindowHasMouse
= TRUE
;
4027 void wxWindowGTK::DoReleaseMouse()
4029 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4031 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4033 g_captureWindow
= (wxWindowGTK
*) NULL
;
4035 GdkWindow
*window
= (GdkWindow
*) NULL
;
4037 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4039 window
= GetConnectWidget()->window
;
4044 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4048 wxWindow
*wxWindowBase::GetCapture()
4050 return (wxWindow
*)g_captureWindow
;
4053 bool wxWindowGTK::IsRetained() const
4058 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4059 int range
, bool refresh
)
4061 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4063 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4065 m_hasScrolling
= TRUE
;
4067 if (orient
== wxHORIZONTAL
)
4069 float fpos
= (float)pos
;
4070 float frange
= (float)range
;
4071 float fthumb
= (float)thumbVisible
;
4072 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4073 if (fpos
< 0.0) fpos
= 0.0;
4075 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4076 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4078 SetScrollPos( orient
, pos
, refresh
);
4082 m_oldHorizontalPos
= fpos
;
4084 m_hAdjust
->lower
= 0.0;
4085 m_hAdjust
->upper
= frange
;
4086 m_hAdjust
->value
= fpos
;
4087 m_hAdjust
->step_increment
= 1.0;
4088 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4089 m_hAdjust
->page_size
= fthumb
;
4093 float fpos
= (float)pos
;
4094 float frange
= (float)range
;
4095 float fthumb
= (float)thumbVisible
;
4096 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4097 if (fpos
< 0.0) fpos
= 0.0;
4099 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4100 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4102 SetScrollPos( orient
, pos
, refresh
);
4106 m_oldVerticalPos
= fpos
;
4108 m_vAdjust
->lower
= 0.0;
4109 m_vAdjust
->upper
= frange
;
4110 m_vAdjust
->value
= fpos
;
4111 m_vAdjust
->step_increment
= 1.0;
4112 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4113 m_vAdjust
->page_size
= fthumb
;
4116 if (orient
== wxHORIZONTAL
)
4117 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4119 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4122 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4124 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4126 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4128 if (orient
== wxHORIZONTAL
)
4130 float fpos
= (float)pos
;
4131 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4132 if (fpos
< 0.0) fpos
= 0.0;
4133 m_oldHorizontalPos
= fpos
;
4135 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4136 m_hAdjust
->value
= fpos
;
4140 float fpos
= (float)pos
;
4141 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4142 if (fpos
< 0.0) fpos
= 0.0;
4143 m_oldVerticalPos
= fpos
;
4145 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4146 m_vAdjust
->value
= fpos
;
4149 if (m_wxwindow
->window
)
4151 if (orient
== wxHORIZONTAL
)
4153 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4154 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4156 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4158 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4159 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4163 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4164 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4166 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4168 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4169 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4174 int wxWindowGTK::GetScrollThumb( int orient
) const
4176 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4178 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4180 if (orient
== wxHORIZONTAL
)
4181 return (int)(m_hAdjust
->page_size
+0.5);
4183 return (int)(m_vAdjust
->page_size
+0.5);
4186 int wxWindowGTK::GetScrollPos( int orient
) const
4188 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4190 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4192 if (orient
== wxHORIZONTAL
)
4193 return (int)(m_hAdjust
->value
+0.5);
4195 return (int)(m_vAdjust
->value
+0.5);
4198 int wxWindowGTK::GetScrollRange( int orient
) const
4200 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4202 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4204 if (orient
== wxHORIZONTAL
)
4205 return (int)(m_hAdjust
->upper
+0.5);
4207 return (int)(m_vAdjust
->upper
+0.5);
4210 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4212 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4214 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4216 // No scrolling requested.
4217 if ((dx
== 0) && (dy
== 0)) return;
4220 if (!m_updateRegion
.IsEmpty())
4222 m_updateRegion
.Offset( dx
, dy
);
4226 GetClientSize( &cw
, &ch
);
4227 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4230 if (!m_clearRegion
.IsEmpty())
4232 m_clearRegion
.Offset( dx
, dy
);
4236 GetClientSize( &cw
, &ch
);
4237 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4240 m_clipPaintRegion
= TRUE
;
4242 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4244 m_clipPaintRegion
= FALSE
;
4247 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4249 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4250 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4257 // Find the wxWindow at the current mouse position, also returning the mouse
4259 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4261 pt
= wxGetMousePosition();
4262 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4266 // Get the current mouse position.
4267 wxPoint
wxGetMousePosition()
4269 /* This crashes when used within wxHelpContext,
4270 so we have to use the X-specific implementation below.
4272 GdkModifierType *mask;
4273 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4275 return wxPoint(x, y);
4279 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4281 return wxPoint(-999, -999);
4283 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4284 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4285 Window rootReturn
, childReturn
;
4286 int rootX
, rootY
, winX
, winY
;
4287 unsigned int maskReturn
;
4289 XQueryPointer (display
,
4293 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4294 return wxPoint(rootX
, rootY
);
4298 // ----------------------------------------------------------------------------
4300 // ----------------------------------------------------------------------------
4302 class wxWinModule
: public wxModule
4309 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4312 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4314 bool wxWinModule::OnInit()
4316 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4317 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4322 void wxWinModule::OnExit()
4325 gdk_gc_unref( g_eraseGC
);