1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "window.h"
16 #define XWarpPointer XWARPPOINTER
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
24 #include "wx/layout.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28 #include "wx/module.h"
30 #if wxUSE_DRAG_AND_DROP
35 #include "wx/tooltip.h"
43 #include "wx/textctrl.h"
47 #include "wx/statusbr.h"
49 #include "wx/settings.h"
51 #include "wx/fontutil.h"
54 #include "wx/thread.h"
60 #include "wx/gtk/private.h"
61 #include <gdk/gdkprivate.h>
62 #include <gdk/gdkkeysyms.h>
66 #include <gtk/gtkprivate.h>
68 #include "wx/gtk/win_gtk.h"
71 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
73 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
83 extern GtkContainerClass
*pizza_parent_class
;
86 //-----------------------------------------------------------------------------
87 // documentation on internals
88 //-----------------------------------------------------------------------------
91 I have been asked several times about writing some documentation about
92 the GTK port of wxWindows, especially its internal structures. Obviously,
93 you cannot understand wxGTK without knowing a little about the GTK, but
94 some more information about what the wxWindow, which is the base class
95 for all other window classes, does seems required as well.
99 What does wxWindow do? It contains the common interface for the following
100 jobs of its descendants:
102 1) Define the rudimentary behaviour common to all window classes, such as
103 resizing, intercepting user input (so as to make it possible to use these
104 events for special purposes in a derived class), window names etc.
106 2) Provide the possibility to contain and manage children, if the derived
107 class is allowed to contain children, which holds true for those window
108 classes which do not display a native GTK widget. To name them, these
109 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
110 work classes are a special case and are handled a bit differently from
111 the rest. The same holds true for the wxNotebook class.
113 3) Provide the possibility to draw into a client area of a window. This,
114 too, only holds true for classes that do not display a native GTK widget
117 4) Provide the entire mechanism for scrolling widgets. This actual inter-
118 face for this is usually in wxScrolledWindow, but the GTK implementation
121 5) A multitude of helper or extra methods for special purposes, such as
122 Drag'n'Drop, managing validators etc.
124 6) Display a border (sunken, raised, simple or none).
126 Normally one might expect, that one wxWindows window would always correspond
127 to one GTK widget. Under GTK, there is no such allround widget that has all
128 the functionality. Moreover, the GTK defines a client area as a different
129 widget from the actual widget you are handling. Last but not least some
130 special classes (e.g. wxFrame) handle different categories of widgets and
131 still have the possibility to draw something in the client area.
132 It was therefore required to write a special purpose GTK widget, that would
133 represent a client area in the sense of wxWindows capable to do the jobs
134 2), 3) and 4). I have written this class and it resides in win_gtk.c of
137 All windows must have a widget, with which they interact with other under-
138 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
139 thw wxWindow class has a member variable called m_widget which holds a
140 pointer to this widget. When the window class represents a GTK native widget,
141 this is (in most cases) the only GTK widget the class manages. E.g. the
142 wxStatitText class handles only a GtkLabel widget a pointer to which you
143 can find in m_widget (defined in wxWindow)
145 When the class has a client area for drawing into and for containing children
146 it has to handle the client area widget (of the type GtkPizza, defined in
147 win_gtk.c), but there could be any number of widgets, handled by a class
148 The common rule for all windows is only, that the widget that interacts with
149 the rest of GTK must be referenced in m_widget and all other widgets must be
150 children of this widget on the GTK level. The top-most widget, which also
151 represents the client area, must be in the m_wxwindow field and must be of
154 As I said, the window classes that display a GTK native widget only have
155 one widget, so in the case of e.g. the wxButton class m_widget holds a
156 pointer to a GtkButton widget. But windows with client areas (for drawing
157 and children) have a m_widget field that is a pointer to a GtkScrolled-
158 Window and a m_wxwindow field that is pointer to a GtkPizza and this
159 one is (in the GTK sense) a child of the GtkScrolledWindow.
161 If the m_wxwindow field is set, then all input to this widget is inter-
162 cepted and sent to the wxWindows class. If not, all input to the widget
163 that gets pointed to by m_widget gets intercepted and sent to the class.
167 The design of scrolling in wxWindows is markedly different from that offered
168 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
169 clicking on a scrollbar belonging to scrolled window will inevitably move
170 the window. In wxWindows, the scrollbar will only emit an event, send this
171 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
172 which actually moves the window and its subchildren. Note that GtkPizza
173 memorizes how much it has been scrolled but that wxWindows forgets this
174 so that the two coordinates systems have to be kept in synch. This is done
175 in various places using the pizza->xoffset and pizza->yoffset values.
179 Singularily the most broken code in GTK is the code that is supposes to
180 inform subwindows (child windows) about new positions. Very often, duplicate
181 events are sent without changes in size or position, equally often no
182 events are sent at all (All this is due to a bug in the GtkContainer code
183 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
184 GTK's own system and it simply waits for size events for toplevel windows
185 and then iterates down the respective size events to all window. This has
186 the disadvantage, that windows might get size events before the GTK widget
187 actually has the reported size. This doesn't normally pose any problem, but
188 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
189 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
190 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
191 window that is used for OpenGl output really has that size (as reported by
196 If someone at some point of time feels the immense desire to have a look at,
197 change or attempt to optimse the Refresh() logic, this person will need an
198 intimate understanding of what a "draw" and what an "expose" events are and
199 what there are used for, in particular when used in connection with GTK's
200 own windowless widgets. Beware.
204 Cursors, too, have been a constant source of pleasure. The main difficulty
205 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
206 for the parent. To prevent this from doing too much harm, I use idle time
207 to set the cursor over and over again, starting from the toplevel windows
208 and ending with the youngest generation (speaking of parent and child windows).
209 Also don't forget that cursors (like much else) are connected to GdkWindows,
210 not GtkWidgets and that the "window" field of a GtkWidget might very well
211 point to the GdkWindow of the parent widget (-> "window less widget") and
212 that the two obviously have very different meanings.
216 //-----------------------------------------------------------------------------
218 //-----------------------------------------------------------------------------
220 extern wxList wxPendingDelete
;
221 extern bool g_blockEventsOnDrag
;
222 extern bool g_blockEventsOnScroll
;
223 extern wxCursor g_globalCursor
;
225 static GdkGC
*g_eraseGC
= NULL
;
227 // mouse capture state: the window which has it and if the mouse is currently
229 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
230 static bool g_captureWindowHasMouse
= FALSE
;
232 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
234 // the last window which had the focus - this is normally never NULL (except
235 // if we never had focus at all) as even when g_focusWindow is NULL it still
236 // keeps its previous value
237 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
239 // the frame that is currently active (i.e. its child has focus). It is
240 // used to generate wxActivateEvents
241 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
242 static bool g_activeFrameLostFocus
= FALSE
;
244 // If a window get the focus set but has not been realized
245 // yet, defer setting the focus to idle time.
246 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
248 // if we detect that the app has got/lost the focus, we set this variable to
249 // either TRUE or FALSE and an activate event will be sent during the next
250 // OnIdle() call and it is reset to -1: this value means that we shouldn't
251 // send any activate events at all
252 static int g_sendActivateEvent
= -1;
254 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
255 the last click here */
256 static guint32 gs_timeLastClick
= 0;
258 extern bool g_mainThreadLocked
;
260 //-----------------------------------------------------------------------------
262 //-----------------------------------------------------------------------------
265 #define DISABLE_STYLE_IF_BROKEN_THEME 1
271 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
273 # define DEBUG_MAIN_THREAD
276 #define DEBUG_MAIN_THREAD
279 // the trace mask used for the focus debugging messages
280 #define TRACE_FOCUS _T("focus")
282 //-----------------------------------------------------------------------------
283 // missing gdk functions
284 //-----------------------------------------------------------------------------
287 gdk_window_warp_pointer (GdkWindow
*window
,
292 GdkWindowPrivate
*priv
;
296 window
= GDK_ROOT_PARENT();
299 if (!GDK_WINDOW_DESTROYED(window
))
301 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
302 None
, /* not source window -> move from anywhere */
303 GDK_WINDOW_XID(window
), /* dest window */
304 0, 0, 0, 0, /* not source window -> move from anywhere */
308 priv
= (GdkWindowPrivate
*) window
;
310 if (!priv
->destroyed
)
312 XWarpPointer (priv
->xdisplay
,
313 None
, /* not source window -> move from anywhere */
314 priv
->xwindow
, /* dest window */
315 0, 0, 0, 0, /* not source window -> move from anywhere */
321 //-----------------------------------------------------------------------------
323 //-----------------------------------------------------------------------------
325 extern void wxapp_install_idle_handler();
326 extern bool g_isIdle
;
328 //-----------------------------------------------------------------------------
329 // local code (see below)
330 //-----------------------------------------------------------------------------
332 // returns the child of win which currently has focus or NULL if not found
334 // Note: can't be static, needed by textctrl.cpp.
335 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
337 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
339 return (wxWindow
*)NULL
;
341 if ( winFocus
== win
)
342 return (wxWindow
*)win
;
344 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
346 node
= node
->GetNext() )
348 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
353 return (wxWindow
*)NULL
;
356 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
358 // wxUniversal widgets draw the borders and scrollbars themselves
359 #ifndef __WXUNIVERSAL__
366 if (win
->m_hasScrolling
)
368 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
370 GtkRequisition vscroll_req
;
371 vscroll_req
.width
= 2;
372 vscroll_req
.height
= 2;
373 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
374 (scroll_window
->vscrollbar
, &vscroll_req
);
376 GtkRequisition hscroll_req
;
377 hscroll_req
.width
= 2;
378 hscroll_req
.height
= 2;
379 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
380 (scroll_window
->hscrollbar
, &hscroll_req
);
382 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
384 if (scroll_window
->vscrollbar_visible
)
386 dw
+= vscroll_req
.width
;
387 dw
+= scroll_class
->scrollbar_spacing
;
390 if (scroll_window
->hscrollbar_visible
)
392 dh
+= hscroll_req
.height
;
393 dh
+= scroll_class
->scrollbar_spacing
;
399 if (GTK_WIDGET_NO_WINDOW (widget
))
401 dx
+= widget
->allocation
.x
;
402 dy
+= widget
->allocation
.y
;
405 if (win
->HasFlag(wxRAISED_BORDER
))
407 gtk_draw_shadow( widget
->style
,
412 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
416 if (win
->HasFlag(wxSUNKEN_BORDER
))
418 gtk_draw_shadow( widget
->style
,
423 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
427 if (win
->HasFlag(wxSIMPLE_BORDER
))
430 gc
= gdk_gc_new( widget
->window
);
431 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
432 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
434 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
438 #endif // __WXUNIVERSAL__
441 //-----------------------------------------------------------------------------
442 // "expose_event" of m_widget
443 //-----------------------------------------------------------------------------
445 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
447 if (gdk_event
->count
> 0) return FALSE
;
449 draw_frame( widget
, win
);
453 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
459 //-----------------------------------------------------------------------------
460 // "draw" of m_widget
461 //-----------------------------------------------------------------------------
465 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
467 draw_frame( widget
, win
);
472 //-----------------------------------------------------------------------------
473 // "size_request" of m_widget
474 //-----------------------------------------------------------------------------
476 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
479 win
->GetSize( &w
, &h
);
483 requisition
->height
= h
;
484 requisition
->width
= w
;
487 //-----------------------------------------------------------------------------
488 // "expose_event" of m_wxwindow
489 //-----------------------------------------------------------------------------
491 static int gtk_window_expose_callback( GtkWidget
*widget
,
492 GdkEventExpose
*gdk_event
,
498 wxapp_install_idle_handler();
503 wxPrintf( wxT("OnExpose from ") );
504 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
505 wxPrintf( win
->GetClassInfo()->GetClassName() );
506 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
507 (int)gdk_event
->area
.y
,
508 (int)gdk_event
->area
.width
,
509 (int)gdk_event
->area
.height
);
513 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
515 gdk_event
->area
.width
,
516 gdk_event
->area
.height
);
517 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
519 gdk_event
->area
.width
,
520 gdk_event
->area
.height
);
522 // Actual redrawing takes place in idle time.
527 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
534 //-----------------------------------------------------------------------------
535 // "event" of m_wxwindow
536 //-----------------------------------------------------------------------------
538 // GTK thinks it is clever and filters out a certain amount of "unneeded"
539 // expose events. We need them, of course, so we override the main event
540 // procedure in GtkWidget by giving our own handler for all system events.
541 // There, we look for expose events ourselves whereas all other events are
544 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
545 GdkEventExpose
*event
,
548 if (event
->type
== GDK_EXPOSE
)
550 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
557 //-----------------------------------------------------------------------------
558 // "draw" of m_wxwindow
559 //-----------------------------------------------------------------------------
563 // This callback is a complete replacement of the gtk_pizza_draw() function,
564 // which is disabled.
566 static void gtk_window_draw_callback( GtkWidget
*widget
,
573 wxapp_install_idle_handler();
575 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
576 // there are no child windows.
577 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
578 (win
->GetChildren().GetCount() == 0))
586 wxPrintf( wxT("OnDraw from ") );
587 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
588 wxPrintf( win
->GetClassInfo()->GetClassName() );
589 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
596 #ifndef __WXUNIVERSAL__
597 GtkPizza
*pizza
= GTK_PIZZA (widget
);
599 if (win
->GetThemeEnabled())
601 wxWindow
*parent
= win
->GetParent();
602 while (parent
&& !parent
->IsTopLevel())
603 parent
= parent
->GetParent();
607 gtk_paint_flat_box (parent
->m_widget
->style
,
618 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
619 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
621 // Update immediately, not in idle time.
624 #ifndef __WXUNIVERSAL__
625 // Redraw child widgets
626 GList
*children
= pizza
->children
;
629 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
630 children
= children
->next
;
632 GdkRectangle child_area
;
633 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
635 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
643 //-----------------------------------------------------------------------------
644 // "key_press_event" from any window
645 //-----------------------------------------------------------------------------
647 // set WXTRACE to this to see the key event codes on the console
648 #define TRACE_KEYS _T("keyevent")
650 // translates an X key symbol to WXK_XXX value
652 // if isChar is true it means that the value returned will be used for EVT_CHAR
653 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
654 // for example, while if it is false it means that the value is going to be
655 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
657 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
663 // Shift, Control and Alt don't generate the CHAR events at all
666 key_code
= isChar
? 0 : WXK_SHIFT
;
670 key_code
= isChar
? 0 : WXK_CONTROL
;
678 key_code
= isChar
? 0 : WXK_ALT
;
681 // neither do the toggle modifies
682 case GDK_Scroll_Lock
:
683 key_code
= isChar
? 0 : WXK_SCROLL
;
687 key_code
= isChar
? 0 : WXK_CAPITAL
;
691 key_code
= isChar
? 0 : WXK_NUMLOCK
;
695 // various other special keys
708 case GDK_ISO_Left_Tab
:
715 key_code
= WXK_RETURN
;
719 key_code
= WXK_CLEAR
;
723 key_code
= WXK_PAUSE
;
727 key_code
= WXK_SELECT
;
731 key_code
= WXK_PRINT
;
735 key_code
= WXK_EXECUTE
;
739 key_code
= WXK_ESCAPE
;
742 // cursor and other extended keyboard keys
744 key_code
= WXK_DELETE
;
760 key_code
= WXK_RIGHT
;
767 case GDK_Prior
: // == GDK_Page_Up
768 key_code
= WXK_PRIOR
;
771 case GDK_Next
: // == GDK_Page_Down
784 key_code
= WXK_INSERT
;
799 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
803 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
807 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
811 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
815 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
819 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
823 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
827 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
831 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
835 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
839 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
843 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
847 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
850 case GDK_KP_Prior
: // == GDK_KP_Page_Up
851 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
854 case GDK_KP_Next
: // == GDK_KP_Page_Down
855 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
859 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
863 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
867 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
871 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
875 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
878 case GDK_KP_Multiply
:
879 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
883 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
886 case GDK_KP_Separator
:
887 // FIXME: what is this?
888 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
891 case GDK_KP_Subtract
:
892 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
896 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
900 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
917 key_code
= WXK_F1
+ keysym
- GDK_F1
;
927 static inline bool wxIsAsciiKeysym(KeySym ks
)
933 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
935 GdkEventKey
*gdk_event
)
937 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
938 // but only event->keyval which is quite useless to us, so remember
939 // the last character from GDK_KEY_PRESS and reuse it as last resort
941 // NB: should be MT-safe as we're always called from the main thread only
946 } s_lastKeyPress
= { 0, 0 };
948 KeySym keysym
= gdk_event
->keyval
;
950 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
951 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
955 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
959 // do we have the translation or is it a plain ASCII character?
960 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
962 // we should use keysym if it is ASCII as X does some translations
963 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
964 // which we don't want here (but which we do use for OnChar())
965 if ( !wxIsAsciiKeysym(keysym
) )
967 keysym
= (KeySym
)gdk_event
->string
[0];
970 // we want to always get the same key code when the same key is
971 // pressed regardless of the state of the modifies, i.e. on a
972 // standard US keyboard pressing '5' or '%' ('5' key with
973 // Shift) should result in the same key code in OnKeyDown():
974 // '5' (although OnChar() will get either '5' or '%').
976 // to do it we first translate keysym to keycode (== scan code)
977 // and then back but always using the lower register
978 Display
*dpy
= (Display
*)wxGetDisplay();
979 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
981 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
983 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
985 // use the normalized, i.e. lower register, keysym if we've
987 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
989 // as explained above, we want to have lower register key codes
990 // normally but for the letter keys we want to have the upper ones
992 // NB: don't use XConvertCase() here, we want to do it for letters
994 key_code
= toupper(key_code
);
996 else // non ASCII key, what to do?
998 // by default, ignore it
1001 // but if we have cached information from the last KEY_PRESS
1002 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1005 if ( keysym
== s_lastKeyPress
.keysym
)
1007 key_code
= s_lastKeyPress
.keycode
;
1012 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1014 // remember it to be reused for KEY_UP event later
1015 s_lastKeyPress
.keysym
= keysym
;
1016 s_lastKeyPress
.keycode
= key_code
;
1020 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1022 // sending unknown key events doesn't really make sense
1026 // now fill all the other fields
1029 GdkModifierType state
;
1030 if (gdk_event
->window
)
1031 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1033 event
.SetTimestamp( gdk_event
->time
);
1034 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1035 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1036 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1037 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1038 event
.m_keyCode
= key_code
;
1039 event
.m_scanCode
= gdk_event
->keyval
;
1040 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1041 event
.m_rawFlags
= 0;
1044 event
.SetEventObject( win
);
1049 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1050 GdkEventKey
*gdk_event
,
1056 wxapp_install_idle_handler();
1060 if (g_blockEventsOnDrag
)
1064 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1065 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1067 // unknown key pressed, ignore (the event would be useless anyhow)
1071 // Emit KEY_DOWN event
1072 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1077 wxWindowGTK
*ancestor
= win
;
1080 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1083 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1084 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1087 if (ancestor
->IsTopLevel())
1089 ancestor
= ancestor
->GetParent();
1092 #endif // wxUSE_ACCEL
1094 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1095 // will only be sent if it is not in an accelerator table.
1098 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1099 KeySym keysym
= gdk_event
->keyval
;
1100 long key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1103 if ( gdk_event
->length
== 1 )
1105 key_code
= (unsigned char)gdk_event
->string
[0];
1107 else if ( wxIsAsciiKeysym(keysym
) )
1110 key_code
= (unsigned char)keysym
;
1116 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1118 event
.m_keyCode
= key_code
;
1120 // Implement OnCharHook by checking ancesteror top level windows
1121 wxWindow
*parent
= win
;
1122 while (parent
&& !parent
->IsTopLevel())
1123 parent
= parent
->GetParent();
1126 event
.SetEventType( wxEVT_CHAR_HOOK
);
1127 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1132 event
.SetEventType(wxEVT_CHAR
);
1133 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1138 // win is a control: tab can be propagated up
1140 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1141 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1142 // have this style, yet choose not to process this particular TAB in which
1143 // case TAB must still work as a navigational character
1145 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1147 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1149 wxNavigationKeyEvent new_event
;
1150 new_event
.SetEventObject( win
->GetParent() );
1151 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1152 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1153 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1154 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1155 new_event
.SetCurrentFocus( win
);
1156 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1159 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1161 (gdk_event
->keyval
== GDK_Escape
) )
1163 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1164 new_event
.SetEventObject( win
);
1165 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1170 // Pressing F10 will activate the menu bar of the top frame
1172 (gdk_event
->keyval
== GDK_F10
) )
1174 wxWindowGTK
*ancestor
= win
;
1177 if (wxIsKindOf(ancestor
,wxFrame
))
1179 wxFrame
*frame
= (wxFrame
*) ancestor
;
1180 wxMenuBar
*menubar
= frame
->GetMenuBar();
1183 wxNode
*node
= menubar
->GetMenus().First();
1186 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1187 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1193 ancestor
= ancestor
->GetParent();
1200 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1207 //-----------------------------------------------------------------------------
1208 // "key_release_event" from any window
1209 //-----------------------------------------------------------------------------
1211 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1212 GdkEventKey
*gdk_event
,
1218 wxapp_install_idle_handler();
1223 if (g_blockEventsOnDrag
)
1226 wxKeyEvent
event( wxEVT_KEY_UP
);
1227 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1229 // unknown key pressed, ignore (the event would be useless anyhow
1233 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1236 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1240 // ============================================================================
1242 // ============================================================================
1244 // ----------------------------------------------------------------------------
1245 // mouse event processing helpers
1246 // ----------------------------------------------------------------------------
1248 // init wxMouseEvent with the info from gdk_event
1250 // NB: this has to be a macro as gdk_event type is different for different
1251 // events we're used with
1252 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1253 /* wxMouseEvent& */ event, \
1254 /* GdkEventXXX * */ gdk_event) \
1256 event.SetTimestamp( gdk_event->time ); \
1257 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1258 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1259 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1260 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1261 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1262 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1263 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1265 wxPoint pt = win->GetClientAreaOrigin(); \
1266 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1267 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1269 event.SetEventObject( win ); \
1270 event.SetId( win->GetId() ); \
1271 event.SetTimestamp( gdk_event->time ); \
1274 static void AdjustEventButtonState(wxMouseEvent& event)
1276 // GDK reports the old state of the button for a button press event, but
1277 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1278 // for a LEFT_DOWN event, not FALSE, so we will invert
1279 // left/right/middleDown for the corresponding click events
1281 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1282 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1283 (event
.GetEventType() == wxEVT_LEFT_UP
))
1285 event
.m_leftDown
= !event
.m_leftDown
;
1289 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1290 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1291 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1293 event
.m_middleDown
= !event
.m_middleDown
;
1297 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1298 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1299 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1301 event
.m_rightDown
= !event
.m_rightDown
;
1306 // find the window to send the mouse event too
1308 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1313 if (win
->m_wxwindow
)
1315 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1316 xx
+= pizza
->xoffset
;
1317 yy
+= pizza
->yoffset
;
1320 wxNode
*node
= win
->GetChildren().First();
1323 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1325 node
= node
->Next();
1326 if (!child
->IsShown())
1329 if (child
->IsTransparentForMouse())
1331 // wxStaticBox is transparent in the box itself
1332 int xx1
= child
->m_x
;
1333 int yy1
= child
->m_y
;
1334 int xx2
= child
->m_x
+ child
->m_width
;
1335 int yy2
= child
->m_x
+ child
->m_height
;
1338 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1340 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1342 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1344 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1355 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1356 (child
->m_x
<= xx
) &&
1357 (child
->m_y
<= yy
) &&
1358 (child
->m_x
+child
->m_width
>= xx
) &&
1359 (child
->m_y
+child
->m_height
>= yy
))
1372 //-----------------------------------------------------------------------------
1373 // "button_press_event"
1374 //-----------------------------------------------------------------------------
1376 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1377 GdkEventButton
*gdk_event
,
1383 wxapp_install_idle_handler();
1386 wxPrintf( wxT("1) OnButtonPress from ") );
1387 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1388 wxPrintf( win->GetClassInfo()->GetClassName() );
1389 wxPrintf( wxT(".\n") );
1391 if (!win
->m_hasVMT
) return FALSE
;
1392 if (g_blockEventsOnDrag
) return TRUE
;
1393 if (g_blockEventsOnScroll
) return TRUE
;
1395 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1397 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1399 gtk_widget_grab_focus( win
->m_wxwindow
);
1401 wxPrintf( wxT("GrabFocus from ") );
1402 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1403 wxPrintf( win->GetClassInfo()->GetClassName() );
1404 wxPrintf( wxT(".\n") );
1408 wxEventType event_type
= wxEVT_NULL
;
1410 if (gdk_event
->button
== 1)
1412 switch (gdk_event
->type
)
1414 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1415 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1419 else if (gdk_event
->button
== 2)
1421 switch (gdk_event
->type
)
1423 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1424 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1428 else if (gdk_event
->button
== 3)
1430 switch (gdk_event
->type
)
1432 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1433 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1438 if ( event_type
== wxEVT_NULL
)
1440 // unknown mouse button or click type
1444 wxMouseEvent
event( event_type
);
1445 InitMouseEvent( win
, event
, gdk_event
);
1447 AdjustEventButtonState(event
);
1449 // wxListBox actually get mouse events from the item, so we need to give it
1450 // a chance to correct this
1451 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1453 // find the correct window to send the event too: it may be a different one
1454 // from the one which got it at GTK+ level because some control don't have
1455 // their own X window and thus cannot get any events.
1456 if ( !g_captureWindow
)
1457 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1459 gs_timeLastClick
= gdk_event
->time
;
1462 wxPrintf( wxT("2) OnButtonPress from ") );
1463 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1464 wxPrintf( win->GetClassInfo()->GetClassName() );
1465 wxPrintf( wxT(".\n") );
1468 if (win
->GetEventHandler()->ProcessEvent( event
))
1470 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1477 //-----------------------------------------------------------------------------
1478 // "button_release_event"
1479 //-----------------------------------------------------------------------------
1481 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1486 wxapp_install_idle_handler();
1488 if (!win
->m_hasVMT
) return FALSE
;
1489 if (g_blockEventsOnDrag
) return FALSE
;
1490 if (g_blockEventsOnScroll
) return FALSE
;
1492 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1495 printf( "OnButtonRelease from " );
1496 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1497 printf( win->GetClassInfo()->GetClassName() );
1501 wxEventType event_type
= wxEVT_NULL
;
1503 switch (gdk_event
->button
)
1505 case 1: event_type
= wxEVT_LEFT_UP
; break;
1506 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1507 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1508 default: return FALSE
;
1511 wxMouseEvent
event( event_type
);
1512 InitMouseEvent( win
, event
, gdk_event
);
1514 AdjustEventButtonState(event
);
1516 // same wxListBox hack as above
1517 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1519 if ( !g_captureWindow
)
1520 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1522 if (win
->GetEventHandler()->ProcessEvent( event
))
1524 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1531 //-----------------------------------------------------------------------------
1532 // "motion_notify_event"
1533 //-----------------------------------------------------------------------------
1535 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1536 GdkEventMotion
*gdk_event
,
1542 wxapp_install_idle_handler();
1544 if (!win
->m_hasVMT
) return FALSE
;
1545 if (g_blockEventsOnDrag
) return FALSE
;
1546 if (g_blockEventsOnScroll
) return FALSE
;
1548 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1550 if (gdk_event
->is_hint
)
1554 GdkModifierType state
;
1555 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1561 printf( "OnMotion from " );
1562 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1563 printf( win->GetClassInfo()->GetClassName() );
1567 wxMouseEvent
event( wxEVT_MOTION
);
1568 InitMouseEvent(win
, event
, gdk_event
);
1570 if ( g_captureWindow
)
1572 // synthetize a mouse enter or leave event if needed
1573 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1574 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1575 if ( hasMouse
!= g_captureWindowHasMouse
)
1577 // the mouse changed window
1578 g_captureWindowHasMouse
= hasMouse
;
1580 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1581 : wxEVT_LEAVE_WINDOW
);
1582 InitMouseEvent(win
, event
, gdk_event
);
1583 event
.SetEventObject(win
);
1584 win
->GetEventHandler()->ProcessEvent(event
);
1589 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1592 if (win
->GetEventHandler()->ProcessEvent( event
))
1594 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1601 //-----------------------------------------------------------------------------
1603 //-----------------------------------------------------------------------------
1605 // send the wxChildFocusEvent and wxFocusEvent, common code of
1606 // gtk_window_focus_in_callback() and SetFocus()
1607 static bool DoSendFocusEvents(wxWindow
*win
)
1609 // Notify the parent keeping track of focus for the kbd navigation
1610 // purposes that we got it.
1611 wxChildFocusEvent
eventChildFocus(win
);
1612 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1614 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1615 eventFocus
.SetEventObject(win
);
1617 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1620 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1621 GdkEvent
*WXUNUSED(event
),
1627 wxapp_install_idle_handler();
1629 if (!win
->m_hasVMT
) return FALSE
;
1630 if (g_blockEventsOnDrag
) return FALSE
;
1632 switch ( g_sendActivateEvent
)
1635 // we've got focus from outside, synthetize wxActivateEvent
1636 g_sendActivateEvent
= 1;
1640 // another our window just lost focus, it was already ours before
1641 // - don't send any wxActivateEvent
1642 g_sendActivateEvent
= -1;
1647 g_focusWindow
= win
;
1649 wxLogTrace(TRACE_FOCUS
,
1650 _T("%s: focus in"), win
->GetName().c_str());
1654 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1658 // caret needs to be informed about focus change
1659 wxCaret
*caret
= win
->GetCaret();
1662 caret
->OnSetFocus();
1664 #endif // wxUSE_CARET
1666 g_activeFrameLostFocus
= FALSE
;
1668 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1669 if ( active
!= g_activeFrame
)
1671 if ( g_activeFrame
)
1673 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1674 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1675 event
.SetEventObject(g_activeFrame
);
1676 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1679 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1680 g_activeFrame
= active
;
1681 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1682 event
.SetEventObject(g_activeFrame
);
1683 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1685 // Don't send focus events in addition to activate
1686 // if (win == g_activeFrame)
1690 // does the window itself think that it has the focus?
1691 if ( !win
->m_hasFocus
)
1693 // not yet, notify it
1694 win
->m_hasFocus
= TRUE
;
1696 if ( DoSendFocusEvents(win
) )
1698 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1706 //-----------------------------------------------------------------------------
1707 // "focus_out_event"
1708 //-----------------------------------------------------------------------------
1710 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1715 wxapp_install_idle_handler();
1717 if (!win
->m_hasVMT
) return FALSE
;
1718 if (g_blockEventsOnDrag
) return FALSE
;
1720 wxLogTrace( TRACE_FOCUS
,
1721 _T("%s: focus out"), win
->GetName().c_str() );
1723 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1725 // VZ: commenting this out because it does happen (although not easy
1726 // to reproduce, I only see it when using wxMiniFrame and not
1727 // always) and makes using Mahogany quite annoying
1729 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1730 wxT("unfocusing window that hasn't gained focus properly") );
1733 g_activeFrameLostFocus
= TRUE
;
1736 // if the focus goes out of our app alltogether, OnIdle() will send
1737 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1738 // g_sendActivateEvent to -1
1739 g_sendActivateEvent
= 0;
1741 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1745 g_focusWindow
= (wxWindowGTK
*)NULL
;
1753 // caret needs to be informed about focus change
1754 wxCaret
*caret
= win
->GetCaret();
1757 caret
->OnKillFocus();
1759 #endif // wxUSE_CARET
1761 // don't send the window a kill focus event if it thinks that it doesn't
1762 // have focus already
1763 if ( win
->m_hasFocus
)
1765 win
->m_hasFocus
= FALSE
;
1767 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1768 event
.SetEventObject( win
);
1770 if (win
->GetEventHandler()->ProcessEvent( event
))
1772 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1780 //-----------------------------------------------------------------------------
1781 // "enter_notify_event"
1782 //-----------------------------------------------------------------------------
1785 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1786 GdkEventCrossing
*gdk_event
,
1792 wxapp_install_idle_handler();
1794 if (!win
->m_hasVMT
) return FALSE
;
1795 if (g_blockEventsOnDrag
) return FALSE
;
1797 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1801 GdkModifierType state
= (GdkModifierType
)0;
1803 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1805 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1806 InitMouseEvent(win
, event
, gdk_event
);
1807 wxPoint pt
= win
->GetClientAreaOrigin();
1808 event
.m_x
= x
+ pt
.x
;
1809 event
.m_y
= y
+ pt
.y
;
1811 if (win
->GetEventHandler()->ProcessEvent( event
))
1813 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1820 //-----------------------------------------------------------------------------
1821 // "leave_notify_event"
1822 //-----------------------------------------------------------------------------
1824 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1829 wxapp_install_idle_handler();
1831 if (!win
->m_hasVMT
) return FALSE
;
1832 if (g_blockEventsOnDrag
) return FALSE
;
1834 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1836 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1837 event
.SetTimestamp( gdk_event
->time
);
1838 event
.SetEventObject( win
);
1842 GdkModifierType state
= (GdkModifierType
)0;
1844 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1846 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1847 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1848 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1849 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1850 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1851 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1852 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1854 wxPoint pt
= win
->GetClientAreaOrigin();
1855 event
.m_x
= x
+ pt
.x
;
1856 event
.m_y
= y
+ pt
.y
;
1858 if (win
->GetEventHandler()->ProcessEvent( event
))
1860 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1867 //-----------------------------------------------------------------------------
1868 // "value_changed" from m_vAdjust
1869 //-----------------------------------------------------------------------------
1871 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1878 wxapp_install_idle_handler();
1880 if (g_blockEventsOnDrag
) return;
1882 if (!win
->m_hasVMT
) return;
1884 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1885 if (fabs(diff
) < 0.2) return;
1887 win
->m_oldVerticalPos
= adjust
->value
;
1889 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1890 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
1892 int value
= (int)(adjust
->value
+0.5);
1894 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1895 event
.SetEventObject( win
);
1896 win
->GetEventHandler()->ProcessEvent( event
);
1899 //-----------------------------------------------------------------------------
1900 // "value_changed" from m_hAdjust
1901 //-----------------------------------------------------------------------------
1903 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1910 wxapp_install_idle_handler();
1912 if (g_blockEventsOnDrag
) return;
1913 if (!win
->m_hasVMT
) return;
1915 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1916 if (fabs(diff
) < 0.2) return;
1918 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1919 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
1921 win
->m_oldHorizontalPos
= adjust
->value
;
1923 int value
= (int)(adjust
->value
+0.5);
1925 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1926 event
.SetEventObject( win
);
1927 win
->GetEventHandler()->ProcessEvent( event
);
1930 //-----------------------------------------------------------------------------
1931 // "button_press_event" from scrollbar
1932 //-----------------------------------------------------------------------------
1934 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1935 GdkEventButton
*gdk_event
,
1941 wxapp_install_idle_handler();
1944 g_blockEventsOnScroll
= TRUE
;
1946 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1948 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1954 //-----------------------------------------------------------------------------
1955 // "button_release_event" from scrollbar
1956 //-----------------------------------------------------------------------------
1958 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1959 GdkEventButton
*WXUNUSED(gdk_event
),
1964 // don't test here as we can release the mouse while being over
1965 // a different window than the slider
1967 // if (gdk_event->window != widget->slider) return FALSE;
1969 g_blockEventsOnScroll
= FALSE
;
1971 if (win
->m_isScrolling
)
1973 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1977 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1978 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1980 value
= (int)(win
->m_hAdjust
->value
+0.5);
1983 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
1985 value
= (int)(win
->m_vAdjust
->value
+0.5);
1989 wxScrollWinEvent
event( command
, value
, dir
);
1990 event
.SetEventObject( win
);
1991 win
->GetEventHandler()->ProcessEvent( event
);
1994 win
->m_isScrolling
= FALSE
;
1999 // ----------------------------------------------------------------------------
2000 // this wxWindowBase function is implemented here (in platform-specific file)
2001 // because it is static and so couldn't be made virtual
2002 // ----------------------------------------------------------------------------
2004 wxWindow
*wxWindowBase::FindFocus()
2006 // the cast is necessary when we compile in wxUniversal mode
2007 return (wxWindow
*)g_focusWindow
;
2010 //-----------------------------------------------------------------------------
2012 //-----------------------------------------------------------------------------
2014 // VZ: Robert commented the code using out so it generates warnings: should
2015 // be either fixed or removed completely
2018 static void gtk_window_destroy_callback( GtkWidget
* widget
, wxWindow
*win
)
2020 wxWindowDestroyEvent
event(win
);
2021 win
->GetEventHandler()->ProcessEvent(event
);
2026 //-----------------------------------------------------------------------------
2027 // "realize" from m_widget
2028 //-----------------------------------------------------------------------------
2030 /* We cannot set colours and fonts before the widget has
2031 been realized, so we do this directly after realization. */
2034 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2039 wxapp_install_idle_handler();
2041 if (win
->m_delayedBackgroundColour
)
2042 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2044 if (win
->m_delayedForegroundColour
)
2045 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2047 wxWindowCreateEvent
event( win
);
2048 event
.SetEventObject( win
);
2049 win
->GetEventHandler()->ProcessEvent( event
);
2054 //-----------------------------------------------------------------------------
2056 //-----------------------------------------------------------------------------
2059 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2060 GtkAllocation
*WXUNUSED(alloc
),
2064 wxapp_install_idle_handler();
2066 if (!win
->m_hasScrolling
) return;
2068 int client_width
= 0;
2069 int client_height
= 0;
2070 win
->GetClientSize( &client_width
, &client_height
);
2071 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2074 win
->m_oldClientWidth
= client_width
;
2075 win
->m_oldClientHeight
= client_height
;
2077 if (!win
->m_nativeSizeEvent
)
2079 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2080 event
.SetEventObject( win
);
2081 win
->GetEventHandler()->ProcessEvent( event
);
2087 #define WXUNUSED_UNLESS_XIM(param) param
2089 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2092 /* Resize XIM window */
2095 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2096 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2097 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2100 wxapp_install_idle_handler();
2106 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2110 gdk_window_get_size (widget
->window
, &width
, &height
);
2111 win
->m_icattr
->preedit_area
.width
= width
;
2112 win
->m_icattr
->preedit_area
.height
= height
;
2113 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2118 //-----------------------------------------------------------------------------
2119 // "realize" from m_wxwindow
2120 //-----------------------------------------------------------------------------
2122 /* Initialize XIM support */
2125 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2126 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2129 wxapp_install_idle_handler();
2132 if (win
->m_ic
) return FALSE
;
2133 if (!widget
) return FALSE
;
2134 if (!gdk_im_ready()) return FALSE
;
2136 win
->m_icattr
= gdk_ic_attr_new();
2137 if (!win
->m_icattr
) return FALSE
;
2141 GdkColormap
*colormap
;
2142 GdkICAttr
*attr
= win
->m_icattr
;
2143 unsigned attrmask
= GDK_IC_ALL_REQ
;
2145 GdkIMStyle supported_style
= (GdkIMStyle
)
2146 (GDK_IM_PREEDIT_NONE
|
2147 GDK_IM_PREEDIT_NOTHING
|
2148 GDK_IM_PREEDIT_POSITION
|
2149 GDK_IM_STATUS_NONE
|
2150 GDK_IM_STATUS_NOTHING
);
2152 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2153 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2155 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2156 attr
->client_window
= widget
->window
;
2158 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2159 gtk_widget_get_default_colormap ())
2161 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2162 attr
->preedit_colormap
= colormap
;
2165 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2166 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2167 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2168 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2170 switch (style
& GDK_IM_PREEDIT_MASK
)
2172 case GDK_IM_PREEDIT_POSITION
:
2173 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2175 g_warning ("over-the-spot style requires fontset");
2179 gdk_window_get_size (widget
->window
, &width
, &height
);
2181 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2182 attr
->spot_location
.x
= 0;
2183 attr
->spot_location
.y
= height
;
2184 attr
->preedit_area
.x
= 0;
2185 attr
->preedit_area
.y
= 0;
2186 attr
->preedit_area
.width
= width
;
2187 attr
->preedit_area
.height
= height
;
2188 attr
->preedit_fontset
= widget
->style
->font
;
2193 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2195 if (win
->m_ic
== NULL
)
2196 g_warning ("Can't create input context.");
2199 mask
= gdk_window_get_events (widget
->window
);
2200 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2201 gdk_window_set_events (widget
->window
, mask
);
2203 if (GTK_WIDGET_HAS_FOCUS(widget
))
2204 gdk_im_begin (win
->m_ic
, widget
->window
);
2211 //-----------------------------------------------------------------------------
2212 // InsertChild for wxWindowGTK.
2213 //-----------------------------------------------------------------------------
2215 /* Callback for wxWindowGTK. This very strange beast has to be used because
2216 * C++ has no virtual methods in a constructor. We have to emulate a
2217 * virtual function here as wxNotebook requires a different way to insert
2218 * a child in it. I had opted for creating a wxNotebookPage window class
2219 * which would have made this superfluous (such in the MDI window system),
2220 * but no-one was listening to me... */
2222 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2224 /* the window might have been scrolled already, do we
2225 have to adapt the position */
2226 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2227 child
->m_x
+= pizza
->xoffset
;
2228 child
->m_y
+= pizza
->yoffset
;
2230 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2231 GTK_WIDGET(child
->m_widget
),
2238 //-----------------------------------------------------------------------------
2240 //-----------------------------------------------------------------------------
2242 wxWindow
*wxGetActiveWindow()
2244 return wxWindow::FindFocus();
2247 //-----------------------------------------------------------------------------
2249 //-----------------------------------------------------------------------------
2251 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2253 #ifdef __WXUNIVERSAL__
2254 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2256 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2257 #endif // __WXUNIVERSAL__/__WXGTK__
2259 void wxWindowGTK::Init()
2265 m_widget
= (GtkWidget
*) NULL
;
2266 m_wxwindow
= (GtkWidget
*) NULL
;
2267 m_focusWidget
= (GtkWidget
*) NULL
;
2277 m_needParent
= TRUE
;
2278 m_isBeingDeleted
= FALSE
;
2281 m_nativeSizeEvent
= FALSE
;
2283 m_hasScrolling
= FALSE
;
2284 m_isScrolling
= FALSE
;
2286 m_hAdjust
= (GtkAdjustment
*) NULL
;
2287 m_vAdjust
= (GtkAdjustment
*) NULL
;
2288 m_oldHorizontalPos
= 0.0;
2289 m_oldVerticalPos
= 0.0;
2292 m_widgetStyle
= (GtkStyle
*) NULL
;
2294 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2296 m_acceptsFocus
= FALSE
;
2299 m_clipPaintRegion
= FALSE
;
2301 m_cursor
= *wxSTANDARD_CURSOR
;
2303 m_delayedForegroundColour
= FALSE
;
2304 m_delayedBackgroundColour
= FALSE
;
2307 m_ic
= (GdkIC
*) NULL
;
2308 m_icattr
= (GdkICAttr
*) NULL
;
2312 wxWindowGTK::wxWindowGTK()
2317 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2322 const wxString
&name
)
2326 Create( parent
, id
, pos
, size
, style
, name
);
2329 bool wxWindowGTK::Create( wxWindow
*parent
,
2334 const wxString
&name
)
2336 if (!PreCreation( parent
, pos
, size
) ||
2337 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2339 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2343 m_insertCallback
= wxInsertChildInWindow
;
2345 // always needed for background clearing
2346 m_delayedBackgroundColour
= TRUE
;
2348 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2349 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2351 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2353 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2354 scroll_class
->scrollbar_spacing
= 0;
2356 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2358 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2359 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2361 m_wxwindow
= gtk_pizza_new();
2363 #ifndef __WXUNIVERSAL__
2364 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2366 if (HasFlag(wxRAISED_BORDER
))
2368 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2370 else if (HasFlag(wxSUNKEN_BORDER
))
2372 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2374 else if (HasFlag(wxSIMPLE_BORDER
))
2376 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2380 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2382 #endif // __WXUNIVERSAL__
2384 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2386 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2387 m_acceptsFocus
= TRUE
;
2389 // I _really_ don't want scrollbars in the beginning
2390 m_vAdjust
->lower
= 0.0;
2391 m_vAdjust
->upper
= 1.0;
2392 m_vAdjust
->value
= 0.0;
2393 m_vAdjust
->step_increment
= 1.0;
2394 m_vAdjust
->page_increment
= 1.0;
2395 m_vAdjust
->page_size
= 5.0;
2396 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2397 m_hAdjust
->lower
= 0.0;
2398 m_hAdjust
->upper
= 1.0;
2399 m_hAdjust
->value
= 0.0;
2400 m_hAdjust
->step_increment
= 1.0;
2401 m_hAdjust
->page_increment
= 1.0;
2402 m_hAdjust
->page_size
= 5.0;
2403 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2405 // these handlers block mouse events to any window during scrolling such as
2406 // motion events and prevent GTK and wxWindows from fighting over where the
2409 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2410 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2412 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2413 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2415 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2416 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2418 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2419 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2421 // these handlers get notified when screen updates are required either when
2422 // scrolling or when the window size (and therefore scrollbar configuration)
2425 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2426 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2427 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2428 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2430 gtk_widget_show( m_wxwindow
);
2433 m_parent
->DoAddChild( this );
2435 m_focusWidget
= m_wxwindow
;
2444 wxWindowGTK::~wxWindowGTK()
2446 if (g_focusWindow
== this)
2447 g_focusWindow
= NULL
;
2449 if (g_activeFrame
== this)
2450 g_activeFrame
= NULL
;
2452 if ( g_delayedFocus
== this )
2453 g_delayedFocus
= NULL
;
2455 m_isBeingDeleted
= TRUE
;
2464 m_parent
->RemoveChild( this );
2468 gdk_ic_destroy (m_ic
);
2470 gdk_ic_attr_destroy (m_icattr
);
2475 #if DISABLE_STYLE_IF_BROKEN_THEME
2476 // don't delete if it's a pixmap theme style
2477 if (!m_widgetStyle
->engine_data
)
2478 gtk_style_unref( m_widgetStyle
);
2480 m_widgetStyle
= (GtkStyle
*) NULL
;
2485 gtk_widget_destroy( m_wxwindow
);
2486 m_wxwindow
= (GtkWidget
*) NULL
;
2491 gtk_widget_destroy( m_widget
);
2492 m_widget
= (GtkWidget
*) NULL
;
2496 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2498 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2500 // This turns -1 into 30 so that a minimal window is
2501 // visible even although -1,-1 has been given as the
2502 // size of the window. the same trick is used in other
2503 // ports and should make debugging easier.
2504 m_width
= WidthDefault(size
.x
) ;
2505 m_height
= HeightDefault(size
.y
);
2510 // some reasonable defaults
2515 m_x
= (gdk_screen_width () - m_width
) / 2;
2516 if (m_x
< 10) m_x
= 10;
2520 m_y
= (gdk_screen_height () - m_height
) / 2;
2521 if (m_y
< 10) m_y
= 10;
2528 void wxWindowGTK::PostCreation()
2530 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2536 // these get reported to wxWindows -> wxPaintEvent
2538 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2540 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2541 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2544 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2545 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2547 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2549 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2550 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2553 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2557 // these are called when the "sunken" or "raised" borders are drawn
2558 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2559 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2562 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2563 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2569 if (m_focusWidget
== NULL
)
2570 m_focusWidget
= m_widget
;
2572 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2573 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2575 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2576 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2578 // connect to the various key and mouse handlers
2580 GtkWidget
*connect_widget
= GetConnectWidget();
2582 ConnectWidget( connect_widget
);
2584 /* We cannot set colours, fonts and cursors before the widget has
2585 been realized, so we do this directly after realization */
2586 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2587 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2591 // Catch native resize events
2592 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2593 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2595 // Initialize XIM support
2596 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2597 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2599 // And resize XIM window
2600 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2601 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2604 if (!GTK_IS_COMBO(m_widget
))
2606 // This is needed if we want to add our windows into native
2607 // GTK control, such as the toolbar. With this callback, the
2608 // toolbar gets to know the correct size (the one set by the
2609 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2610 // when moving to GTK 2.0.
2611 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2612 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2618 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2620 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2621 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2623 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2624 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2626 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2627 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2629 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2630 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2632 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2633 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2635 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2636 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2638 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2639 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2641 // This keeps crashing on me. RR.
2643 // gtk_signal_connect( GTK_OBJECT(widget), "destroy",
2644 // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this );
2647 bool wxWindowGTK::Destroy()
2649 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2653 return wxWindowBase::Destroy();
2656 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2658 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2661 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2663 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2664 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2667 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2670 if (m_resizing
) return; /* I don't like recursions */
2673 int currentX
, currentY
;
2674 GetPosition(¤tX
, ¤tY
);
2679 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2681 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2683 /* don't set the size for children of wxNotebook, just take the values. */
2691 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2692 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2694 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2695 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2699 m_x
= x
+ pizza
->xoffset
;
2700 m_y
= y
+ pizza
->yoffset
;
2702 if (width
!= -1) m_width
= width
;
2703 if (height
!= -1) m_height
= height
;
2705 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2707 if (width
== -1) m_width
= 80;
2710 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2712 if (height
== -1) m_height
= 26;
2715 int minWidth
= GetMinWidth(),
2716 minHeight
= GetMinHeight(),
2717 maxWidth
= GetMaxWidth(),
2718 maxHeight
= GetMaxHeight();
2720 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2721 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2722 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2723 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2726 int bottom_border
= 0;
2729 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2731 /* the default button has a border around it */
2737 DoMoveWindow( m_x
-border
,
2740 m_height
+border
+bottom_border
);
2745 /* Sometimes the client area changes size without the
2746 whole windows's size changing, but if the whole
2747 windows's size doesn't change, no wxSizeEvent will
2748 normally be sent. Here we add an extra test if
2749 the client test has been changed and this will
2751 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2755 wxPrintf( "OnSize sent from " );
2756 if (GetClassInfo() && GetClassInfo()->GetClassName())
2757 wxPrintf( GetClassInfo()->GetClassName() );
2758 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2761 if (!m_nativeSizeEvent
)
2763 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2764 event
.SetEventObject( this );
2765 GetEventHandler()->ProcessEvent( event
);
2771 void wxWindowGTK::OnInternalIdle()
2773 // Update invalidated regions.
2776 // Synthetize activate events.
2777 if ( g_sendActivateEvent
!= -1 )
2779 bool activate
= g_sendActivateEvent
!= 0;
2782 g_sendActivateEvent
= -1;
2784 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2787 if ( g_activeFrameLostFocus
)
2789 if ( g_activeFrame
)
2791 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2792 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2793 event
.SetEventObject(g_activeFrame
);
2794 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2795 g_activeFrame
= NULL
;
2797 g_activeFrameLostFocus
= FALSE
;
2800 wxCursor cursor
= m_cursor
;
2801 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2805 /* I now set the cursor anew in every OnInternalIdle call
2806 as setting the cursor in a parent window also effects the
2807 windows above so that checking for the current cursor is
2812 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2814 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2816 if (!g_globalCursor
.Ok())
2817 cursor
= *wxSTANDARD_CURSOR
;
2819 window
= m_widget
->window
;
2820 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2821 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2827 GdkWindow
*window
= m_widget
->window
;
2828 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2829 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2837 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2839 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2841 if (width
) (*width
) = m_width
;
2842 if (height
) (*height
) = m_height
;
2845 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2847 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2851 SetSize( width
, height
);
2858 #ifndef __WXUNIVERSAL__
2859 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2861 /* when using GTK 1.2 we set the shadow border size to 2 */
2865 if (HasFlag(wxSIMPLE_BORDER
))
2867 /* when using GTK 1.2 we set the simple border size to 1 */
2871 #endif // __WXUNIVERSAL__
2875 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2877 GtkRequisition vscroll_req
;
2878 vscroll_req
.width
= 2;
2879 vscroll_req
.height
= 2;
2880 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2881 (scroll_window
->vscrollbar
, &vscroll_req
);
2883 GtkRequisition hscroll_req
;
2884 hscroll_req
.width
= 2;
2885 hscroll_req
.height
= 2;
2886 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2887 (scroll_window
->hscrollbar
, &hscroll_req
);
2889 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2891 if (scroll_window
->vscrollbar_visible
)
2893 dw
+= vscroll_req
.width
;
2894 dw
+= scroll_class
->scrollbar_spacing
;
2897 if (scroll_window
->hscrollbar_visible
)
2899 dh
+= hscroll_req
.height
;
2900 dh
+= scroll_class
->scrollbar_spacing
;
2904 SetSize( width
+dw
, height
+dh
);
2908 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2910 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2914 if (width
) (*width
) = m_width
;
2915 if (height
) (*height
) = m_height
;
2922 #ifndef __WXUNIVERSAL__
2923 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2925 /* when using GTK 1.2 we set the shadow border size to 2 */
2929 if (HasFlag(wxSIMPLE_BORDER
))
2931 /* when using GTK 1.2 we set the simple border size to 1 */
2935 #endif // __WXUNIVERSAL__
2939 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2941 GtkRequisition vscroll_req
;
2942 vscroll_req
.width
= 2;
2943 vscroll_req
.height
= 2;
2944 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2945 (scroll_window
->vscrollbar
, &vscroll_req
);
2947 GtkRequisition hscroll_req
;
2948 hscroll_req
.width
= 2;
2949 hscroll_req
.height
= 2;
2950 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2951 (scroll_window
->hscrollbar
, &hscroll_req
);
2953 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2955 if (scroll_window
->vscrollbar_visible
)
2957 dw
+= vscroll_req
.width
;
2958 dw
+= scroll_class
->scrollbar_spacing
;
2961 if (scroll_window
->hscrollbar_visible
)
2963 dh
+= hscroll_req
.height
;
2964 dh
+= scroll_class
->scrollbar_spacing
;
2968 if (width
) (*width
) = m_width
- dw
;
2969 if (height
) (*height
) = m_height
- dh
;
2973 printf( "GetClientSize, name %s ", GetName().c_str() );
2974 if (width) printf( " width = %d", (*width) );
2975 if (height) printf( " height = %d", (*height) );
2980 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2982 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2986 if (m_parent
&& m_parent
->m_wxwindow
)
2988 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2989 dx
= pizza
->xoffset
;
2990 dy
= pizza
->yoffset
;
2993 if (x
) (*x
) = m_x
- dx
;
2994 if (y
) (*y
) = m_y
- dy
;
2997 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2999 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3001 if (!m_widget
->window
) return;
3003 GdkWindow
*source
= (GdkWindow
*) NULL
;
3005 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3007 source
= m_widget
->window
;
3011 gdk_window_get_origin( source
, &org_x
, &org_y
);
3015 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3017 org_x
+= m_widget
->allocation
.x
;
3018 org_y
+= m_widget
->allocation
.y
;
3026 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3028 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3030 if (!m_widget
->window
) return;
3032 GdkWindow
*source
= (GdkWindow
*) NULL
;
3034 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3036 source
= m_widget
->window
;
3040 gdk_window_get_origin( source
, &org_x
, &org_y
);
3044 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3046 org_x
+= m_widget
->allocation
.x
;
3047 org_y
+= m_widget
->allocation
.y
;
3055 bool wxWindowGTK::Show( bool show
)
3057 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3059 if (!wxWindowBase::Show(show
))
3066 gtk_widget_show( m_widget
);
3068 gtk_widget_hide( m_widget
);
3073 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3075 win
->OnParentEnable(enable
);
3077 // Recurse, so that children have the opportunity to Do The Right Thing
3078 // and reset colours that have been messed up by a parent's (really ancestor's)
3080 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3082 node
= node
->GetNext() )
3084 wxWindow
*child
= node
->GetData();
3085 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3086 wxWindowNotifyEnable(child
, enable
);
3090 bool wxWindowGTK::Enable( bool enable
)
3092 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3094 if (!wxWindowBase::Enable(enable
))
3100 gtk_widget_set_sensitive( m_widget
, enable
);
3102 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3104 wxWindowNotifyEnable(this, enable
);
3109 int wxWindowGTK::GetCharHeight() const
3111 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3113 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3115 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3117 return font
->ascent
+ font
->descent
;
3120 int wxWindowGTK::GetCharWidth() const
3122 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3124 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3126 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3128 return gdk_string_width( font
, "H" );
3131 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3135 int *externalLeading
,
3136 const wxFont
*theFont
) const
3138 wxFont fontToUse
= m_font
;
3139 if (theFont
) fontToUse
= *theFont
;
3141 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3143 if (string
.IsEmpty())
3151 PangoContext
*context
= NULL
;
3153 gtk_widget_get_pango_context( m_widget
);
3162 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3163 PangoLayout
*layout
= pango_layout_new(context
);
3164 pango_layout_set_font_description(layout
, desc
);
3166 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3167 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3169 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3171 PangoRectangle rect
;
3172 pango_layout_line_get_extents(line
, NULL
, &rect
);
3174 if (x
) (*x
) = (wxCoord
) rect
.width
;
3175 if (y
) (*y
) = (wxCoord
) rect
.height
;
3178 // Do something about metrics here
3181 if (externalLeading
) (*externalLeading
) = 0; // ??
3183 g_object_unref( G_OBJECT( layout
) );
3185 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3186 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3187 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3188 if (descent
) (*descent
) = font
->descent
;
3189 if (externalLeading
) (*externalLeading
) = 0; // ??
3193 void wxWindowGTK::SetFocus()
3195 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3199 // don't do anything if we already have focus
3205 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3207 gtk_widget_grab_focus (m_wxwindow
);
3212 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3214 if (!GTK_WIDGET_REALIZED(m_widget
))
3216 // we can't set the focus to the widget now so we remember that
3217 // it should be focused and will do it later, during the idle
3218 // time, as soon as we can
3219 wxLogTrace(TRACE_FOCUS
,
3220 _T("Delaying setting focus to %s(%s)"),
3221 GetClassInfo()->GetClassName(), GetLabel().c_str());
3223 g_delayedFocus
= this;
3227 wxLogTrace(TRACE_FOCUS
,
3228 _T("Setting focus to %s(%s)"),
3229 GetClassInfo()->GetClassName(), GetLabel().c_str());
3231 gtk_widget_grab_focus (m_widget
);
3234 else if (GTK_IS_CONTAINER(m_widget
))
3236 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3240 wxLogTrace(TRACE_FOCUS
,
3241 _T("Can't set focus to %s(%s)"),
3242 GetClassInfo()->GetClassName(), GetLabel().c_str());
3247 bool wxWindowGTK::AcceptsFocus() const
3249 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3252 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3254 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3256 wxWindowGTK
*oldParent
= m_parent
,
3257 *newParent
= (wxWindowGTK
*)newParentBase
;
3259 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3261 if ( !wxWindowBase::Reparent(newParent
) )
3264 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3266 /* prevent GTK from deleting the widget arbitrarily */
3267 gtk_widget_ref( m_widget
);
3271 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3274 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3278 /* insert GTK representation */
3279 (*(newParent
->m_insertCallback
))(newParent
, this);
3282 /* reverse: prevent GTK from deleting the widget arbitrarily */
3283 gtk_widget_unref( m_widget
);
3288 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3290 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3292 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3294 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3299 /* insert GTK representation */
3300 (*m_insertCallback
)(this, child
);
3303 void wxWindowGTK::Raise()
3305 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3307 if (!m_widget
->window
) return;
3309 gdk_window_raise( m_widget
->window
);
3312 void wxWindowGTK::Lower()
3314 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3316 if (!m_widget
->window
) return;
3318 gdk_window_lower( m_widget
->window
);
3321 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3323 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3325 if (cursor
== m_cursor
)
3329 wxapp_install_idle_handler();
3331 if (cursor
== wxNullCursor
)
3332 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3334 return wxWindowBase::SetCursor( cursor
);
3337 void wxWindowGTK::WarpPointer( int x
, int y
)
3339 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3341 // We provide this function ourselves as it is
3342 // missing in GDK (top of this file).
3344 GdkWindow
*window
= (GdkWindow
*) NULL
;
3346 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3348 window
= GetConnectWidget()->window
;
3351 gdk_window_warp_pointer( window
, x
, y
);
3355 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3357 if (!m_widget
) return;
3358 if (!m_widget
->window
) return;
3362 wxapp_install_idle_handler();
3364 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3368 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3369 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3373 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3374 m_clearRegion
.Clear();
3375 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3383 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3384 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3388 GdkRectangle gdk_rect
;
3389 gdk_rect
.x
= rect
->x
;
3390 gdk_rect
.y
= rect
->y
;
3391 gdk_rect
.width
= rect
->width
;
3392 gdk_rect
.height
= rect
->height
;
3393 gtk_widget_draw( m_widget
, &gdk_rect
);
3400 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3401 m_updateRegion
.Clear();
3402 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3406 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3414 GdkRectangle gdk_rect
;
3415 gdk_rect
.x
= rect
->x
;
3416 gdk_rect
.y
= rect
->y
;
3417 gdk_rect
.width
= rect
->width
;
3418 gdk_rect
.height
= rect
->height
;
3419 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3423 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3429 void wxWindowGTK::Update()
3434 void wxWindowGTK::GtkUpdate()
3437 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3438 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3441 if (!m_updateRegion
.IsEmpty())
3442 GtkSendPaintEvents();
3445 void wxWindowGTK::GtkSendPaintEvents()
3449 m_clearRegion
.Clear();
3450 m_updateRegion
.Clear();
3454 // widget to draw on
3455 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3457 // Clip to paint region in wxClientDC
3458 m_clipPaintRegion
= TRUE
;
3461 if (GetThemeEnabled())
3463 // find ancestor from which to steal background
3464 wxWindow
*parent
= GetParent();
3465 while (parent
&& !parent
->IsTopLevel())
3466 parent
= parent
->GetParent();
3468 parent
= (wxWindow
*)this;
3470 wxRegionIterator
upd( m_updateRegion
);
3474 rect
.x
= upd
.GetX();
3475 rect
.y
= upd
.GetY();
3476 rect
.width
= upd
.GetWidth();
3477 rect
.height
= upd
.GetHeight();
3479 gtk_paint_flat_box( parent
->m_widget
->style
,
3494 if (!m_clearRegion
.IsEmpty()) // Always send an erase event under GTK 1.2
3497 wxWindowDC
dc( (wxWindow
*)this );
3498 if (m_clearRegion
.IsEmpty())
3499 dc
.SetClippingRegion( m_updateRegion
);
3501 dc
.SetClippingRegion( m_clearRegion
);
3503 wxEraseEvent
erase_event( GetId(), &dc
);
3504 erase_event
.SetEventObject( this );
3506 if (!GetEventHandler()->ProcessEvent(erase_event
))
3511 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3512 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3514 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3516 wxRegionIterator
upd( m_clearRegion
);
3519 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3520 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3525 m_clearRegion
.Clear();
3528 wxNcPaintEvent
nc_paint_event( GetId() );
3529 nc_paint_event
.SetEventObject( this );
3530 GetEventHandler()->ProcessEvent( nc_paint_event
);
3532 wxPaintEvent
paint_event( GetId() );
3533 paint_event
.SetEventObject( this );
3534 GetEventHandler()->ProcessEvent( paint_event
);
3536 m_clipPaintRegion
= FALSE
;
3538 #ifndef __WXUNIVERSAL__
3540 // The following code will result in all window-less widgets
3541 // being redrawn because the wxWindows class is allowed to
3542 // paint over the window-less widgets.
3544 GList
*children
= pizza
->children
;
3547 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3548 children
= children
->next
;
3550 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3551 GTK_WIDGET_DRAWABLE (child
->widget
))
3553 // Get intersection of widget area and update region
3554 wxRegion
region( m_updateRegion
);
3556 GdkEventExpose gdk_event
;
3557 gdk_event
.type
= GDK_EXPOSE
;
3558 gdk_event
.window
= pizza
->bin_window
;
3559 gdk_event
.count
= 0;
3561 wxRegionIterator
upd( m_updateRegion
);
3565 rect
.x
= upd
.GetX();
3566 rect
.y
= upd
.GetY();
3567 rect
.width
= upd
.GetWidth();
3568 rect
.height
= upd
.GetHeight();
3570 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3572 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3582 m_updateRegion
.Clear();
3585 void wxWindowGTK::Clear()
3587 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3589 if (m_wxwindow
&& m_wxwindow
->window
)
3591 m_clearRegion
.Clear();
3592 wxSize
size( GetClientSize() );
3593 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3595 // Better do this in idle?
3601 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3603 wxWindowBase::DoSetToolTip(tip
);
3606 m_tooltip
->Apply( (wxWindow
*)this );
3609 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3611 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3613 #endif // wxUSE_TOOLTIPS
3615 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3617 GdkWindow
*window
= (GdkWindow
*) NULL
;
3619 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3621 window
= GetConnectWidget()->window
;
3625 // We need the pixel value e.g. for background clearing.
3626 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3630 // wxMSW doesn't clear the window here, either.
3631 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3637 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3639 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3641 if (!wxWindowBase::SetBackgroundColour(colour
))
3644 GdkWindow
*window
= (GdkWindow
*) NULL
;
3646 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3648 window
= GetConnectWidget()->window
;
3652 // indicate that a new style has been set
3653 // but it couldn't get applied as the
3654 // widget hasn't been realized yet.
3655 m_delayedBackgroundColour
= TRUE
;
3660 GtkSetBackgroundColour( colour
);
3666 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3668 GdkWindow
*window
= (GdkWindow
*) NULL
;
3670 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3672 window
= GetConnectWidget()->window
;
3679 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3681 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3683 if (!wxWindowBase::SetForegroundColour(colour
))
3685 // don't leave if the GTK widget has just
3687 if (!m_delayedForegroundColour
) return FALSE
;
3690 GdkWindow
*window
= (GdkWindow
*) NULL
;
3692 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3694 window
= GetConnectWidget()->window
;
3698 // indicate that a new style has been set
3699 // but it couldn't get applied as the
3700 // widget hasn't been realized yet.
3701 m_delayedForegroundColour
= TRUE
;
3705 GtkSetForegroundColour( colour
);
3711 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3715 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3717 // FIXME: no more klass in 2.0
3719 remake
->klass
= m_widgetStyle
->klass
;
3722 gtk_style_unref( m_widgetStyle
);
3723 m_widgetStyle
= remake
;
3727 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3730 def
= gtk_widget_get_default_style();
3732 m_widgetStyle
= gtk_style_copy( def
);
3734 // FIXME: no more klass in 2.0
3736 m_widgetStyle
->klass
= def
->klass
;
3740 return m_widgetStyle
;
3743 void wxWindowGTK::SetWidgetStyle()
3745 #if DISABLE_STYLE_IF_BROKEN_THEME
3746 if (m_widget
->style
->engine_data
)
3748 static bool s_warningPrinted
= FALSE
;
3749 if (!s_warningPrinted
)
3751 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3752 s_warningPrinted
= TRUE
;
3754 m_widgetStyle
= m_widget
->style
;
3759 GtkStyle
*style
= GetWidgetStyle();
3761 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3763 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3766 if (m_foregroundColour
.Ok())
3768 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3769 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3771 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3772 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3773 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3777 // Try to restore the gtk default style. This is still a little
3778 // oversimplified for what is probably really needed here for controls
3779 // other than buttons, but is better than not being able to (re)set a
3780 // control's foreground colour to *wxBLACK -- RL
3781 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3784 def
= gtk_widget_get_default_style();
3786 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3787 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3788 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3792 if (m_backgroundColour
.Ok())
3794 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3795 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3797 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3798 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3799 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3800 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3801 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3802 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3803 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3804 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3808 // Try to restore the gtk default style. This is still a little
3809 // oversimplified for what is probably really needed here for controls
3810 // other than buttons, but is better than not being able to (re)set a
3811 // control's background colour to default grey and means resetting a
3812 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3814 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3817 def
= gtk_widget_get_default_style();
3819 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3820 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3821 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3822 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3823 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3824 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3825 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3826 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3831 void wxWindowGTK::ApplyWidgetStyle()
3835 //-----------------------------------------------------------------------------
3836 // Pop-up menu stuff
3837 //-----------------------------------------------------------------------------
3839 #if wxUSE_MENUS_NATIVE
3842 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3844 *is_waiting
= FALSE
;
3847 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3849 menu
->SetInvokingWindow( win
);
3850 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3853 wxMenuItem
*menuitem
= node
->GetData();
3854 if (menuitem
->IsSubMenu())
3856 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3859 node
= node
->GetNext();
3863 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3864 // wxPopupMenuPositionCallback()
3866 // should be safe even in the MT case as the user can hardly popup 2 menus
3867 // simultaneously, can he?
3868 static gint gs_pop_x
= 0;
3869 static gint gs_pop_y
= 0;
3871 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3874 gboolean
* WXUNUSED(whatever
),
3876 gpointer
WXUNUSED(user_data
) )
3878 // ensure that the menu appears entirely on screen
3880 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3882 wxSize sizeScreen
= wxGetDisplaySize();
3884 gint xmax
= sizeScreen
.x
- req
.width
,
3885 ymax
= sizeScreen
.y
- req
.height
;
3887 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3888 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3891 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3893 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3895 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3897 SetInvokingWindow( menu
, this );
3903 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3905 bool is_waiting
= TRUE
;
3907 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3909 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3910 (gpointer
)&is_waiting
);
3913 GTK_MENU(menu
->m_menu
),
3914 (GtkWidget
*) NULL
, // parent menu shell
3915 (GtkWidget
*) NULL
, // parent menu item
3916 wxPopupMenuPositionCallback
, // function to position it
3917 NULL
, // client data
3918 0, // button used to activate it
3919 gs_timeLastClick
// the time of activation
3924 while (gtk_events_pending())
3925 gtk_main_iteration();
3931 #endif // wxUSE_MENUS_NATIVE
3933 #if wxUSE_DRAG_AND_DROP
3935 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3937 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3939 GtkWidget
*dnd_widget
= GetConnectWidget();
3941 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3943 if (m_dropTarget
) delete m_dropTarget
;
3944 m_dropTarget
= dropTarget
;
3946 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3949 #endif // wxUSE_DRAG_AND_DROP
3951 GtkWidget
* wxWindowGTK::GetConnectWidget()
3953 GtkWidget
*connect_widget
= m_widget
;
3954 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3956 return connect_widget
;
3959 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3962 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3964 return (window
== m_widget
->window
);
3967 bool wxWindowGTK::SetFont( const wxFont
&font
)
3969 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3971 if (!wxWindowBase::SetFont(font
))
3976 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3977 if ( sysbg
== m_backgroundColour
)
3979 m_backgroundColour
= wxNullColour
;
3981 m_backgroundColour
= sysbg
;
3991 void wxWindowGTK::DoCaptureMouse()
3993 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3995 GdkWindow
*window
= (GdkWindow
*) NULL
;
3997 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3999 window
= GetConnectWidget()->window
;
4001 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4003 wxCursor
* cursor
= & m_cursor
;
4005 cursor
= wxSTANDARD_CURSOR
;
4007 gdk_pointer_grab( window
, FALSE
,
4009 (GDK_BUTTON_PRESS_MASK
|
4010 GDK_BUTTON_RELEASE_MASK
|
4011 GDK_POINTER_MOTION_HINT_MASK
|
4012 GDK_POINTER_MOTION_MASK
),
4014 cursor
->GetCursor(),
4015 (guint32
)GDK_CURRENT_TIME
);
4016 g_captureWindow
= this;
4017 g_captureWindowHasMouse
= TRUE
;
4020 void wxWindowGTK::DoReleaseMouse()
4022 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4024 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4026 g_captureWindow
= (wxWindowGTK
*) NULL
;
4028 GdkWindow
*window
= (GdkWindow
*) NULL
;
4030 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4032 window
= GetConnectWidget()->window
;
4037 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4041 wxWindow
*wxWindowBase::GetCapture()
4043 return (wxWindow
*)g_captureWindow
;
4046 bool wxWindowGTK::IsRetained() const
4051 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4052 int range
, bool refresh
)
4054 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4056 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4058 m_hasScrolling
= TRUE
;
4060 if (orient
== wxHORIZONTAL
)
4062 float fpos
= (float)pos
;
4063 float frange
= (float)range
;
4064 float fthumb
= (float)thumbVisible
;
4065 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4066 if (fpos
< 0.0) fpos
= 0.0;
4068 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4069 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4071 SetScrollPos( orient
, pos
, refresh
);
4075 m_oldHorizontalPos
= fpos
;
4077 m_hAdjust
->lower
= 0.0;
4078 m_hAdjust
->upper
= frange
;
4079 m_hAdjust
->value
= fpos
;
4080 m_hAdjust
->step_increment
= 1.0;
4081 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4082 m_hAdjust
->page_size
= fthumb
;
4086 float fpos
= (float)pos
;
4087 float frange
= (float)range
;
4088 float fthumb
= (float)thumbVisible
;
4089 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4090 if (fpos
< 0.0) fpos
= 0.0;
4092 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4093 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4095 SetScrollPos( orient
, pos
, refresh
);
4099 m_oldVerticalPos
= fpos
;
4101 m_vAdjust
->lower
= 0.0;
4102 m_vAdjust
->upper
= frange
;
4103 m_vAdjust
->value
= fpos
;
4104 m_vAdjust
->step_increment
= 1.0;
4105 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4106 m_vAdjust
->page_size
= fthumb
;
4109 if (orient
== wxHORIZONTAL
)
4110 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4112 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4115 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4117 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4119 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4121 if (orient
== wxHORIZONTAL
)
4123 float fpos
= (float)pos
;
4124 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4125 if (fpos
< 0.0) fpos
= 0.0;
4126 m_oldHorizontalPos
= fpos
;
4128 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4129 m_hAdjust
->value
= fpos
;
4133 float fpos
= (float)pos
;
4134 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4135 if (fpos
< 0.0) fpos
= 0.0;
4136 m_oldVerticalPos
= fpos
;
4138 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4139 m_vAdjust
->value
= fpos
;
4142 if (m_wxwindow
->window
)
4144 if (orient
== wxHORIZONTAL
)
4146 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4147 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4149 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4151 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4152 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4156 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4157 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4159 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4161 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4162 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4167 int wxWindowGTK::GetScrollThumb( int orient
) const
4169 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4171 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4173 if (orient
== wxHORIZONTAL
)
4174 return (int)(m_hAdjust
->page_size
+0.5);
4176 return (int)(m_vAdjust
->page_size
+0.5);
4179 int wxWindowGTK::GetScrollPos( int orient
) const
4181 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4183 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4185 if (orient
== wxHORIZONTAL
)
4186 return (int)(m_hAdjust
->value
+0.5);
4188 return (int)(m_vAdjust
->value
+0.5);
4191 int wxWindowGTK::GetScrollRange( int orient
) const
4193 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4195 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4197 if (orient
== wxHORIZONTAL
)
4198 return (int)(m_hAdjust
->upper
+0.5);
4200 return (int)(m_vAdjust
->upper
+0.5);
4203 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4205 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4207 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4209 // No scrolling requested.
4210 if ((dx
== 0) && (dy
== 0)) return;
4213 if (!m_updateRegion
.IsEmpty())
4215 m_updateRegion
.Offset( dx
, dy
);
4219 GetClientSize( &cw
, &ch
);
4220 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4223 if (!m_clearRegion
.IsEmpty())
4225 m_clearRegion
.Offset( dx
, dy
);
4229 GetClientSize( &cw
, &ch
);
4230 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4232 m_clipPaintRegion
= TRUE
;
4234 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4236 m_clipPaintRegion
= FALSE
;
4239 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4241 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4242 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4249 // Find the wxWindow at the current mouse position, also returning the mouse
4251 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4253 pt
= wxGetMousePosition();
4254 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4258 // Get the current mouse position.
4259 wxPoint
wxGetMousePosition()
4261 /* This crashes when used within wxHelpContext,
4262 so we have to use the X-specific implementation below.
4264 GdkModifierType *mask;
4265 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4267 return wxPoint(x, y);
4271 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4273 return wxPoint(-999, -999);
4275 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4276 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4277 Window rootReturn
, childReturn
;
4278 int rootX
, rootY
, winX
, winY
;
4279 unsigned int maskReturn
;
4281 XQueryPointer (display
,
4285 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4286 return wxPoint(rootX
, rootY
);
4290 // ----------------------------------------------------------------------------
4292 // ----------------------------------------------------------------------------
4294 class wxWinModule
: public wxModule
4301 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4304 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4306 bool wxWinModule::OnInit()
4308 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4309 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4314 void wxWinModule::OnExit()
4317 gdk_gc_unref( g_eraseGC
);