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 #include <pango/pangox.h>
75 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
77 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
87 extern GtkContainerClass
*pizza_parent_class
;
90 //-----------------------------------------------------------------------------
91 // documentation on internals
92 //-----------------------------------------------------------------------------
95 I have been asked several times about writing some documentation about
96 the GTK port of wxWindows, especially its internal structures. Obviously,
97 you cannot understand wxGTK without knowing a little about the GTK, but
98 some more information about what the wxWindow, which is the base class
99 for all other window classes, does seems required as well.
103 What does wxWindow do? It contains the common interface for the following
104 jobs of its descendants:
106 1) Define the rudimentary behaviour common to all window classes, such as
107 resizing, intercepting user input (so as to make it possible to use these
108 events for special purposes in a derived class), window names etc.
110 2) Provide the possibility to contain and manage children, if the derived
111 class is allowed to contain children, which holds true for those window
112 classes which do not display a native GTK widget. To name them, these
113 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
114 work classes are a special case and are handled a bit differently from
115 the rest. The same holds true for the wxNotebook class.
117 3) Provide the possibility to draw into a client area of a window. This,
118 too, only holds true for classes that do not display a native GTK widget
121 4) Provide the entire mechanism for scrolling widgets. This actual inter-
122 face for this is usually in wxScrolledWindow, but the GTK implementation
125 5) A multitude of helper or extra methods for special purposes, such as
126 Drag'n'Drop, managing validators etc.
128 6) Display a border (sunken, raised, simple or none).
130 Normally one might expect, that one wxWindows window would always correspond
131 to one GTK widget. Under GTK, there is no such allround widget that has all
132 the functionality. Moreover, the GTK defines a client area as a different
133 widget from the actual widget you are handling. Last but not least some
134 special classes (e.g. wxFrame) handle different categories of widgets and
135 still have the possibility to draw something in the client area.
136 It was therefore required to write a special purpose GTK widget, that would
137 represent a client area in the sense of wxWindows capable to do the jobs
138 2), 3) and 4). I have written this class and it resides in win_gtk.c of
141 All windows must have a widget, with which they interact with other under-
142 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
143 thw wxWindow class has a member variable called m_widget which holds a
144 pointer to this widget. When the window class represents a GTK native widget,
145 this is (in most cases) the only GTK widget the class manages. E.g. the
146 wxStatitText class handles only a GtkLabel widget a pointer to which you
147 can find in m_widget (defined in wxWindow)
149 When the class has a client area for drawing into and for containing children
150 it has to handle the client area widget (of the type GtkPizza, defined in
151 win_gtk.c), but there could be any number of widgets, handled by a class
152 The common rule for all windows is only, that the widget that interacts with
153 the rest of GTK must be referenced in m_widget and all other widgets must be
154 children of this widget on the GTK level. The top-most widget, which also
155 represents the client area, must be in the m_wxwindow field and must be of
158 As I said, the window classes that display a GTK native widget only have
159 one widget, so in the case of e.g. the wxButton class m_widget holds a
160 pointer to a GtkButton widget. But windows with client areas (for drawing
161 and children) have a m_widget field that is a pointer to a GtkScrolled-
162 Window and a m_wxwindow field that is pointer to a GtkPizza and this
163 one is (in the GTK sense) a child of the GtkScrolledWindow.
165 If the m_wxwindow field is set, then all input to this widget is inter-
166 cepted and sent to the wxWindows class. If not, all input to the widget
167 that gets pointed to by m_widget gets intercepted and sent to the class.
171 The design of scrolling in wxWindows is markedly different from that offered
172 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
173 clicking on a scrollbar belonging to scrolled window will inevitably move
174 the window. In wxWindows, the scrollbar will only emit an event, send this
175 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
176 which actually moves the window and its subchildren. Note that GtkPizza
177 memorizes how much it has been scrolled but that wxWindows forgets this
178 so that the two coordinates systems have to be kept in synch. This is done
179 in various places using the pizza->xoffset and pizza->yoffset values.
183 Singularily the most broken code in GTK is the code that is supposes to
184 inform subwindows (child windows) about new positions. Very often, duplicate
185 events are sent without changes in size or position, equally often no
186 events are sent at all (All this is due to a bug in the GtkContainer code
187 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
188 GTK's own system and it simply waits for size events for toplevel windows
189 and then iterates down the respective size events to all window. This has
190 the disadvantage, that windows might get size events before the GTK widget
191 actually has the reported size. This doesn't normally pose any problem, but
192 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
193 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
194 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
195 window that is used for OpenGl output really has that size (as reported by
200 If someone at some point of time feels the immense desire to have a look at,
201 change or attempt to optimse the Refresh() logic, this person will need an
202 intimate understanding of what a "draw" and what an "expose" events are and
203 what there are used for, in particular when used in connection with GTK's
204 own windowless widgets. Beware.
208 Cursors, too, have been a constant source of pleasure. The main difficulty
209 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
210 for the parent. To prevent this from doing too much harm, I use idle time
211 to set the cursor over and over again, starting from the toplevel windows
212 and ending with the youngest generation (speaking of parent and child windows).
213 Also don't forget that cursors (like much else) are connected to GdkWindows,
214 not GtkWidgets and that the "window" field of a GtkWidget might very well
215 point to the GdkWindow of the parent widget (-> "window less widget") and
216 that the two obviously have very different meanings.
220 //-----------------------------------------------------------------------------
222 //-----------------------------------------------------------------------------
224 extern wxList wxPendingDelete
;
225 extern bool g_blockEventsOnDrag
;
226 extern bool g_blockEventsOnScroll
;
227 extern wxCursor g_globalCursor
;
229 static GdkGC
*g_eraseGC
= NULL
;
231 // mouse capture state: the window which has it and if the mouse is currently
233 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
234 static bool g_captureWindowHasMouse
= FALSE
;
236 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
238 // the last window which had the focus - this is normally never NULL (except
239 // if we never had focus at all) as even when g_focusWindow is NULL it still
240 // keeps its previous value
241 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
243 // the frame that is currently active (i.e. its child has focus). It is
244 // used to generate wxActivateEvents
245 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
246 static bool g_activeFrameLostFocus
= FALSE
;
248 // If a window get the focus set but has not been realized
249 // yet, defer setting the focus to idle time.
250 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
252 // if we detect that the app has got/lost the focus, we set this variable to
253 // either TRUE or FALSE and an activate event will be sent during the next
254 // OnIdle() call and it is reset to -1: this value means that we shouldn't
255 // send any activate events at all
256 static int g_sendActivateEvent
= -1;
258 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
259 the last click here */
260 static guint32 gs_timeLastClick
= 0;
262 extern bool g_mainThreadLocked
;
264 //-----------------------------------------------------------------------------
266 //-----------------------------------------------------------------------------
269 #define DISABLE_STYLE_IF_BROKEN_THEME 0
275 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
277 # define DEBUG_MAIN_THREAD
280 #define DEBUG_MAIN_THREAD
283 // the trace mask used for the focus debugging messages
284 #define TRACE_FOCUS _T("focus")
286 //-----------------------------------------------------------------------------
287 // missing gdk functions
288 //-----------------------------------------------------------------------------
291 gdk_window_warp_pointer (GdkWindow
*window
,
296 GdkWindowPrivate
*priv
;
300 window
= GDK_ROOT_PARENT();
303 if (!GDK_WINDOW_DESTROYED(window
))
305 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
306 None
, /* not source window -> move from anywhere */
307 GDK_WINDOW_XID(window
), /* dest window */
308 0, 0, 0, 0, /* not source window -> move from anywhere */
312 priv
= (GdkWindowPrivate
*) window
;
314 if (!priv
->destroyed
)
316 XWarpPointer (priv
->xdisplay
,
317 None
, /* not source window -> move from anywhere */
318 priv
->xwindow
, /* dest window */
319 0, 0, 0, 0, /* not source window -> move from anywhere */
325 //-----------------------------------------------------------------------------
327 //-----------------------------------------------------------------------------
329 extern void wxapp_install_idle_handler();
330 extern bool g_isIdle
;
332 //-----------------------------------------------------------------------------
333 // local code (see below)
334 //-----------------------------------------------------------------------------
336 // returns the child of win which currently has focus or NULL if not found
338 // Note: can't be static, needed by textctrl.cpp.
339 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
341 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
343 return (wxWindow
*)NULL
;
345 if ( winFocus
== win
)
346 return (wxWindow
*)win
;
348 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
350 node
= node
->GetNext() )
352 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
357 return (wxWindow
*)NULL
;
360 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
362 // wxUniversal widgets draw the borders and scrollbars themselves
363 #ifndef __WXUNIVERSAL__
370 if (win
->m_hasScrolling
)
372 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
374 GtkRequisition vscroll_req
;
375 vscroll_req
.width
= 2;
376 vscroll_req
.height
= 2;
377 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
378 (scroll_window
->vscrollbar
, &vscroll_req
);
380 GtkRequisition hscroll_req
;
381 hscroll_req
.width
= 2;
382 hscroll_req
.height
= 2;
383 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
384 (scroll_window
->hscrollbar
, &hscroll_req
);
386 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
388 if (scroll_window
->vscrollbar_visible
)
390 dw
+= vscroll_req
.width
;
391 dw
+= scroll_class
->scrollbar_spacing
;
394 if (scroll_window
->hscrollbar_visible
)
396 dh
+= hscroll_req
.height
;
397 dh
+= scroll_class
->scrollbar_spacing
;
403 if (GTK_WIDGET_NO_WINDOW (widget
))
405 dx
+= widget
->allocation
.x
;
406 dy
+= widget
->allocation
.y
;
409 if (win
->HasFlag(wxRAISED_BORDER
))
411 gtk_draw_shadow( widget
->style
,
416 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
420 if (win
->HasFlag(wxSUNKEN_BORDER
))
422 gtk_draw_shadow( widget
->style
,
427 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
431 if (win
->HasFlag(wxSIMPLE_BORDER
))
434 gc
= gdk_gc_new( widget
->window
);
435 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
436 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
438 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
442 #endif // __WXUNIVERSAL__
445 //-----------------------------------------------------------------------------
446 // "expose_event" of m_widget
447 //-----------------------------------------------------------------------------
449 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
451 if (gdk_event
->count
> 0) return FALSE
;
453 draw_frame( widget
, win
);
457 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
463 //-----------------------------------------------------------------------------
464 // "draw" of m_widget
465 //-----------------------------------------------------------------------------
469 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
471 draw_frame( widget
, win
);
476 //-----------------------------------------------------------------------------
477 // "size_request" of m_widget
478 //-----------------------------------------------------------------------------
480 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
483 win
->GetSize( &w
, &h
);
487 requisition
->height
= h
;
488 requisition
->width
= w
;
491 //-----------------------------------------------------------------------------
492 // "expose_event" of m_wxwindow
493 //-----------------------------------------------------------------------------
495 static int gtk_window_expose_callback( GtkWidget
*widget
,
496 GdkEventExpose
*gdk_event
,
502 wxapp_install_idle_handler();
505 // This callback gets called in drawing-idle time under
506 // GTK 2.0, so we don't need to defer anything to idle
509 GtkPizza
*pizza
= GTK_PIZZA( widget
);
510 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
515 wxPrintf( wxT("OnExpose from ") );
516 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
517 wxPrintf( win
->GetClassInfo()->GetClassName() );
518 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
519 (int)gdk_event
->area
.y
,
520 (int)gdk_event
->area
.width
,
521 (int)gdk_event
->area
.height
);
525 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
527 win
->GtkSendPaintEvents();
530 // Let parent window draw window less widgets
531 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
533 // This gets called immediately after an expose event
534 // under GTK 1.2 so we collect the calls and wait for
535 // the idle handler to pick things up.
537 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
539 gdk_event
->area
.width
,
540 gdk_event
->area
.height
);
541 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
543 gdk_event
->area
.width
,
544 gdk_event
->area
.height
);
546 // Actual redrawing takes place in idle time.
553 //-----------------------------------------------------------------------------
554 // "event" of m_wxwindow
555 //-----------------------------------------------------------------------------
557 // GTK thinks it is clever and filters out a certain amount of "unneeded"
558 // expose events. We need them, of course, so we override the main event
559 // procedure in GtkWidget by giving our own handler for all system events.
560 // There, we look for expose events ourselves whereas all other events are
563 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
564 GdkEventExpose
*event
,
567 if (event
->type
== GDK_EXPOSE
)
569 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
576 //-----------------------------------------------------------------------------
577 // "draw" of m_wxwindow
578 //-----------------------------------------------------------------------------
582 // This callback is a complete replacement of the gtk_pizza_draw() function,
583 // which is disabled.
585 static void gtk_window_draw_callback( GtkWidget
*widget
,
592 wxapp_install_idle_handler();
594 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
595 // there are no child windows.
596 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
597 (win
->GetChildren().GetCount() == 0))
605 wxPrintf( wxT("OnDraw from ") );
606 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
607 wxPrintf( win
->GetClassInfo()->GetClassName() );
608 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
615 #ifndef __WXUNIVERSAL__
616 GtkPizza
*pizza
= GTK_PIZZA (widget
);
618 if (win
->GetThemeEnabled())
620 wxWindow
*parent
= win
->GetParent();
621 while (parent
&& !parent
->IsTopLevel())
622 parent
= parent
->GetParent();
626 gtk_paint_flat_box (parent
->m_widget
->style
,
637 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
638 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
640 // Update immediately, not in idle time.
643 #ifndef __WXUNIVERSAL__
644 // Redraw child widgets
645 GList
*children
= pizza
->children
;
648 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
649 children
= children
->next
;
651 GdkRectangle child_area
;
652 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
654 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
662 //-----------------------------------------------------------------------------
663 // "key_press_event" from any window
664 //-----------------------------------------------------------------------------
666 // set WXTRACE to this to see the key event codes on the console
667 #define TRACE_KEYS _T("keyevent")
669 // translates an X key symbol to WXK_XXX value
671 // if isChar is true it means that the value returned will be used for EVT_CHAR
672 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
673 // for example, while if it is false it means that the value is going to be
674 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
676 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
682 // Shift, Control and Alt don't generate the CHAR events at all
685 key_code
= isChar
? 0 : WXK_SHIFT
;
689 key_code
= isChar
? 0 : WXK_CONTROL
;
697 key_code
= isChar
? 0 : WXK_ALT
;
700 // neither do the toggle modifies
701 case GDK_Scroll_Lock
:
702 key_code
= isChar
? 0 : WXK_SCROLL
;
706 key_code
= isChar
? 0 : WXK_CAPITAL
;
710 key_code
= isChar
? 0 : WXK_NUMLOCK
;
714 // various other special keys
727 case GDK_ISO_Left_Tab
:
734 key_code
= WXK_RETURN
;
738 key_code
= WXK_CLEAR
;
742 key_code
= WXK_PAUSE
;
746 key_code
= WXK_SELECT
;
750 key_code
= WXK_PRINT
;
754 key_code
= WXK_EXECUTE
;
758 key_code
= WXK_ESCAPE
;
761 // cursor and other extended keyboard keys
763 key_code
= WXK_DELETE
;
779 key_code
= WXK_RIGHT
;
786 case GDK_Prior
: // == GDK_Page_Up
787 key_code
= WXK_PRIOR
;
790 case GDK_Next
: // == GDK_Page_Down
803 key_code
= WXK_INSERT
;
818 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
822 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
826 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
830 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
834 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
838 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
842 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
846 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
850 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
854 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
858 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
862 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
866 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
869 case GDK_KP_Prior
: // == GDK_KP_Page_Up
870 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
873 case GDK_KP_Next
: // == GDK_KP_Page_Down
874 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
878 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
882 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
886 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
890 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
894 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
897 case GDK_KP_Multiply
:
898 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
902 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
905 case GDK_KP_Separator
:
906 // FIXME: what is this?
907 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
910 case GDK_KP_Subtract
:
911 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
915 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
919 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
936 key_code
= WXK_F1
+ keysym
- GDK_F1
;
946 static inline bool wxIsAsciiKeysym(KeySym ks
)
952 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
954 GdkEventKey
*gdk_event
)
956 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
957 // but only event->keyval which is quite useless to us, so remember
958 // the last character from GDK_KEY_PRESS and reuse it as last resort
960 // NB: should be MT-safe as we're always called from the main thread only
965 } s_lastKeyPress
= { 0, 0 };
967 KeySym keysym
= gdk_event
->keyval
;
969 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
970 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
974 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
978 // do we have the translation or is it a plain ASCII character?
979 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
981 // we should use keysym if it is ASCII as X does some translations
982 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
983 // which we don't want here (but which we do use for OnChar())
984 if ( !wxIsAsciiKeysym(keysym
) )
986 keysym
= (KeySym
)gdk_event
->string
[0];
989 // we want to always get the same key code when the same key is
990 // pressed regardless of the state of the modifies, i.e. on a
991 // standard US keyboard pressing '5' or '%' ('5' key with
992 // Shift) should result in the same key code in OnKeyDown():
993 // '5' (although OnChar() will get either '5' or '%').
995 // to do it we first translate keysym to keycode (== scan code)
996 // and then back but always using the lower register
997 Display
*dpy
= (Display
*)wxGetDisplay();
998 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1000 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1002 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1004 // use the normalized, i.e. lower register, keysym if we've
1006 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1008 // as explained above, we want to have lower register key codes
1009 // normally but for the letter keys we want to have the upper ones
1011 // NB: don't use XConvertCase() here, we want to do it for letters
1013 key_code
= toupper(key_code
);
1015 else // non ASCII key, what to do?
1017 // by default, ignore it
1020 // but if we have cached information from the last KEY_PRESS
1021 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1024 if ( keysym
== s_lastKeyPress
.keysym
)
1026 key_code
= s_lastKeyPress
.keycode
;
1031 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1033 // remember it to be reused for KEY_UP event later
1034 s_lastKeyPress
.keysym
= keysym
;
1035 s_lastKeyPress
.keycode
= key_code
;
1039 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1041 // sending unknown key events doesn't really make sense
1045 // now fill all the other fields
1048 GdkModifierType state
;
1049 if (gdk_event
->window
)
1050 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1052 event
.SetTimestamp( gdk_event
->time
);
1053 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1054 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1055 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1056 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1057 event
.m_keyCode
= key_code
;
1058 event
.m_scanCode
= gdk_event
->keyval
;
1059 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1060 event
.m_rawFlags
= 0;
1063 event
.SetEventObject( win
);
1069 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1070 GdkEventKey
*gdk_event
,
1076 wxapp_install_idle_handler();
1080 if (g_blockEventsOnDrag
)
1084 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1085 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1087 // unknown key pressed, ignore (the event would be useless anyhow)
1091 // Emit KEY_DOWN event
1092 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1097 wxWindowGTK
*ancestor
= win
;
1100 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1103 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1104 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1107 if (ancestor
->IsTopLevel())
1109 ancestor
= ancestor
->GetParent();
1112 #endif // wxUSE_ACCEL
1114 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1115 // will only be sent if it is not in an accelerator table.
1119 KeySym keysym
= gdk_event
->keyval
;
1121 // In GTK 2.0, we need to hand over the key event to an input method
1122 // and the IM will emit a "commit" event containing the actual utf8
1123 // character. In that case the EVT_CHAR events will be sent from
1124 // there. But only do it this way for non-KeySym keys.
1125 key_code
= wxTranslateKeySymToWXKey(gdk_event
->keyval
, FALSE
/* isChar */);
1126 if ( !key_code
&& win
->m_imContext
)
1128 gtk_im_context_filter_keypress ( (GtkIMContext
*) win
->m_imContext
, gdk_event
);
1134 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1135 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1138 if ( gdk_event
->length
== 1 )
1140 key_code
= (unsigned char)gdk_event
->string
[0];
1142 else if ( wxIsAsciiKeysym(keysym
) )
1145 key_code
= (unsigned char)keysym
;
1151 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1153 event
.m_keyCode
= key_code
;
1155 // Implement OnCharHook by checking ancesteror top level windows
1156 wxWindow
*parent
= win
;
1157 while (parent
&& !parent
->IsTopLevel())
1158 parent
= parent
->GetParent();
1161 event
.SetEventType( wxEVT_CHAR_HOOK
);
1162 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1167 event
.SetEventType(wxEVT_CHAR
);
1168 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1174 // win is a control: tab can be propagated up
1176 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1177 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1178 // have this style, yet choose not to process this particular TAB in which
1179 // case TAB must still work as a navigational character
1181 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1183 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1185 wxNavigationKeyEvent new_event
;
1186 new_event
.SetEventObject( win
->GetParent() );
1187 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1188 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1189 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1190 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1191 new_event
.SetCurrentFocus( win
);
1192 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1195 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1197 (gdk_event
->keyval
== GDK_Escape
) )
1199 // however only do it if we have a Cancel button in the dialog,
1200 // otherwise the user code may get confused by the events from a
1201 // non-existing button and, worse, a wxButton might get button event
1202 // from another button which is not really expected
1203 wxWindow
*winForCancel
= win
,
1205 while ( winForCancel
)
1207 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1210 // found a cancel button
1214 if ( winForCancel
->IsTopLevel() )
1216 // no need to look further
1220 // maybe our parent has a cancel button?
1221 winForCancel
= winForCancel
->GetParent();
1226 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1227 event
.SetEventObject(btnCancel
);
1228 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1234 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1242 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1248 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1251 event
.m_uniChar
= g_utf8_get_char( str
);
1253 // Backward compatible for ISO-8859
1254 if (event
.m_uniChar
< 256)
1255 event
.m_keyCode
= event
.m_uniChar
;
1257 gunichar uniChar
= g_utf8_get_char( str
);
1258 // We cannot handle Unicode in non-Unicode mode
1259 if (uniChar
> 255) return;
1261 event
.m_keyCode
= uniChar
;
1265 // TODO: We still need to set all the extra attributes of the
1266 // event, modifiers and such...
1269 // Implement OnCharHook by checking ancestor top level windows
1270 wxWindow
*parent
= window
;
1271 while (parent
&& !parent
->IsTopLevel())
1272 parent
= parent
->GetParent();
1275 event
.SetEventType( wxEVT_CHAR_HOOK
);
1276 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1281 event
.SetEventType(wxEVT_CHAR
);
1282 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1288 //-----------------------------------------------------------------------------
1289 // "key_release_event" from any window
1290 //-----------------------------------------------------------------------------
1292 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1293 GdkEventKey
*gdk_event
,
1299 wxapp_install_idle_handler();
1304 if (g_blockEventsOnDrag
)
1307 wxKeyEvent
event( wxEVT_KEY_UP
);
1308 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1310 // unknown key pressed, ignore (the event would be useless anyhow
1314 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1317 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1321 // ============================================================================
1323 // ============================================================================
1325 // ----------------------------------------------------------------------------
1326 // mouse event processing helpers
1327 // ----------------------------------------------------------------------------
1329 // init wxMouseEvent with the info from gdk_event
1331 // NB: this has to be a macro as gdk_event type is different for different
1332 // events we're used with
1333 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1334 /* wxMouseEvent& */ event, \
1335 /* GdkEventXXX * */ gdk_event) \
1337 event.SetTimestamp( gdk_event->time ); \
1338 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1339 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1340 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1341 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1342 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1343 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1344 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1345 if (event.GetEventType()==wxEVT_MOUSEWHEEL) \
1347 if (((GdkEventButton*)gdk_event)->button == 4) \
1348 event.m_wheelRotation = 120; \
1349 else if (((GdkEventButton*)gdk_event)->button == 5) \
1350 event.m_wheelRotation = -120; \
1353 wxPoint pt = win->GetClientAreaOrigin(); \
1354 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1355 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1357 event.SetEventObject( win ); \
1358 event.SetId( win->GetId() ); \
1359 event.SetTimestamp( gdk_event->time ); \
1362 static void AdjustEventButtonState(wxMouseEvent& event)
1364 // GDK reports the old state of the button for a button press event, but
1365 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1366 // for a LEFT_DOWN event, not FALSE, so we will invert
1367 // left/right/middleDown for the corresponding click events
1369 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1370 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1371 (event
.GetEventType() == wxEVT_LEFT_UP
))
1373 event
.m_leftDown
= !event
.m_leftDown
;
1377 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1378 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1379 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1381 event
.m_middleDown
= !event
.m_middleDown
;
1385 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1386 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1387 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1389 event
.m_rightDown
= !event
.m_rightDown
;
1394 // find the window to send the mouse event too
1396 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1401 if (win
->m_wxwindow
)
1403 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1404 xx
+= pizza
->xoffset
;
1405 yy
+= pizza
->yoffset
;
1408 wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
1411 wxWindowGTK
*child
= node
->GetData();
1413 node
= node
->GetNext();
1414 if (!child
->IsShown())
1417 if (child
->IsTransparentForMouse())
1419 // wxStaticBox is transparent in the box itself
1420 int xx1
= child
->m_x
;
1421 int yy1
= child
->m_y
;
1422 int xx2
= child
->m_x
+ child
->m_width
;
1423 int yy2
= child
->m_y
+ child
->m_height
;
1426 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1428 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1430 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1432 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1443 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1444 (child
->m_x
<= xx
) &&
1445 (child
->m_y
<= yy
) &&
1446 (child
->m_x
+child
->m_width
>= xx
) &&
1447 (child
->m_y
+child
->m_height
>= yy
))
1460 //-----------------------------------------------------------------------------
1461 // "button_press_event"
1462 //-----------------------------------------------------------------------------
1464 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1465 GdkEventButton
*gdk_event
,
1471 wxapp_install_idle_handler();
1474 wxPrintf( wxT("1) OnButtonPress from ") );
1475 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1476 wxPrintf( win->GetClassInfo()->GetClassName() );
1477 wxPrintf( wxT(".\n") );
1479 if (!win
->m_hasVMT
) return FALSE
;
1480 if (g_blockEventsOnDrag
) return TRUE
;
1481 if (g_blockEventsOnScroll
) return TRUE
;
1483 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1485 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1487 gtk_widget_grab_focus( win
->m_wxwindow
);
1489 wxPrintf( wxT("GrabFocus from ") );
1490 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1491 wxPrintf( win->GetClassInfo()->GetClassName() );
1492 wxPrintf( wxT(".\n") );
1496 // GDK sends surplus button down event
1497 // before a double click event. We
1498 // need to filter these out.
1499 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1501 GdkEvent
*peek_event
= gdk_event_peek();
1504 if (peek_event
->type
== GDK_2BUTTON_PRESS
)
1506 gdk_event_free( peek_event
);
1511 gdk_event_free( peek_event
);
1516 wxEventType event_type
= wxEVT_NULL
;
1518 if (gdk_event
->button
== 1)
1520 switch (gdk_event
->type
)
1522 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1523 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1527 else if (gdk_event
->button
== 2)
1529 switch (gdk_event
->type
)
1531 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1532 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1536 else if (gdk_event
->button
== 3)
1538 switch (gdk_event
->type
)
1540 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1541 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1545 else if (gdk_event
->button
== 4)
1547 switch (gdk_event
->type
)
1549 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1553 else if (gdk_event
->button
== 5)
1555 switch (gdk_event
->type
)
1557 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1562 if ( event_type
== wxEVT_NULL
)
1564 // unknown mouse button or click type
1568 wxMouseEvent
event( event_type
);
1569 InitMouseEvent( win
, event
, gdk_event
);
1571 AdjustEventButtonState(event
);
1573 // wxListBox actually get mouse events from the item, so we need to give it
1574 // a chance to correct this
1575 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1577 // find the correct window to send the event too: it may be a different one
1578 // from the one which got it at GTK+ level because some control don't have
1579 // their own X window and thus cannot get any events.
1580 if ( !g_captureWindow
)
1581 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1583 gs_timeLastClick
= gdk_event
->time
;
1586 wxPrintf( wxT("2) OnButtonPress from ") );
1587 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1588 wxPrintf( win->GetClassInfo()->GetClassName() );
1589 wxPrintf( wxT(".\n") );
1593 if (event_type
== wxEVT_LEFT_DCLICK
)
1595 // GTK 1.2 crashes when intercepting double
1596 // click events from both wxSpinButton and
1598 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1600 // Just disable this event for now.
1606 if (win
->GetEventHandler()->ProcessEvent( event
))
1608 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1615 //-----------------------------------------------------------------------------
1616 // "button_release_event"
1617 //-----------------------------------------------------------------------------
1619 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1620 GdkEventButton
*gdk_event
,
1626 wxapp_install_idle_handler();
1628 if (!win
->m_hasVMT
) return FALSE
;
1629 if (g_blockEventsOnDrag
) return FALSE
;
1630 if (g_blockEventsOnScroll
) return FALSE
;
1632 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1634 wxEventType event_type
= wxEVT_NULL
;
1636 switch (gdk_event
->button
)
1639 event_type
= wxEVT_LEFT_UP
;
1643 event_type
= wxEVT_MIDDLE_UP
;
1647 event_type
= wxEVT_RIGHT_UP
;
1651 // unknwon button, don't process
1655 wxMouseEvent
event( event_type
);
1656 InitMouseEvent( win
, event
, gdk_event
);
1658 AdjustEventButtonState(event
);
1660 // same wxListBox hack as above
1661 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1663 if ( event_type
== wxEVT_RIGHT_UP
)
1665 // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
1668 // (a) it's a command event and so is propagated to the parent
1669 // (b) under MSW it can be generated from kbd too
1670 // (c) it uses screen coords (because of (a))
1671 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1673 win
->ClientToScreen(event
.GetPosition()));
1674 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1677 if ( !g_captureWindow
)
1678 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1680 if (win
->GetEventHandler()->ProcessEvent( event
))
1682 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1689 //-----------------------------------------------------------------------------
1690 // "motion_notify_event"
1691 //-----------------------------------------------------------------------------
1693 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1694 GdkEventMotion
*gdk_event
,
1700 wxapp_install_idle_handler();
1702 if (!win
->m_hasVMT
) return FALSE
;
1703 if (g_blockEventsOnDrag
) return FALSE
;
1704 if (g_blockEventsOnScroll
) return FALSE
;
1706 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1708 if (gdk_event
->is_hint
)
1712 GdkModifierType state
;
1713 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1719 printf( "OnMotion from " );
1720 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1721 printf( win->GetClassInfo()->GetClassName() );
1725 wxMouseEvent
event( wxEVT_MOTION
);
1726 InitMouseEvent(win
, event
, gdk_event
);
1728 if ( g_captureWindow
)
1730 // synthetize a mouse enter or leave event if needed
1731 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1732 // This seems to be necessary and actually been added to
1733 // GDK itself in version 2.0.X
1736 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1737 if ( hasMouse
!= g_captureWindowHasMouse
)
1739 // the mouse changed window
1740 g_captureWindowHasMouse
= hasMouse
;
1742 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1743 : wxEVT_LEAVE_WINDOW
);
1744 InitMouseEvent(win
, event
, gdk_event
);
1745 event
.SetEventObject(win
);
1746 win
->GetEventHandler()->ProcessEvent(event
);
1751 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1754 if (win
->GetEventHandler()->ProcessEvent( event
))
1756 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1763 //-----------------------------------------------------------------------------
1765 //-----------------------------------------------------------------------------
1767 // send the wxChildFocusEvent and wxFocusEvent, common code of
1768 // gtk_window_focus_in_callback() and SetFocus()
1769 static bool DoSendFocusEvents(wxWindow
*win
)
1771 // Notify the parent keeping track of focus for the kbd navigation
1772 // purposes that we got it.
1773 wxChildFocusEvent
eventChildFocus(win
);
1774 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1776 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1777 eventFocus
.SetEventObject(win
);
1779 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1782 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1783 GdkEvent
*WXUNUSED(event
),
1789 wxapp_install_idle_handler();
1791 if (!win
->m_hasVMT
) return FALSE
;
1792 if (g_blockEventsOnDrag
) return FALSE
;
1794 switch ( g_sendActivateEvent
)
1797 // we've got focus from outside, synthetize wxActivateEvent
1798 g_sendActivateEvent
= 1;
1802 // another our window just lost focus, it was already ours before
1803 // - don't send any wxActivateEvent
1804 g_sendActivateEvent
= -1;
1809 g_focusWindow
= win
;
1811 wxLogTrace(TRACE_FOCUS
,
1812 _T("%s: focus in"), win
->GetName().c_str());
1816 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1820 // caret needs to be informed about focus change
1821 wxCaret
*caret
= win
->GetCaret();
1824 caret
->OnSetFocus();
1826 #endif // wxUSE_CARET
1828 g_activeFrameLostFocus
= FALSE
;
1830 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1831 if ( active
!= g_activeFrame
)
1833 if ( g_activeFrame
)
1835 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1836 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1837 event
.SetEventObject(g_activeFrame
);
1838 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1841 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1842 g_activeFrame
= active
;
1843 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1844 event
.SetEventObject(g_activeFrame
);
1845 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1847 // Don't send focus events in addition to activate
1848 // if (win == g_activeFrame)
1852 // does the window itself think that it has the focus?
1853 if ( !win
->m_hasFocus
)
1855 // not yet, notify it
1856 win
->m_hasFocus
= TRUE
;
1858 if ( DoSendFocusEvents(win
) )
1860 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1868 //-----------------------------------------------------------------------------
1869 // "focus_out_event"
1870 //-----------------------------------------------------------------------------
1872 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1877 wxapp_install_idle_handler();
1879 if (!win
->m_hasVMT
) return FALSE
;
1880 if (g_blockEventsOnDrag
) return FALSE
;
1882 wxLogTrace( TRACE_FOCUS
,
1883 _T("%s: focus out"), win
->GetName().c_str() );
1885 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1887 // VZ: commenting this out because it does happen (although not easy
1888 // to reproduce, I only see it when using wxMiniFrame and not
1889 // always) and makes using Mahogany quite annoying
1891 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1892 wxT("unfocusing window that hasn't gained focus properly") );
1895 g_activeFrameLostFocus
= TRUE
;
1898 // if the focus goes out of our app alltogether, OnIdle() will send
1899 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1900 // g_sendActivateEvent to -1
1901 g_sendActivateEvent
= 0;
1903 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1907 g_focusWindow
= (wxWindowGTK
*)NULL
;
1915 // caret needs to be informed about focus change
1916 wxCaret
*caret
= win
->GetCaret();
1919 caret
->OnKillFocus();
1921 #endif // wxUSE_CARET
1923 // don't send the window a kill focus event if it thinks that it doesn't
1924 // have focus already
1925 if ( win
->m_hasFocus
)
1927 win
->m_hasFocus
= FALSE
;
1929 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1930 event
.SetEventObject( win
);
1932 if (win
->GetEventHandler()->ProcessEvent( event
))
1934 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1942 //-----------------------------------------------------------------------------
1943 // "enter_notify_event"
1944 //-----------------------------------------------------------------------------
1947 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1948 GdkEventCrossing
*gdk_event
,
1954 wxapp_install_idle_handler();
1956 if (!win
->m_hasVMT
) return FALSE
;
1957 if (g_blockEventsOnDrag
) return FALSE
;
1959 // Event was emitted after a grab
1960 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1962 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1966 GdkModifierType state
= (GdkModifierType
)0;
1968 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1970 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1971 InitMouseEvent(win
, event
, gdk_event
);
1972 wxPoint pt
= win
->GetClientAreaOrigin();
1973 event
.m_x
= x
+ pt
.x
;
1974 event
.m_y
= y
+ pt
.y
;
1976 if (win
->GetEventHandler()->ProcessEvent( event
))
1978 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1985 //-----------------------------------------------------------------------------
1986 // "leave_notify_event"
1987 //-----------------------------------------------------------------------------
1989 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1994 wxapp_install_idle_handler();
1996 if (!win
->m_hasVMT
) return FALSE
;
1997 if (g_blockEventsOnDrag
) return FALSE
;
1999 // Event was emitted after an ungrab
2000 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2002 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2004 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2005 event
.SetTimestamp( gdk_event
->time
);
2006 event
.SetEventObject( win
);
2010 GdkModifierType state
= (GdkModifierType
)0;
2012 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2014 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2015 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2016 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2017 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2018 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2019 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2020 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2022 wxPoint pt
= win
->GetClientAreaOrigin();
2023 event
.m_x
= x
+ pt
.x
;
2024 event
.m_y
= y
+ pt
.y
;
2026 if (win
->GetEventHandler()->ProcessEvent( event
))
2028 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2035 //-----------------------------------------------------------------------------
2036 // "value_changed" from m_vAdjust
2037 //-----------------------------------------------------------------------------
2039 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2046 wxapp_install_idle_handler();
2048 if (g_blockEventsOnDrag
) return;
2050 if (!win
->m_hasVMT
) return;
2052 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2053 if (fabs(diff
) < 0.2) return;
2055 win
->m_oldVerticalPos
= adjust
->value
;
2058 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2060 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2062 int value
= (int)(adjust
->value
+0.5);
2064 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2065 event
.SetEventObject( win
);
2066 win
->GetEventHandler()->ProcessEvent( event
);
2069 //-----------------------------------------------------------------------------
2070 // "value_changed" from m_hAdjust
2071 //-----------------------------------------------------------------------------
2073 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2080 wxapp_install_idle_handler();
2082 if (g_blockEventsOnDrag
) return;
2083 if (!win
->m_hasVMT
) return;
2085 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2086 if (fabs(diff
) < 0.2) return;
2089 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2091 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2093 win
->m_oldHorizontalPos
= adjust
->value
;
2095 int value
= (int)(adjust
->value
+0.5);
2097 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2098 event
.SetEventObject( win
);
2099 win
->GetEventHandler()->ProcessEvent( event
);
2102 //-----------------------------------------------------------------------------
2103 // "button_press_event" from scrollbar
2104 //-----------------------------------------------------------------------------
2106 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2107 GdkEventButton
*gdk_event
,
2113 wxapp_install_idle_handler();
2116 g_blockEventsOnScroll
= TRUE
;
2118 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2120 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2126 //-----------------------------------------------------------------------------
2127 // "button_release_event" from scrollbar
2128 //-----------------------------------------------------------------------------
2130 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2131 GdkEventButton
*WXUNUSED(gdk_event
),
2136 // don't test here as we can release the mouse while being over
2137 // a different window than the slider
2139 // if (gdk_event->window != widget->slider) return FALSE;
2141 g_blockEventsOnScroll
= FALSE
;
2143 if (win
->m_isScrolling
)
2145 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2149 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2150 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2152 value
= (int)(win
->m_hAdjust
->value
+0.5);
2155 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2157 value
= (int)(win
->m_vAdjust
->value
+0.5);
2161 wxScrollWinEvent
event( command
, value
, dir
);
2162 event
.SetEventObject( win
);
2163 win
->GetEventHandler()->ProcessEvent( event
);
2166 win
->m_isScrolling
= FALSE
;
2171 // ----------------------------------------------------------------------------
2172 // this wxWindowBase function is implemented here (in platform-specific file)
2173 // because it is static and so couldn't be made virtual
2174 // ----------------------------------------------------------------------------
2176 wxWindow
*wxWindowBase::FindFocus()
2178 // the cast is necessary when we compile in wxUniversal mode
2179 return (wxWindow
*)g_focusWindow
;
2183 //-----------------------------------------------------------------------------
2184 // "realize" from m_widget
2185 //-----------------------------------------------------------------------------
2187 /* We cannot set colours and fonts before the widget has
2188 been realized, so we do this directly after realization. */
2191 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2196 wxapp_install_idle_handler();
2198 if (win
->m_delayedBackgroundColour
&& !win
->GetThemeEnabled())
2199 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2201 if (win
->m_delayedForegroundColour
&& !win
->GetThemeEnabled())
2202 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2205 if (win
->m_imContext
)
2207 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2208 gtk_im_context_set_client_window( (GtkIMContext
*) win
->m_imContext
, pizza
->bin_window
);
2212 wxWindowCreateEvent
event( win
);
2213 event
.SetEventObject( win
);
2214 win
->GetEventHandler()->ProcessEvent( event
);
2219 //-----------------------------------------------------------------------------
2221 //-----------------------------------------------------------------------------
2224 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2225 GtkAllocation
*WXUNUSED(alloc
),
2229 wxapp_install_idle_handler();
2231 if (!win
->m_hasScrolling
) return;
2233 int client_width
= 0;
2234 int client_height
= 0;
2235 win
->GetClientSize( &client_width
, &client_height
);
2236 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2239 win
->m_oldClientWidth
= client_width
;
2240 win
->m_oldClientHeight
= client_height
;
2242 if (!win
->m_nativeSizeEvent
)
2244 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2245 event
.SetEventObject( win
);
2246 win
->GetEventHandler()->ProcessEvent( event
);
2252 #define WXUNUSED_UNLESS_XIM(param) param
2254 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2257 /* Resize XIM window */
2260 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2261 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2262 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2265 wxapp_install_idle_handler();
2271 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2275 gdk_window_get_size (widget
->window
, &width
, &height
);
2276 win
->m_icattr
->preedit_area
.width
= width
;
2277 win
->m_icattr
->preedit_area
.height
= height
;
2278 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2283 //-----------------------------------------------------------------------------
2284 // "realize" from m_wxwindow
2285 //-----------------------------------------------------------------------------
2287 /* Initialize XIM support */
2290 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2291 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2294 wxapp_install_idle_handler();
2297 if (win
->m_ic
) return FALSE
;
2298 if (!widget
) return FALSE
;
2299 if (!gdk_im_ready()) return FALSE
;
2301 win
->m_icattr
= gdk_ic_attr_new();
2302 if (!win
->m_icattr
) return FALSE
;
2306 GdkColormap
*colormap
;
2307 GdkICAttr
*attr
= win
->m_icattr
;
2308 unsigned attrmask
= GDK_IC_ALL_REQ
;
2310 GdkIMStyle supported_style
= (GdkIMStyle
)
2311 (GDK_IM_PREEDIT_NONE
|
2312 GDK_IM_PREEDIT_NOTHING
|
2313 GDK_IM_PREEDIT_POSITION
|
2314 GDK_IM_STATUS_NONE
|
2315 GDK_IM_STATUS_NOTHING
);
2317 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2318 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2320 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2321 attr
->client_window
= widget
->window
;
2323 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2324 gtk_widget_get_default_colormap ())
2326 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2327 attr
->preedit_colormap
= colormap
;
2330 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2331 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2332 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2333 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2335 switch (style
& GDK_IM_PREEDIT_MASK
)
2337 case GDK_IM_PREEDIT_POSITION
:
2338 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2340 g_warning ("over-the-spot style requires fontset");
2344 gdk_window_get_size (widget
->window
, &width
, &height
);
2346 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2347 attr
->spot_location
.x
= 0;
2348 attr
->spot_location
.y
= height
;
2349 attr
->preedit_area
.x
= 0;
2350 attr
->preedit_area
.y
= 0;
2351 attr
->preedit_area
.width
= width
;
2352 attr
->preedit_area
.height
= height
;
2353 attr
->preedit_fontset
= widget
->style
->font
;
2358 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2360 if (win
->m_ic
== NULL
)
2361 g_warning ("Can't create input context.");
2364 mask
= gdk_window_get_events (widget
->window
);
2365 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2366 gdk_window_set_events (widget
->window
, mask
);
2368 if (GTK_WIDGET_HAS_FOCUS(widget
))
2369 gdk_im_begin (win
->m_ic
, widget
->window
);
2376 //-----------------------------------------------------------------------------
2377 // InsertChild for wxWindowGTK.
2378 //-----------------------------------------------------------------------------
2380 /* Callback for wxWindowGTK. This very strange beast has to be used because
2381 * C++ has no virtual methods in a constructor. We have to emulate a
2382 * virtual function here as wxNotebook requires a different way to insert
2383 * a child in it. I had opted for creating a wxNotebookPage window class
2384 * which would have made this superfluous (such in the MDI window system),
2385 * but no-one was listening to me... */
2387 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2389 /* the window might have been scrolled already, do we
2390 have to adapt the position */
2391 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2392 child
->m_x
+= pizza
->xoffset
;
2393 child
->m_y
+= pizza
->yoffset
;
2395 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2396 GTK_WIDGET(child
->m_widget
),
2403 //-----------------------------------------------------------------------------
2405 //-----------------------------------------------------------------------------
2407 wxWindow
*wxGetActiveWindow()
2409 return wxWindow::FindFocus();
2412 //-----------------------------------------------------------------------------
2414 //-----------------------------------------------------------------------------
2416 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2418 #ifdef __WXUNIVERSAL__
2419 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2421 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2422 #endif // __WXUNIVERSAL__/__WXGTK__
2424 void wxWindowGTK::Init()
2430 m_widget
= (GtkWidget
*) NULL
;
2431 m_wxwindow
= (GtkWidget
*) NULL
;
2432 m_focusWidget
= (GtkWidget
*) NULL
;
2442 m_needParent
= TRUE
;
2443 m_isBeingDeleted
= FALSE
;
2446 m_nativeSizeEvent
= FALSE
;
2448 m_hasScrolling
= FALSE
;
2449 m_isScrolling
= FALSE
;
2451 m_hAdjust
= (GtkAdjustment
*) NULL
;
2452 m_vAdjust
= (GtkAdjustment
*) NULL
;
2453 m_oldHorizontalPos
=
2454 m_oldVerticalPos
= 0.0;
2456 m_oldClientHeight
= 0;
2459 m_widgetStyle
= (GtkStyle
*) NULL
;
2461 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2463 m_acceptsFocus
= FALSE
;
2466 m_clipPaintRegion
= FALSE
;
2468 m_cursor
= *wxSTANDARD_CURSOR
;
2470 m_delayedForegroundColour
= FALSE
;
2471 m_delayedBackgroundColour
= FALSE
;
2475 m_x11Context
= NULL
;
2478 m_ic
= (GdkIC
*) NULL
;
2479 m_icattr
= (GdkICAttr
*) NULL
;
2484 wxWindowGTK::wxWindowGTK()
2489 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2494 const wxString
&name
)
2498 Create( parent
, id
, pos
, size
, style
, name
);
2501 bool wxWindowGTK::Create( wxWindow
*parent
,
2506 const wxString
&name
)
2508 if (!PreCreation( parent
, pos
, size
) ||
2509 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2511 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2515 m_insertCallback
= wxInsertChildInWindow
;
2517 // always needed for background clearing
2518 m_delayedBackgroundColour
= TRUE
;
2520 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2521 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2523 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2525 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2526 scroll_class
->scrollbar_spacing
= 0;
2528 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2530 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2531 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2533 m_wxwindow
= gtk_pizza_new();
2535 #ifndef __WXUNIVERSAL__
2536 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2538 if (HasFlag(wxRAISED_BORDER
))
2540 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2542 else if (HasFlag(wxSUNKEN_BORDER
))
2544 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2546 else if (HasFlag(wxSIMPLE_BORDER
))
2548 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2552 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2554 #endif // __WXUNIVERSAL__
2556 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2558 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2559 m_acceptsFocus
= TRUE
;
2561 // I _really_ don't want scrollbars in the beginning
2562 m_vAdjust
->lower
= 0.0;
2563 m_vAdjust
->upper
= 1.0;
2564 m_vAdjust
->value
= 0.0;
2565 m_vAdjust
->step_increment
= 1.0;
2566 m_vAdjust
->page_increment
= 1.0;
2567 m_vAdjust
->page_size
= 5.0;
2568 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2569 m_hAdjust
->lower
= 0.0;
2570 m_hAdjust
->upper
= 1.0;
2571 m_hAdjust
->value
= 0.0;
2572 m_hAdjust
->step_increment
= 1.0;
2573 m_hAdjust
->page_increment
= 1.0;
2574 m_hAdjust
->page_size
= 5.0;
2575 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2577 // these handlers block mouse events to any window during scrolling such as
2578 // motion events and prevent GTK and wxWindows from fighting over where the
2581 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2582 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2584 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2585 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2587 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2588 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2590 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2591 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2593 // these handlers get notified when screen updates are required either when
2594 // scrolling or when the window size (and therefore scrollbar configuration)
2597 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2598 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2599 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2600 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2603 // Create input method handler
2604 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2606 // Cannot handle drawing preedited text yet
2607 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2609 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2610 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2613 gtk_widget_show( m_wxwindow
);
2616 m_parent
->DoAddChild( this );
2618 m_focusWidget
= m_wxwindow
;
2627 wxWindowGTK::~wxWindowGTK()
2631 if (g_focusWindow
== this)
2632 g_focusWindow
= NULL
;
2634 if (g_activeFrame
== this)
2635 g_activeFrame
= NULL
;
2637 if ( g_delayedFocus
== this )
2638 g_delayedFocus
= NULL
;
2640 m_isBeingDeleted
= TRUE
;
2649 m_parent
->RemoveChild( this );
2653 gdk_ic_destroy (m_ic
);
2655 gdk_ic_attr_destroy (m_icattr
);
2660 #if DISABLE_STYLE_IF_BROKEN_THEME
2661 // don't delete if it's a pixmap theme style
2662 if (!m_widgetStyle
->engine_data
)
2663 gtk_style_unref( m_widgetStyle
);
2665 m_widgetStyle
= (GtkStyle
*) NULL
;
2670 gtk_widget_destroy( m_wxwindow
);
2671 m_wxwindow
= (GtkWidget
*) NULL
;
2676 gtk_widget_destroy( m_widget
);
2677 m_widget
= (GtkWidget
*) NULL
;
2681 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2683 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2685 // This turns -1 into 30 so that a minimal window is
2686 // visible even although -1,-1 has been given as the
2687 // size of the window. the same trick is used in other
2688 // ports and should make debugging easier.
2689 m_width
= WidthDefault(size
.x
) ;
2690 m_height
= HeightDefault(size
.y
);
2695 // some reasonable defaults
2700 m_x
= (gdk_screen_width () - m_width
) / 2;
2701 if (m_x
< 10) m_x
= 10;
2705 m_y
= (gdk_screen_height () - m_height
) / 2;
2706 if (m_y
< 10) m_y
= 10;
2713 void wxWindowGTK::PostCreation()
2715 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2721 // these get reported to wxWindows -> wxPaintEvent
2723 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2725 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2726 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2729 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2730 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2732 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2734 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2735 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2738 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE ) );
2742 // Create input method handler
2743 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2745 // Cannot handle drawing preedited text yet
2746 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2748 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2749 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2753 // these are called when the "sunken" or "raised" borders are drawn
2754 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2755 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2758 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2759 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2765 if (m_focusWidget
== NULL
)
2766 m_focusWidget
= m_widget
;
2768 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2769 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2771 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2772 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2774 // connect to the various key and mouse handlers
2776 GtkWidget
*connect_widget
= GetConnectWidget();
2778 ConnectWidget( connect_widget
);
2780 /* We cannot set colours, fonts and cursors before the widget has
2781 been realized, so we do this directly after realization */
2782 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2783 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2787 // Catch native resize events
2788 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2789 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2791 // Initialize XIM support
2792 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2793 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2795 // And resize XIM window
2796 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2797 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2800 if (!GTK_IS_COMBO(m_widget
))
2802 // This is needed if we want to add our windows into native
2803 // GTK control, such as the toolbar. With this callback, the
2804 // toolbar gets to know the correct size (the one set by the
2805 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2806 // when moving to GTK 2.0.
2807 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2808 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2814 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2816 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2817 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2819 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2820 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2822 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2823 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2825 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2826 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2828 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2829 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2831 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2832 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2834 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2835 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2838 bool wxWindowGTK::Destroy()
2840 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2844 return wxWindowBase::Destroy();
2847 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2849 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2852 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2854 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2855 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2858 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2861 if (m_resizing
) return; /* I don't like recursions */
2864 int currentX
, currentY
;
2865 GetPosition(¤tX
, ¤tY
);
2870 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2872 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2874 /* don't set the size for children of wxNotebook, just take the values. */
2882 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2883 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2885 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2886 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2890 m_x
= x
+ pizza
->xoffset
;
2891 m_y
= y
+ pizza
->yoffset
;
2893 if (width
!= -1) m_width
= width
;
2894 if (height
!= -1) m_height
= height
;
2896 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2898 if (width
== -1) m_width
= 80;
2901 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2903 if (height
== -1) m_height
= 26;
2906 int minWidth
= GetMinWidth(),
2907 minHeight
= GetMinHeight(),
2908 maxWidth
= GetMaxWidth(),
2909 maxHeight
= GetMaxHeight();
2911 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2912 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2913 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2914 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2917 int bottom_border
= 0;
2920 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2922 /* the default button has a border around it */
2928 DoMoveWindow( m_x
-border
,
2931 m_height
+border
+bottom_border
);
2936 /* Sometimes the client area changes size without the
2937 whole windows's size changing, but if the whole
2938 windows's size doesn't change, no wxSizeEvent will
2939 normally be sent. Here we add an extra test if
2940 the client test has been changed and this will
2942 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2946 wxPrintf( "OnSize sent from " );
2947 if (GetClassInfo() && GetClassInfo()->GetClassName())
2948 wxPrintf( GetClassInfo()->GetClassName() );
2949 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2952 if (!m_nativeSizeEvent
)
2954 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2955 event
.SetEventObject( this );
2956 GetEventHandler()->ProcessEvent( event
);
2962 void wxWindowGTK::OnInternalIdle()
2964 // Update invalidated regions.
2967 // Synthetize activate events.
2968 if ( g_sendActivateEvent
!= -1 )
2970 bool activate
= g_sendActivateEvent
!= 0;
2973 g_sendActivateEvent
= -1;
2975 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2978 if ( g_activeFrameLostFocus
)
2980 if ( g_activeFrame
)
2982 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2983 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2984 event
.SetEventObject(g_activeFrame
);
2985 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2986 g_activeFrame
= NULL
;
2988 g_activeFrameLostFocus
= FALSE
;
2991 wxCursor cursor
= m_cursor
;
2992 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2996 /* I now set the cursor anew in every OnInternalIdle call
2997 as setting the cursor in a parent window also effects the
2998 windows above so that checking for the current cursor is
3003 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3005 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3007 if (!g_globalCursor
.Ok())
3008 cursor
= *wxSTANDARD_CURSOR
;
3010 window
= m_widget
->window
;
3011 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3012 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3018 GdkWindow
*window
= m_widget
->window
;
3019 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3020 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3025 if (wxUpdateUIEvent::CanUpdate())
3029 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3031 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3033 if (width
) (*width
) = m_width
;
3034 if (height
) (*height
) = m_height
;
3037 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3039 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3043 SetSize( width
, height
);
3050 #ifndef __WXUNIVERSAL__
3051 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3053 /* when using GTK 1.2 we set the shadow border size to 2 */
3057 if (HasFlag(wxSIMPLE_BORDER
))
3059 /* when using GTK 1.2 we set the simple border size to 1 */
3063 #endif // __WXUNIVERSAL__
3067 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3069 GtkRequisition vscroll_req
;
3070 vscroll_req
.width
= 2;
3071 vscroll_req
.height
= 2;
3072 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3073 (scroll_window
->vscrollbar
, &vscroll_req
);
3075 GtkRequisition hscroll_req
;
3076 hscroll_req
.width
= 2;
3077 hscroll_req
.height
= 2;
3078 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3079 (scroll_window
->hscrollbar
, &hscroll_req
);
3081 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3083 if (scroll_window
->vscrollbar_visible
)
3085 dw
+= vscroll_req
.width
;
3086 dw
+= scroll_class
->scrollbar_spacing
;
3089 if (scroll_window
->hscrollbar_visible
)
3091 dh
+= hscroll_req
.height
;
3092 dh
+= scroll_class
->scrollbar_spacing
;
3096 SetSize( width
+dw
, height
+dh
);
3100 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3102 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3106 if (width
) (*width
) = m_width
;
3107 if (height
) (*height
) = m_height
;
3114 #ifndef __WXUNIVERSAL__
3115 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3117 /* when using GTK 1.2 we set the shadow border size to 2 */
3121 if (HasFlag(wxSIMPLE_BORDER
))
3123 /* when using GTK 1.2 we set the simple border size to 1 */
3127 #endif // __WXUNIVERSAL__
3131 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3133 GtkRequisition vscroll_req
;
3134 vscroll_req
.width
= 2;
3135 vscroll_req
.height
= 2;
3136 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3137 (scroll_window
->vscrollbar
, &vscroll_req
);
3139 GtkRequisition hscroll_req
;
3140 hscroll_req
.width
= 2;
3141 hscroll_req
.height
= 2;
3142 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3143 (scroll_window
->hscrollbar
, &hscroll_req
);
3145 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3147 if (scroll_window
->vscrollbar_visible
)
3149 dw
+= vscroll_req
.width
;
3150 dw
+= scroll_class
->scrollbar_spacing
;
3153 if (scroll_window
->hscrollbar_visible
)
3155 dh
+= hscroll_req
.height
;
3156 dh
+= scroll_class
->scrollbar_spacing
;
3160 if (width
) (*width
) = m_width
- dw
;
3161 if (height
) (*height
) = m_height
- dh
;
3165 printf( "GetClientSize, name %s ", GetName().c_str() );
3166 if (width) printf( " width = %d", (*width) );
3167 if (height) printf( " height = %d", (*height) );
3172 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3174 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3178 if (m_parent
&& m_parent
->m_wxwindow
)
3180 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3181 dx
= pizza
->xoffset
;
3182 dy
= pizza
->yoffset
;
3185 if (x
) (*x
) = m_x
- dx
;
3186 if (y
) (*y
) = m_y
- dy
;
3189 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3191 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3193 if (!m_widget
->window
) return;
3195 GdkWindow
*source
= (GdkWindow
*) NULL
;
3197 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3199 source
= m_widget
->window
;
3203 gdk_window_get_origin( source
, &org_x
, &org_y
);
3207 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3209 org_x
+= m_widget
->allocation
.x
;
3210 org_y
+= m_widget
->allocation
.y
;
3218 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3220 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3222 if (!m_widget
->window
) return;
3224 GdkWindow
*source
= (GdkWindow
*) NULL
;
3226 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3228 source
= m_widget
->window
;
3232 gdk_window_get_origin( source
, &org_x
, &org_y
);
3236 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3238 org_x
+= m_widget
->allocation
.x
;
3239 org_y
+= m_widget
->allocation
.y
;
3247 bool wxWindowGTK::Show( bool show
)
3249 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3251 if (!wxWindowBase::Show(show
))
3258 gtk_widget_show( m_widget
);
3260 gtk_widget_hide( m_widget
);
3262 wxShowEvent
eventShow(GetId(), show
);
3263 eventShow
.m_eventObject
= this;
3265 GetEventHandler()->ProcessEvent(eventShow
);
3270 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3272 win
->OnParentEnable(enable
);
3274 // Recurse, so that children have the opportunity to Do The Right Thing
3275 // and reset colours that have been messed up by a parent's (really ancestor's)
3277 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3279 node
= node
->GetNext() )
3281 wxWindow
*child
= node
->GetData();
3282 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3283 wxWindowNotifyEnable(child
, enable
);
3287 bool wxWindowGTK::Enable( bool enable
)
3289 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3291 if (!wxWindowBase::Enable(enable
))
3297 gtk_widget_set_sensitive( m_widget
, enable
);
3299 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3301 wxWindowNotifyEnable(this, enable
);
3306 int wxWindowGTK::GetCharHeight() const
3308 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3310 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3313 PangoContext
*context
= NULL
;
3315 context
= gtk_widget_get_pango_context( m_widget
);
3320 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3321 PangoLayout
*layout
= pango_layout_new(context
);
3322 pango_layout_set_font_description(layout
, desc
);
3323 pango_layout_set_text(layout
, "H", 1);
3324 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3326 PangoRectangle rect
;
3327 pango_layout_line_get_extents(line
, NULL
, &rect
);
3329 g_object_unref( G_OBJECT( layout
) );
3331 return (int) (rect
.height
/ PANGO_SCALE
);
3333 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3335 return font
->ascent
+ font
->descent
;
3339 int wxWindowGTK::GetCharWidth() const
3341 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3343 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3346 PangoContext
*context
= NULL
;
3348 context
= gtk_widget_get_pango_context( m_widget
);
3353 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3354 PangoLayout
*layout
= pango_layout_new(context
);
3355 pango_layout_set_font_description(layout
, desc
);
3356 pango_layout_set_text(layout
, "H", 1);
3357 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3359 PangoRectangle rect
;
3360 pango_layout_line_get_extents(line
, NULL
, &rect
);
3362 g_object_unref( G_OBJECT( layout
) );
3364 return (int) (rect
.width
/ PANGO_SCALE
);
3366 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3368 return gdk_string_width( font
, "H" );
3372 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3376 int *externalLeading
,
3377 const wxFont
*theFont
) const
3379 wxFont fontToUse
= m_font
;
3380 if (theFont
) fontToUse
= *theFont
;
3382 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3384 if (string
.IsEmpty())
3392 PangoContext
*context
= NULL
;
3394 context
= gtk_widget_get_pango_context( m_widget
);
3403 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3404 PangoLayout
*layout
= pango_layout_new(context
);
3405 pango_layout_set_font_description(layout
, desc
);
3408 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3409 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3411 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3412 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3413 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3416 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3418 PangoRectangle rect
;
3419 pango_layout_line_get_extents(line
, NULL
, &rect
);
3421 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3422 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3425 // Do something about metrics here
3428 if (externalLeading
) (*externalLeading
) = 0; // ??
3430 g_object_unref( G_OBJECT( layout
) );
3432 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3433 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3434 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3435 if (descent
) (*descent
) = font
->descent
;
3436 if (externalLeading
) (*externalLeading
) = 0; // ??
3440 void wxWindowGTK::SetFocus()
3442 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3446 // don't do anything if we already have focus
3452 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3454 gtk_widget_grab_focus (m_wxwindow
);
3459 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3461 if (!GTK_WIDGET_REALIZED(m_widget
))
3463 // we can't set the focus to the widget now so we remember that
3464 // it should be focused and will do it later, during the idle
3465 // time, as soon as we can
3466 wxLogTrace(TRACE_FOCUS
,
3467 _T("Delaying setting focus to %s(%s)"),
3468 GetClassInfo()->GetClassName(), GetLabel().c_str());
3470 g_delayedFocus
= this;
3474 wxLogTrace(TRACE_FOCUS
,
3475 _T("Setting focus to %s(%s)"),
3476 GetClassInfo()->GetClassName(), GetLabel().c_str());
3478 gtk_widget_grab_focus (m_widget
);
3481 else if (GTK_IS_CONTAINER(m_widget
))
3483 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3487 wxLogTrace(TRACE_FOCUS
,
3488 _T("Can't set focus to %s(%s)"),
3489 GetClassInfo()->GetClassName(), GetLabel().c_str());
3494 bool wxWindowGTK::AcceptsFocus() const
3496 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3499 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3501 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3503 wxWindowGTK
*oldParent
= m_parent
,
3504 *newParent
= (wxWindowGTK
*)newParentBase
;
3506 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3508 if ( !wxWindowBase::Reparent(newParent
) )
3511 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3513 /* prevent GTK from deleting the widget arbitrarily */
3514 gtk_widget_ref( m_widget
);
3518 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3521 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3525 /* insert GTK representation */
3526 (*(newParent
->m_insertCallback
))(newParent
, this);
3529 /* reverse: prevent GTK from deleting the widget arbitrarily */
3530 gtk_widget_unref( m_widget
);
3535 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3537 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3539 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3541 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3546 /* insert GTK representation */
3547 (*m_insertCallback
)(this, child
);
3550 void wxWindowGTK::Raise()
3552 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3554 if (!m_widget
->window
) return;
3556 gdk_window_raise( m_widget
->window
);
3559 void wxWindowGTK::Lower()
3561 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3563 if (!m_widget
->window
) return;
3565 gdk_window_lower( m_widget
->window
);
3568 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3570 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3572 if (cursor
== m_cursor
)
3576 wxapp_install_idle_handler();
3578 if (cursor
== wxNullCursor
)
3579 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3581 return wxWindowBase::SetCursor( cursor
);
3584 void wxWindowGTK::WarpPointer( int x
, int y
)
3586 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3588 // We provide this function ourselves as it is
3589 // missing in GDK (top of this file).
3591 GdkWindow
*window
= (GdkWindow
*) NULL
;
3593 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3595 window
= GetConnectWidget()->window
;
3598 gdk_window_warp_pointer( window
, x
, y
);
3602 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3604 if (!m_widget
) return;
3605 if (!m_widget
->window
) return;
3609 wxapp_install_idle_handler();
3611 wxRect
myRect(0,0,0,0);
3612 if (m_wxwindow
&& rect
)
3614 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3615 m_wxwindow
->allocation
.height
));
3616 myRect
.Intersect(*rect
);
3617 if (!myRect
.width
|| !myRect
.height
)
3618 // nothing to do, rectangle is empty
3623 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3627 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3628 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3632 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3633 m_clearRegion
.Clear();
3634 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3642 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3643 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3647 GdkRectangle gdk_rect
;
3648 gdk_rect
.x
= rect
->x
;
3649 gdk_rect
.y
= rect
->y
;
3650 gdk_rect
.width
= rect
->width
;
3651 gdk_rect
.height
= rect
->height
;
3652 gtk_widget_draw( m_widget
, &gdk_rect
);
3659 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3660 m_updateRegion
.Clear();
3661 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3665 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3673 GdkRectangle gdk_rect
;
3674 gdk_rect
.x
= rect
->x
;
3675 gdk_rect
.y
= rect
->y
;
3676 gdk_rect
.width
= rect
->width
;
3677 gdk_rect
.height
= rect
->height
;
3678 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3682 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3688 void wxWindowGTK::Update()
3693 void wxWindowGTK::GtkUpdate()
3696 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3697 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3699 if (!m_updateRegion
.IsEmpty())
3700 GtkSendPaintEvents();
3704 void wxWindowGTK::GtkSendPaintEvents()
3709 m_clearRegion
.Clear();
3711 m_updateRegion
.Clear();
3715 // Clip to paint region in wxClientDC
3716 m_clipPaintRegion
= TRUE
;
3719 // widget to draw on
3720 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3722 // later for GTK 2.0, too.
3723 if (GetThemeEnabled())
3725 // find ancestor from which to steal background
3726 wxWindow
*parent
= GetParent();
3727 while (parent
&& !parent
->IsTopLevel())
3728 parent
= parent
->GetParent();
3730 parent
= (wxWindow
*)this;
3732 wxRegionIterator
upd( m_updateRegion
);
3736 rect
.x
= upd
.GetX();
3737 rect
.y
= upd
.GetY();
3738 rect
.width
= upd
.GetWidth();
3739 rect
.height
= upd
.GetHeight();
3741 gtk_paint_flat_box( parent
->m_widget
->style
,
3758 wxWindowDC
dc( (wxWindow
*)this );
3759 dc
.SetClippingRegion( m_updateRegion
);
3761 wxEraseEvent
erase_event( GetId(), &dc
);
3762 erase_event
.SetEventObject( this );
3764 GetEventHandler()->ProcessEvent(erase_event
);
3767 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3769 wxWindowDC
dc( (wxWindow
*)this );
3770 if (m_clearRegion
.IsEmpty())
3771 dc
.SetClippingRegion( m_updateRegion
);
3773 dc
.SetClippingRegion( m_clearRegion
);
3775 wxEraseEvent
erase_event( GetId(), &dc
);
3776 erase_event
.SetEventObject( this );
3778 if (!GetEventHandler()->ProcessEvent(erase_event
))
3782 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3783 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3785 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3787 wxRegionIterator
upd( m_clearRegion
);
3790 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3791 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3795 m_clearRegion
.Clear();
3799 wxNcPaintEvent
nc_paint_event( GetId() );
3800 nc_paint_event
.SetEventObject( this );
3801 GetEventHandler()->ProcessEvent( nc_paint_event
);
3803 wxPaintEvent
paint_event( GetId() );
3804 paint_event
.SetEventObject( this );
3805 GetEventHandler()->ProcessEvent( paint_event
);
3807 m_clipPaintRegion
= FALSE
;
3809 #ifndef __WXUNIVERSAL__
3811 // The following code will result in all window-less widgets
3812 // being redrawn because the wxWindows class is allowed to
3813 // paint over the window-less widgets.
3815 GList
*children
= pizza
->children
;
3818 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3819 children
= children
->next
;
3821 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3822 GTK_WIDGET_DRAWABLE (child
->widget
))
3824 // Get intersection of widget area and update region
3825 wxRegion
region( m_updateRegion
);
3827 GdkEventExpose gdk_event
;
3828 gdk_event
.type
= GDK_EXPOSE
;
3829 gdk_event
.window
= pizza
->bin_window
;
3830 gdk_event
.count
= 0;
3832 wxRegionIterator
upd( m_updateRegion
);
3836 rect
.x
= upd
.GetX();
3837 rect
.y
= upd
.GetY();
3838 rect
.width
= upd
.GetWidth();
3839 rect
.height
= upd
.GetHeight();
3841 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3843 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3853 m_updateRegion
.Clear();
3856 void wxWindowGTK::Clear()
3858 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3861 if (m_wxwindow
&& m_wxwindow
->window
)
3863 m_clearRegion
.Clear();
3864 wxSize
size( GetClientSize() );
3865 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3867 // Better do this in idle?
3874 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3876 wxWindowBase::DoSetToolTip(tip
);
3879 m_tooltip
->Apply( (wxWindow
*)this );
3882 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3884 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3886 #endif // wxUSE_TOOLTIPS
3888 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3890 GdkWindow
*window
= (GdkWindow
*) NULL
;
3892 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3894 window
= GetConnectWidget()->window
;
3898 // We need the pixel value e.g. for background clearing.
3899 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3903 // wxMSW doesn't clear the window here, either.
3904 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3910 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3912 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3914 if (!wxWindowBase::SetBackgroundColour(colour
))
3917 GdkWindow
*window
= (GdkWindow
*) NULL
;
3919 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3921 window
= GetConnectWidget()->window
;
3925 // indicate that a new style has been set
3926 // but it couldn't get applied as the
3927 // widget hasn't been realized yet.
3928 m_delayedBackgroundColour
= TRUE
;
3933 GtkSetBackgroundColour( colour
);
3939 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3941 GdkWindow
*window
= (GdkWindow
*) NULL
;
3943 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3945 window
= GetConnectWidget()->window
;
3952 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3954 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3956 if (!wxWindowBase::SetForegroundColour(colour
))
3958 // don't leave if the GTK widget has just
3960 if (!m_delayedForegroundColour
) return FALSE
;
3963 GdkWindow
*window
= (GdkWindow
*) NULL
;
3965 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3967 window
= GetConnectWidget()->window
;
3971 // indicate that a new style has been set
3972 // but it couldn't get applied as the
3973 // widget hasn't been realized yet.
3974 m_delayedForegroundColour
= TRUE
;
3978 GtkSetForegroundColour( colour
);
3985 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3987 return gtk_widget_get_pango_context( m_widget
);
3990 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
3993 m_x11Context
= pango_x_get_context( gdk_display
);
3995 return m_x11Context
;
3999 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4003 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4005 // FIXME: no more klass in 2.0
4007 remake
->klass
= m_widgetStyle
->klass
;
4010 gtk_style_unref( m_widgetStyle
);
4011 m_widgetStyle
= remake
;
4015 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4018 def
= gtk_widget_get_default_style();
4020 m_widgetStyle
= gtk_style_copy( def
);
4022 // FIXME: no more klass in 2.0
4024 m_widgetStyle
->klass
= def
->klass
;
4028 return m_widgetStyle
;
4031 void wxWindowGTK::SetWidgetStyle()
4033 #if DISABLE_STYLE_IF_BROKEN_THEME
4034 if (m_widget
->style
->engine_data
)
4036 static bool s_warningPrinted
= FALSE
;
4037 if (!s_warningPrinted
)
4039 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
4040 s_warningPrinted
= TRUE
;
4042 m_widgetStyle
= m_widget
->style
;
4047 GtkStyle
*style
= GetWidgetStyle();
4049 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
4052 pango_font_description_free( style
->font_desc
);
4053 style
->font_desc
= pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4055 gdk_font_unref( style
->font
);
4056 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4060 if (m_foregroundColour
.Ok())
4062 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4063 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4065 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4066 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4067 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4071 // Try to restore the gtk default style. This is still a little
4072 // oversimplified for what is probably really needed here for controls
4073 // other than buttons, but is better than not being able to (re)set a
4074 // control's foreground colour to *wxBLACK -- RL
4075 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4078 def
= gtk_widget_get_default_style();
4080 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4081 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4082 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4086 if (m_backgroundColour
.Ok())
4088 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4089 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4091 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4092 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4093 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4094 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4095 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4096 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4097 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4098 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4102 // Try to restore the gtk default style. This is still a little
4103 // oversimplified for what is probably really needed here for controls
4104 // other than buttons, but is better than not being able to (re)set a
4105 // control's background colour to default grey and means resetting a
4106 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4108 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4111 def
= gtk_widget_get_default_style();
4113 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4114 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4115 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4116 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4117 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4118 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4119 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4120 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4125 void wxWindowGTK::ApplyWidgetStyle()
4129 //-----------------------------------------------------------------------------
4130 // Pop-up menu stuff
4131 //-----------------------------------------------------------------------------
4133 #if wxUSE_MENUS_NATIVE
4136 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4138 *is_waiting
= FALSE
;
4141 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4143 menu
->SetInvokingWindow( win
);
4144 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
4147 wxMenuItem
*menuitem
= node
->GetData();
4148 if (menuitem
->IsSubMenu())
4150 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4153 node
= node
->GetNext();
4157 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
4158 // wxPopupMenuPositionCallback()
4160 // should be safe even in the MT case as the user can hardly popup 2 menus
4161 // simultaneously, can he?
4162 static gint gs_pop_x
= 0;
4163 static gint gs_pop_y
= 0;
4165 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4168 gboolean
* WXUNUSED(whatever
),
4170 gpointer
WXUNUSED(user_data
) )
4172 // ensure that the menu appears entirely on screen
4174 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4176 wxSize sizeScreen
= wxGetDisplaySize();
4178 gint xmax
= sizeScreen
.x
- req
.width
,
4179 ymax
= sizeScreen
.y
- req
.height
;
4181 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
4182 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
4185 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4187 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4189 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
4191 SetInvokingWindow( menu
, this );
4197 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
4199 bool is_waiting
= TRUE
;
4201 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4203 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4204 (gpointer
)&is_waiting
);
4207 GTK_MENU(menu
->m_menu
),
4208 (GtkWidget
*) NULL
, // parent menu shell
4209 (GtkWidget
*) NULL
, // parent menu item
4210 wxPopupMenuPositionCallback
, // function to position it
4211 NULL
, // client data
4212 0, // button used to activate it
4213 gs_timeLastClick
// the time of activation
4218 gtk_main_iteration();
4224 #endif // wxUSE_MENUS_NATIVE
4226 #if wxUSE_DRAG_AND_DROP
4228 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4230 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4232 GtkWidget
*dnd_widget
= GetConnectWidget();
4234 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4236 if (m_dropTarget
) delete m_dropTarget
;
4237 m_dropTarget
= dropTarget
;
4239 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4242 #endif // wxUSE_DRAG_AND_DROP
4244 GtkWidget
* wxWindowGTK::GetConnectWidget()
4246 GtkWidget
*connect_widget
= m_widget
;
4247 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4249 return connect_widget
;
4252 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4255 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4257 return (window
== m_widget
->window
);
4260 bool wxWindowGTK::SetFont( const wxFont
&font
)
4262 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4264 if (!wxWindowBase::SetFont(font
))
4269 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4270 if ( sysbg
== m_backgroundColour
)
4272 m_backgroundColour
= wxNullColour
;
4274 m_backgroundColour
= sysbg
;
4284 void wxWindowGTK::DoCaptureMouse()
4286 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4288 GdkWindow
*window
= (GdkWindow
*) NULL
;
4290 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4292 window
= GetConnectWidget()->window
;
4294 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4296 wxCursor
* cursor
= & m_cursor
;
4298 cursor
= wxSTANDARD_CURSOR
;
4300 gdk_pointer_grab( window
, FALSE
,
4302 (GDK_BUTTON_PRESS_MASK
|
4303 GDK_BUTTON_RELEASE_MASK
|
4304 GDK_POINTER_MOTION_HINT_MASK
|
4305 GDK_POINTER_MOTION_MASK
),
4307 cursor
->GetCursor(),
4308 (guint32
)GDK_CURRENT_TIME
);
4309 g_captureWindow
= this;
4310 g_captureWindowHasMouse
= TRUE
;
4313 void wxWindowGTK::DoReleaseMouse()
4315 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4317 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4319 g_captureWindow
= (wxWindowGTK
*) NULL
;
4321 GdkWindow
*window
= (GdkWindow
*) NULL
;
4323 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4325 window
= GetConnectWidget()->window
;
4330 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4334 wxWindow
*wxWindowBase::GetCapture()
4336 return (wxWindow
*)g_captureWindow
;
4339 bool wxWindowGTK::IsRetained() const
4344 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4345 int range
, bool refresh
)
4347 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4349 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4351 m_hasScrolling
= TRUE
;
4353 if (orient
== wxHORIZONTAL
)
4355 float fpos
= (float)pos
;
4356 float frange
= (float)range
;
4357 float fthumb
= (float)thumbVisible
;
4358 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4359 if (fpos
< 0.0) fpos
= 0.0;
4361 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4362 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4364 SetScrollPos( orient
, pos
, refresh
);
4368 m_oldHorizontalPos
= fpos
;
4370 m_hAdjust
->lower
= 0.0;
4371 m_hAdjust
->upper
= frange
;
4372 m_hAdjust
->value
= fpos
;
4373 m_hAdjust
->step_increment
= 1.0;
4374 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4375 m_hAdjust
->page_size
= fthumb
;
4379 float fpos
= (float)pos
;
4380 float frange
= (float)range
;
4381 float fthumb
= (float)thumbVisible
;
4382 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4383 if (fpos
< 0.0) fpos
= 0.0;
4385 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4386 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4388 SetScrollPos( orient
, pos
, refresh
);
4392 m_oldVerticalPos
= fpos
;
4394 m_vAdjust
->lower
= 0.0;
4395 m_vAdjust
->upper
= frange
;
4396 m_vAdjust
->value
= fpos
;
4397 m_vAdjust
->step_increment
= 1.0;
4398 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4399 m_vAdjust
->page_size
= fthumb
;
4402 if (orient
== wxHORIZONTAL
)
4403 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4405 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4408 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4410 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4412 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4414 if (orient
== wxHORIZONTAL
)
4416 float fpos
= (float)pos
;
4417 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4418 if (fpos
< 0.0) fpos
= 0.0;
4419 m_oldHorizontalPos
= fpos
;
4421 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4422 m_hAdjust
->value
= fpos
;
4426 float fpos
= (float)pos
;
4427 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4428 if (fpos
< 0.0) fpos
= 0.0;
4429 m_oldVerticalPos
= fpos
;
4431 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4432 m_vAdjust
->value
= fpos
;
4435 if (m_wxwindow
->window
)
4437 if (orient
== wxHORIZONTAL
)
4439 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4440 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4442 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4444 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4445 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4449 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4450 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4452 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4454 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4455 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4460 int wxWindowGTK::GetScrollThumb( int orient
) const
4462 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4464 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4466 if (orient
== wxHORIZONTAL
)
4467 return (int)(m_hAdjust
->page_size
+0.5);
4469 return (int)(m_vAdjust
->page_size
+0.5);
4472 int wxWindowGTK::GetScrollPos( int orient
) const
4474 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4476 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4478 if (orient
== wxHORIZONTAL
)
4479 return (int)(m_hAdjust
->value
+0.5);
4481 return (int)(m_vAdjust
->value
+0.5);
4484 int wxWindowGTK::GetScrollRange( int orient
) const
4486 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4488 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4490 if (orient
== wxHORIZONTAL
)
4491 return (int)(m_hAdjust
->upper
+0.5);
4493 return (int)(m_vAdjust
->upper
+0.5);
4496 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4498 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4500 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4502 // No scrolling requested.
4503 if ((dx
== 0) && (dy
== 0)) return;
4506 if (!m_updateRegion
.IsEmpty())
4508 m_updateRegion
.Offset( dx
, dy
);
4512 GetClientSize( &cw
, &ch
);
4513 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4516 if (!m_clearRegion
.IsEmpty())
4518 m_clearRegion
.Offset( dx
, dy
);
4522 GetClientSize( &cw
, &ch
);
4523 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4527 m_clipPaintRegion
= TRUE
;
4529 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4531 m_clipPaintRegion
= FALSE
;
4535 // Find the wxWindow at the current mouse position, also returning the mouse
4537 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4539 pt
= wxGetMousePosition();
4540 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4544 // Get the current mouse position.
4545 wxPoint
wxGetMousePosition()
4547 /* This crashes when used within wxHelpContext,
4548 so we have to use the X-specific implementation below.
4550 GdkModifierType *mask;
4551 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4553 return wxPoint(x, y);
4557 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4559 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4560 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4561 Window rootReturn
, childReturn
;
4562 int rootX
, rootY
, winX
, winY
;
4563 unsigned int maskReturn
;
4565 XQueryPointer (display
,
4569 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4570 return wxPoint(rootX
, rootY
);
4574 // ----------------------------------------------------------------------------
4576 // ----------------------------------------------------------------------------
4578 class wxWinModule
: public wxModule
4585 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4588 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4590 bool wxWinModule::OnInit()
4592 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4593 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4598 void wxWinModule::OnExit()
4601 gdk_gc_unref( g_eraseGC
);